Skip to content

Context structure

Everything the model sees on a turn is assembled from layers, in a fixed order. netclaw doesn’t hand the model one blob of text. It stacks a persisted system prompt, a block of static context, the conversation history and a fresh per-turn nudge, then attaches the tool schemas separately on the request.

The order is deliberate, and it’s built for prompt caching. The stable material sits at the front so the provider can reuse the cached prefix across turns, and the material that changes every turn sits at the back near the model’s generation point. That’s why the current git state is injected late and your persona sits first.

What each layer contains, and whether it appears at all, depends on the session’s audience. A Public turn gets a deliberately thin stack. Team and Personal get the full one.

Tier A, persisted system prompt(cached head): SOUL.md,AGENTS.md, TOOLING.md, projectinstructionsTier B, static context (first call, andagain after compaction): tool index,skill index, memory status, sessionpathsTier C, conversation history(compacted as it grows): prior turns,each with its nudgeTier D, per-turn nudge (saved intohistory): memory-recall, skill hint,subagents, time, working-context,background jobsModel generates the replyTool schemas, on the request and notin the prompt

Built once and stored as the head of the conversation, then rebuilt only when its inputs change. Byte-identical content is left alone to preserve the cache. Four identity layers, concatenated in order:

LayerWhat it isSource
SOUL.mdPersona, tone, your name~/.netclaw/identity/SOUL.md
AGENTS.mdOperating rules: the built-in core plus your deployment playbookembedded in netclaw, plus ~/.netclaw/identity/AGENTS.md
TOOLING.mdWhat the host can actually do~/.netclaw/identity/TOOLING.md
Project instructionsRepo-specific rulesfirst of .netclaw/AGENTS.md, CLAUDE.md, AGENTS.md, CONTEXT.md in the project directory

The AGENTS.md layer has two halves: an operating core compiled into netclaw (a stripped-down variant on Public) and the deployment playbook you write at ~/.netclaw/identity/AGENTS.md. Project instructions follow the same AGENTS.md and CLAUDE.md convention other coding tools use, but are read from the project directory.

Layers that don’t change over a session’s life. They’re rendered on the first model call and again right after a compaction, which resets the context, and otherwise they stay out of the way so they never churn the cached prefix:

LayerWhat it isEmpty when
Tool indexA compressed, audience-filtered catalog of available tools, for awareness and not invocation-
Skill indexThe loaded skill inventoryPublic, or skills disabled
Memory statusWhether the memory subsystem is healthy, and how to use its toolsPublic, or memory disabled
[session]Session id plus five paths: session_dir, temp_dir, artifact_dir, worktree_dir and log_path, with short guidance on using themid only on Public
[attachments] hintHow to handle attached filesfile_read not granted

The tool index is awareness only. The actual tool schemas ride on the request itself (as the provider’s tool parameter), resolved and audience-filtered every turn. A tool has two surfaces: a compressed name in the prompt for discovery, and its full schema on the wire.

The turns so far, verbatim. When it grows past the budget it gets compacted: old tool output is cleared, older messages are dropped, and a short block of compaction notes about what was dropped takes their place. The durable working context (below) survives compaction. The raw transcript doesn’t.

This is the freshest layer, rebuilt every turn. One quirk is worth knowing: it isn’t a trailing system message. netclaw wraps it in a [system: ...] block inside a user-role message placed just before your latest message and saves it into history. That keeps it inside the cacheable prefix on later turns, and it sidesteps the “a fresh user turn just started” confusion some models have with trailing system text. The order inside it:

LayerWhat it isSuppressed on Public
[memory-recall]Memories recalled for this turn, if any cleared the relevance gate✓
Skill hintA nudge toward a relevant skill-
[available-subagents]Subagents this session can spawn✓
[current-time]UTC, local, day, timezone-
[working-context]Shell, git state, project dir and recent files✓
[active-background-jobs]Running or reaped background work✓
Slash-command skill contentThe body of a skill invoked with /name-
Session prompt overlayA per-session instruction added on top-
Turn restart noticeTells the model the daemon restarted and it’s resuming-
Interrupted-automation noteCarried by the first model call after a person ends an automation turn: the automated turn stopped unfinished because a person sent a message. Later turns don’t carry it-

