Files
HomerandClaude Opus 5.5 8e06590d57
ci / check (push) Canceled after 0s
Harness spec 3.1.0: the prefix stays still, in the CLI
The system prompt is made once per session (start, compaction, model
switch), kept in session_meta and resent byte for byte; it holds no
date. What changes mid-session -- the date, a mode the person chose, a
plan or memory or instruction file they edited, a personality, MCP
instructions that arrived later -- is a <session-note> on the next user
message, stored with it. The tool list is fixed for the session:
plan_submit is always offered and answers unavailable outside plan
mode, the wrap-up keeps the tools and runs no call, a withdrawn tool
stays listed and answers its refusal; the first request waits up to
mcp_wait_ms for MCP servers. Compaction asks for its summary as the
next turn of the same conversation. Cached input tokens are parsed
(incl. llama.cpp timings), stored per request and shown in /context.

Spec: context.md §7/§10, loop.json context.note (+ plan_ended,
plan_own, personal, empty, mcp_wait_ms), modes.json plan.refused,
compact.md without the transcript heading. Conformance area prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 13:22:02 +00:00

128 lines
9.6 KiB
JSON

{
"about": "How one prompt runs: model step, tool calls, results, again — and what ends it early. Both harnesses run this loop; the numbers are each project's defaults, the behaviour is the spec's.",
"steps": {
"about": "A runaway backstop, not a working budget: a prompt is meant to run until the task is done, and a step count low enough to end it ends it halfway. Past it the tools are withdrawn and the model answers (wrap_up).",
"default": 200
},
"budgets": {
"about": "What one prompt may spend. Checked between steps, never mid-reply — a reply cut off mid-sentence is worth nothing. Time spent waiting for the user (an approval, a question, a plan) is not counted. Past one, the tools are withdrawn and the model answers from what it has (wrap_up). The CLI leaves them unset by default (one user at their own terminal); LLeMbas sets them, and a group's quota can narrow them.",
"wall_seconds": {
"about": "Seconds of work.",
"cli": null,
"llembas": 900
},
"output_bytes": {
"about": "Bytes of tool output read: a model filling its own context with build logs has no room left to answer.",
"cli": null,
"llembas": 1048576
},
"completion_tokens": {
"about": "Tokens the model writes.",
"cli": null,
"llembas": 200000
}
},
"wrap_up": {
"about": "One more request, with the session's tool list unchanged (context.md §10, rule 4) and a user message saying which limit was reached: answer now — what is done, what is not, what would come next. The transcript says the prompt was stopped, so an answer given because the room ran out is never mistaken for one the model chose to give. A tool call in that reply is not run.",
"message": "The {{limit}} for this prompt has been reached and the tools have been withdrawn. Answer now from what you have: what is done, what is not, and what would come next."
},
"nudges": {
"about": "A reply with only thinking, or one cut off at the output limit, is asked again (at most twice in a row) instead of ending the prompt with nothing said.",
"max": 2
},
"parallel": {
"about": "Calls in one step run together, at most 4; a call that waits on the user (ask_user, plan_submit) runs alone; two calls on one file run in order. A tool's error is its result, never the end of the prompt.",
"max": 4
},
"capacity": "A subagent (task) is not started on a model whose server cannot hold it beside the prompt's own model — or beside the model of a subagent already running: another model of a connection that holds one model at a time, or the same model when it serves one request at a time (models/schema.json capacity).",
"jobs": {
"about": "Background work owned by a session: a command (bash `background: true`, or one still running when its timeout passed) or a subagent (task `background: true`). One id sequence per session (job1, job2, …), one list (job_list), one way to read (job_output), to stop (job_stop) and, for a subagent, to message (job_send); a subagent's own tools see only the jobs it started. A job that ends wakes the session that owns it: while a prompt runs, as a user message at the next step boundary; otherwise as a new turn of its own, marked `machine` so a UI shows it as the harness's, not the person's. A session that is not open keeps the note until it is resumed. Every such message begins with its mark, said rather than hidden: a model refuses an unmarked one as an injection (conformance/jobs.json gives the texts).",
"marks": {
"command": "[A background job you started has finished:]",
"subagent": "[A subagent you started has finished:]",
"message": "[A message from a subagent you started:]",
"to_subagent": "[The main agent sent this while you were working — take it into account from here:]"
},
"note_tail_chars": {
"about": "Of a finished command's unread output, how much the note carries (the end of it).",
"default": 4000
},
"finished_kept": {
"about": "Finished jobs kept per session, oldest forgotten first.",
"default": 50
},
"running_max": {
"about": "Background commands one session may have running at once; past it, bash refuses to start another.",
"default": 8
},
"subagent_steps": {
"about": "The step backstop of a subagent (the CLI: limits.subagent_steps).",
"default": 50
},
"lifecycle": "A subagent's own background commands stop when it ends, and its report says so. A session's jobs stop when the session is deleted. A front end asked to exit while jobs run asks the person first; one with nobody to ask waits for the jobs the prompt started, then stops the rest."
},
"context": {
"about": "Context hygiene (spec 3.0.0, the prefix from 3.1.0; context.md): every measure acts when a result is inserted, and nothing already sent to the model is ever rewritten — changing earlier context throws away the prompt cache from that point. conformance/context.json gives the texts.",
"ids": {
"about": "Every tool result gets an id: `#` and its number in the session, counting from 1, in lowercase hex, at least 4 digits (`#0001`, `#000a`, `#10000`) — unique in the session and never reused (not after a compaction either), so `recall` finds any of them. It is the first thing in the result, in brackets.",
"digits": 4
},
"read_header": "[{{id}} {{path}} lines {{from}}-{{to}} of {{of}} sha {{sha}}]",
"read_header_empty": "[{{id}} {{path}} empty sha {{sha}}]",
"edit_header": "[{{id}} {{path}} sha {{sha}}]",
"header": "[{{id}}]",
"unchanged": "Unchanged since {{earlier}}, which already shows lines {{from}}-{{to}}.",
"same_result": "Same result as {{earlier}}.",
"elided": "[{{n}} lines elided, full output {{id}}]",
"created": "Created, {{n}} lines.",
"no_result": "No stored result {{target}} in this session.",
"recall_header": "[{{id}} recall {{target}} lines {{from}}-{{to}} of {{of}}]",
"sha_digits": 8,
"cap": {
"about": "A result over max_lines lines or max_chars characters keeps its head (as many whole lines as fit both head limits) and its tail (likewise, from what is left), with the elided line between. When even the first line does not fit head_chars, it is cut to it and ends ` […cut]`, and the elided line follows however many whole lines it counts (0 included): it is there whenever anything was left out. Not applied to read (its own window: 2000 lines from an offset) or recall (likewise). The full output is stored with the session.",
"max_lines": 400,
"max_chars": 40000,
"head_lines": 200,
"head_chars": 20000,
"tail_lines": 100,
"tail_chars": 10000
},
"dedupe": {
"about": "by_hash: a read whose file (by its absolute path) has the same content hash as an earlier full read in the table, and whose lines lie wholly inside that read's, is answered with `unchanged`. by_result: a call with the same arguments as an earlier one in the table, whose result is the same text, is answered with `same_result`. Stubs point at the full result, never at another stub. The table is the full results in the request being built — never one the request does not carry (a chat's earlier reply, a turn undone) — and compaction empties it.",
"by_hash": [
"read"
],
"by_result": [
"list",
"glob",
"grep",
"search"
]
},
"compaction": {
"about": "The one deliberate break of the cache. After the summary the harness adds the table of the reads the summary covers — the full reads made since the previous compaction, in turns still in the history being summarised, whether or not the request still carries them; of those the newest full read of each file, newest last, at most `rows` — and then empties the dedupe table, so no stub ever points at content that is gone from the context. No reads: no table.",
"heading": "## Files read before this summary",
"line": "Read a file again for its content; recall shows a result by its id.",
"rows": 50
},
"reasoning": "Earlier turns' reasoning is left to the model's chat template: the harness sends the history as it does, neither stripping reasoning the template keeps nor adding what it drops.",
"note": {
"about": "A note on the next user message (context.md §10, rule 3): what changed since the system prompt was made, after the person's words. Lines in this order, each only when it applies. `plan_ended` is the mode block for a session that leaves plan mode for a mode with no text of its own (a chat). `plan_own` is the plan block for a session that does not resend earlier tool results (a chat): the model's own plan, as its tools left it. `personal` is the {{path}} of the instructions block for the person's own instructions.",
"open": "<session-note>",
"close": "</session-note>",
"date": "Today is {{date}}.",
"mode": "The permission mode is now {{mode}}:\n{{mode_text}}",
"plan_ended": "Plan mode has ended: make the changes the work needs; nothing is refused for planning any more.",
"plan": "The person changed the plan; it is now:\n{{plan}}",
"plan_own": "Your plan, as your plan tools left it:\n{{plan}}",
"memory": "The person changed what is remembered; it is now:\n{{memory}}",
"instructions": "{{path}} changed; it now reads:\n{{text}}",
"personal": "the person's own instructions",
"personality": "The person chose a different personality:\n{{personality}}",
"mcp": "Instructions from an MCP server that connected since the session began:\n{{instructions}}",
"empty": "(none)"
},
"mcp_wait_ms": 3000
}
}