Sub-agents, MCP integration, lifecycle hooks, orchestration, memory, and IPC.
nca can spawn child agent sessions to handle tasks in parallel. The parent agent uses the spawn_subagent tool to delegate work.
Parent Session
├── spawn_subagent(task: "write tests for auth")
│ └── Child Session (new session ID)
│ ├── Inherits conversation context summary
│ ├── Runs in isolated git worktree (optional)
│ ├── Uses bypass-permissions (no interactive prompts)
│ ├── Executes the task autonomously
│ └── Returns result to parent
└── Continues with child's output
The agent calls spawn_subagent with:
{
"task": "Write comprehensive tests for the authentication module",
"focus_files": ["src/auth.rs", "src/auth/middleware.rs"],
"use_worktree": true
}When use_worktree is true (default), the child session runs in an isolated git worktree:
- Worktree path:
<repo>/.nca/worktrees/<session-id> - Branch:
nca/<session-id>(created from currentHEAD) - Changes in the worktree don't affect the parent's working directory
- Permissions:
bypass-permissions(no interactive approval needed) - Approvals: Auto-deny handler (no blocking waits)
- Context: Inherits a summary of the parent's last ~10 messages
- Timeout: 600 seconds (10 minutes)
- Lineage: Parent and child session IDs are cross-referenced in metadata
/agents # List child sessions in interactive mode
nca sessions --search "child" # Find sub-agent sessions via CLI| Event | Description |
|---|---|
ChildSessionSpawned |
Child session created |
ChildSessionCompleted |
Child session finished |
ChildSessionActivity |
Intermediate activity from child |
nca supports the Model Context Protocol for integrating external tool servers.
Add MCP servers in your config:
[[mcp.servers]]
name = "filesystem"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
enabled = true
[[mcp.servers]]
name = "database"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]
env = { DATABASE_URL = "postgresql://localhost/mydb" }
enabled = true
[[mcp.servers]]
name = "custom"
command = "/usr/local/bin/my-mcp-server"
args = ["--port", "3000"]
cwd = "/opt/my-server"
env = { API_KEY = "secret" }
enabled = true| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | Server identifier (used in tool names) |
command |
string | required | Command to start the server |
args |
string[] | [] |
Command arguments |
env |
map | {} |
Environment variables |
cwd |
string | — | Working directory |
enabled |
bool | true |
Whether the server is active |
MCP tools are exposed with the naming convention:
mcp__<server_name>__<tool_name>
For example, a server named database with a tool query becomes mcp__database__query.
nca mcp # CLI
nca mcp --json # JSON output/mcp # Interactive mode
By default, MCP tools are not available in safe mode. To allow them:
[mcp]
expose_in_safe_mode = trueHooks let you run shell commands at various points in the session lifecycle.
| Hook | When It Fires |
|---|---|
session_start |
Session begins |
session_end |
Session ends |
pre_tool_use |
Before a tool executes |
post_tool_use |
After a tool succeeds |
post_tool_failure |
After a tool fails |
approval_requested |
When user approval is needed |
subagent_start |
When a sub-agent is spawned |
subagent_stop |
When a sub-agent completes |
[[hooks.session_start]]
command = "echo 'Session started' >> /tmp/nca.log"
blocking = false
[[hooks.pre_tool_use]]
command = "my-audit-script --tool $NCA_TOOL_NAME"
matcher = "execute_bash" # Only fire for bash tool
blocking = true # Wait for completion before proceeding
[[hooks.session_end]]
command = "notify-send 'nca session ended'"
blocking = false| Field | Type | Default | Description |
|---|---|---|---|
command |
string | required | Shell command to execute |
matcher |
string | "" |
Regex pattern to filter when the hook fires |
blocking |
bool | false |
Whether to wait for the hook to complete |
The memory system stores notes that persist across sessions.
nca memory # List all notes
nca memory list --json # JSON output
nca memory add "prefer async/await patterns" # Add a note
nca memory add "uses PostgreSQL" --kind note # With type/memory # List notes
/memory always use anyhow for error handling # Add a note
[memory]
file_path = ".nca/memory.json" # Storage location
max_notes = 128 # Maximum number of notes- Notes are stored as JSON in the workspace
- Notes are included in the agent's context on each turn
- The agent can reference stored notes for consistency across sessions
- Notes are workspace-scoped (stored in
.nca/memory.json)
nca can be driven by external orchestrators (CI systems, automation scripts, custom tooling) via environment variables and structured output.
Set these to inject orchestration context into the session:
export NCA_ORCH_NAME="github-actions"
export NCA_ORCH_RUN_ID="run-123"
export NCA_ORCH_TASK_ID="task-456"
export NCA_ORCH_TASK_REF="PR-42"
export NCA_ORCH_PARENT_RUN_ID="parent-run-789"
export NCA_ORCH_CALLBACK_URL="https://my-ci/callback"
export NCA_ORCH_META_REPO="my-org/my-repo"
export NCA_ORCH_META_BRANCH="feature/auth"Orchestration metadata is:
- Stored in session state
- Injected into the system prompt
- Available to hooks
For CI/automation, combine orchestration with non-interactive flags:
nca run \
--prompt "run tests and report results" \
--permission-mode bypass-permissions \
--json \
--stream ndjsonUse --stream ndjson to get machine-readable events:
nca run --prompt "fix the build" --stream ndjson | while read -r event; do
echo "$event" | jq '.event_type'
doneEach line is a JSON object with:
id— monotonic event IDts— timestamp- Event-specific fields (message content, tool calls, approvals, etc.)
Running sessions expose a Unix domain socket for external control.
$XDG_RUNTIME_DIR/nca/<session-id>.sock
# Fallback:
/tmp/nca/<session-id>.sock
Newline-delimited JSON over Unix domain socket.
Server → Client (events):
Events are broadcast as EventEnvelope objects:
{"id": 1, "ts": "2026-04-02T10:30:00Z", "event": {"type": "MessageReceived", ...}}
{"id": 2, "ts": "2026-04-02T10:30:01Z", "event": {"type": "ToolCallStarted", ...}}Client → Server (commands):
{"type": "SendMessage", "content": "continue with the refactoring"}
{"type": "ApproveToolCall", "call_id": "abc123"}
{"type": "DenyToolCall", "call_id": "abc123"}
{"type": "AnswerQuestion", "question_id": "q1", "answer": "option-a"}
{"type": "Cancel"}
{"type": "Shutdown"}| Event | Description |
|---|---|
SessionStarted |
Session initialized |
SessionEnded |
Session finished (with reason) |
MessageReceived |
User or assistant message |
TokensStreamed |
Streaming token delta |
CostUpdated |
Token usage update |
ToolCallStarted |
Tool execution began |
ToolCallCompleted |
Tool execution finished |
ApprovalRequested |
Waiting for user approval |
ApprovalResolved |
Approval decision made |
QuestionRequested |
Agent asking user a question |
QuestionResolved |
Question answered |
ChildSessionSpawned |
Sub-agent created |
ChildSessionCompleted |
Sub-agent finished |
ChildSessionActivity |
Sub-agent intermediate activity |
ContextWarning |
Context window getting full |
ContextCompaction |
Context was compacted |
BusyStateChanged |
Agent state changed (Thinking, Streaming, Idle) |
Checkpoint |
Session checkpoint saved |
Error |
Error occurred |
nca loads instructions from multiple sources, merged in order:
- Built-in system prompt — nca's core behavior rules (disable with
harness.built_in_enabled = false) AGENTS.md— project-level instructions in the workspace root.ncarc— nca-specific project instructions (configurable path).nca/instructions.md— personal local instructions (gitignored)- Skills — available skills listed for on-demand invocation
- Orchestration context — injected when orchestration env vars are present
Placed in the workspace root. Compatible with other AI tools (Claude Code, etc.):
## Project Rules
- Use axum for HTTP servers
- All errors must use thiserror
- Write tests for every public functionnca-specific project instructions:
## Stack
- Rust + Tokio async runtime
- PostgreSQL via sqlx
- Redis via deadpool-redis
## Conventions
- Module names are snake_case
- Error types end with Error
- Tests live in the same file as the codePersonal instructions (add to .gitignore):
## My Preferences
- I prefer verbose variable names
- Always add doc comments to public items
- Use `tracing` for logging, not `log`nca includes an auto-research feature for automated investigation:
nca autoresearch once <program> [--workspace <path>]This runs a single automated research pass on a program or topic, generating structured output in the workspace.
Run diagnostics to verify your setup:
nca doctorChecks:
- Configuration file validity
- API key availability for configured providers
- Provider connectivity
- Required tool dependencies (git, rg)
- File system permissions