Most turns carry no [memory-recall] block. The relevance gate drops weak matches, and when nothing survives the block is omitted. See the memory model.

Public sessions run untrusted input, so most of the stack is withheld:

PublicTeam / Personal
SOUL.md, AGENTS.md core, tool index, [current-time]✓ (public AGENTS variant)✓
TOOLING.md, project instructions-✓
Skill index, memory, subagents, working-context, background jobs-✓
[session]id onlyid and paths

On Team and Personal turns where a project directory is set, netclaw derives a live snapshot of your git state and drops it into the nudge as a [working-context] block. It’s how the model knows what branch you’re on and what you’ve been touching without you spelling it out.

It’s computed fresh at the start of every turn by shelling out to git, so git has to be on the daemon’s PATH, under a hard 2-second budget. Nothing is persisted. The snapshot is rebuilt each turn, and the durable half (project directory and recent files) is what survives compaction and restarts.

What the block contains:

  • shell: on Personal turns only: platform, executable, grammar and, for PowerShell, dialect. It tells the model which shell syntax to write.
  • project_dir, set with the set_working_directory tool.
  • recent_files: the last 10 files read or written, most recent first.
  • git: with worktree, common_dir, branch (or (detached)), head, and upstream, ahead and behind only when the branch tracks an upstream, then counts of staged, modified and untracked files.

If git isn’t reachable, the run is slow, or the directory isn’t a repo, the block degrades to a short unavailable note with a reason (for example git executable not found) instead of failing the turn.

A subagent doesn’t get a copy of the parent’s context. It runs a much thinner stack, assembled fresh for a one-shot task:

AGENTS.md operating rules + project instructions
+ the subagent's own markdown body
+ a compressed tool index
+ a headless execution contract

Its first user message carries a Context: ... Task: ... pair, the working-context block, and its own [session] block.

What a subagent inherits from its parent at spawn time:

  • The AGENTS.md operating rules and project instructions (audience-appropriate), so a child plays by the same house rules as the parent.
  • The project directory, the recent-files list, and the same working directory. A subagent edits the same files the parent would.
  • The parent’s audience and a tool policy filtered to it, minus spawn_agent, check_agent_run and attach_file, so subagents can’t spawn their own.
  • An initial git snapshot taken at spawn.

Each child gets its own temp_dir, artifact_dir and log_path. On Linux and macOS the child’s temp_dir is /tmp/netclaw-<uid>/<key>/c<8 hex>, and the other two sit under the parent’s session folder. A successful spawn_agent call returns only the run id and "state":"accepted". When the child ends, a notice names its result.md, which lists the log path and the artifact directory, and the parent reads what the child produced with file_read.

What it doesn’t get: your SOUL.md persona, TOOLING.md, memory recall, the skill and memory indexes, subagent discovery, [current-time], background jobs, or the parent’s conversation history.

When a subagent finishes, it hands back a working-context delta. The parent merges only the files a successful child confirmed it wrote or edited into its own recent-files list. A failed or cancelled run merges nothing, and files the child only read aren’t merged. This is an in-memory recent-files handoff and not a git merge: since parent and child share one working directory, the edits are already on disk. The merge just keeps the parent’s sense of “what we’ve been touching” current.

  • The git working context needs a project directory. Without git on the daemon’s PATH the block is present with an unavailable note, and without a project directory (on Team) it’s absent.
  • Changed-file names are never exposed to the model. Only counts, and the recent-files list, carry paths.
  • None of the layer sizes are configurable. Recent files cap at 10 and git inspection at a 2-second budget.
  • Subagents share the parent’s working directory. Nothing isolates a parent from its subagent beyond the audience’s tool policy. Every session also has a managed worktree_dir, and the agent can create a git worktree there with git worktree add and switch into it with set_working_directory, but that’s something it chooses to do, not a default.