This document defines the public subprocess contract for running nca under an external orchestrator.
The goal is to make nca usable as a headless worker without coupling the project to any one control plane.
These commands are the supported orchestration-facing surfaces:
| Command | Purpose | Machine-readable output |
|---|---|---|
nca run --prompt ... --stream off --json |
Run a foreground task and return a final result | JSON object |
nca run --prompt ... --stream ndjson |
Run a foreground task and stream live events | NDJSON EventEnvelope lines |
nca spawn --prompt ... --json |
Start a detached session | JSON object |
nca status <session_id> --json |
Read the current saved session snapshot | JSON object |
nca sessions --json |
List known sessions | JSON object |
nca attach <session_id> |
Stream live event envelopes from IPC or fall back to the event log | NDJSON EventEnvelope lines |
nca logs <session_id> |
Replay persisted event envelopes from disk | NDJSON EventEnvelope lines |
nca cancel <session_id> --json |
Stop a session and persist cancelled state | JSON object |
nca serve exists for long-lived IPC-driven sessions but is treated as an internal command rather than part of the public orchestration contract.
Machine event streams use the same envelope shape on stdout, in IPC, and in .nca/sessions/<session-id>.events.jsonl:
{
"id": 12,
"ts": "2026-03-14T08:00:00Z",
"event": {
"type": "ToolCallStarted",
"call_id": "call_123",
"tool": "read_file",
"input": {
"path": "src/main.rs"
}
}
}The event payload is the tagged AgentEvent enum from crates/common/src/event.rs.
Lifecycle-critical events:
SessionStartedMessageReceivedToolCallStartedToolCallCompletedApprovalRequestedApprovalResolvedQuestionRequested(interactiveask_questiontool; includessuggested_answer)QuestionResolvedCheckpointResponseSessionEndedChildSessionSpawnedChildSessionCompleted
When the model uses the ask_question tool, the runtime emits QuestionRequested with a question_id. Send a newline-delimited JSON command on the session socket:
{"type":"AnswerQuestion","question_id":"q-<call-id>","selection":{"kind":"suggested"}}selection.kind may be suggested, option (with option_id), or custom (with text). In the interactive CLI, /auto-answer accepts the suggested answer for the active question.
status --json, sessions --json, and the final run --json output are built around the shared SessionSnapshot shape from crates/common/src/session.rs.
Important fields:
idstatusworkspacemodelpidsocket_pathupdated_atestimated_cost_usdtotal_input_tokenstotal_output_tokensorchestration
The orchestration field is optional and only appears when the run was launched with NCA_ORCH_* metadata.
Returns:
{
"session": {
"id": "session-123",
"status": "completed"
},
"output": "final assistant text",
"end_reason": "completed"
}Returns:
{
"session_id": "session-123",
"pid": 4242,
"status_path": ".nca/sessions/session-123.json",
"event_log_path": ".nca/sessions/session-123.events.jsonl",
"spawn_log_path": ".nca/sessions/session-123.spawn.log",
"socket_path": "/tmp/nca/session-123.sock",
"permission_mode": "bypass-permissions",
"safe_mode": false
}Returns:
{
"sessions": [
{
"id": "session-newer",
"status": "running"
}
],
"unreadable": []
}Returns:
{
"session": {
"id": "session-123",
"status": "cancelled"
},
"cancelled": true
}For orchestrated runs, prefer one of these modes:
--permission-mode dont-ask: read-only headless execution--permission-mode bypass-permissions: fully autonomous execution
Avoid default and accept-edits for unattended subprocess runs unless the orchestrator is prepared for approval failures.
If a headless run reaches a tool call that would require user approval, nca exits with a dedicated approval-blocked exit code instead of waiting indefinitely.
These exit codes are intended to stay stable for orchestrators:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Unclassified/internal failure |
10 |
Configuration failure |
11 |
Runtime/provider/tool failure |
13 |
Approval-blocked headless run |
130 |
Cancelled run |
nca reads optional orchestration metadata from these environment variables:
| Variable | Meaning |
|---|---|
NCA_ORCH_NAME |
Orchestrator name |
NCA_ORCH_RUN_ID |
Current external run identifier |
NCA_ORCH_TASK_ID |
Current task identifier |
NCA_ORCH_TASK_REF |
Human-readable task reference |
NCA_ORCH_PARENT_RUN_ID |
Parent external run identifier |
NCA_ORCH_CALLBACK_URL |
Callback or control endpoint hint |
NCA_ORCH_META_<KEY> |
Free-form metadata entries |
This metadata is persisted into session state and injected into the layered system prompt as coordination context. It does not create any implicit network behavior by itself.
Example subprocess flow for a Paperclip-like orchestrator:
- Export headless context:
NCA_ORCH_NAME=paperclip-wrapperNCA_ORCH_RUN_ID=<run-id>NCA_ORCH_TASK_ID=<task-id> - Launch:
nca run --prompt "$PROMPT" --stream off --json --permission-mode bypass-permissions - Parse the final JSON output and persisted
session.id. - If live progress is needed, use:
nca run --prompt "$PROMPT" --stream ndjson --permission-mode bypass-permissionsornca attach <session_id>.
This subprocess contract is the first compatibility layer.
Planned later layers:
- formal local IPC API over the existing Unix socket
- optional HTTP/SSE or A2A-style adapter on top of
runtime + common - orchestrator-specific wrappers only after the generic contract is stable