Agents
Agents meet ctx three ways: the keys that matter to them arrive in their system prompt, tools let them read, write and search the store, and subscriptions bring them changes as messages, waking them when they are idle.
Where things go
The store enforces no layout, so agents share one. These prefixes are what the default preload reads and what the agent skill teaches.
| Prefix | Holds |
|---|---|
global.* | Fleet-wide facts everyone should know. Keep it tiny: it is in every prompt. |
project.<repo>.* | Per-repository state: status, decisions, conventions, open questions. <repo> is the checkout's directory name. |
machine.<node>.* | Per-host facts: services, quirks, maintenance. <node> is the short host name. |
agent.<id>.* | An agent's own working state, readable by everyone else. |
flow.<name>.* | State machines: .state, .log, inputs and outputs. |
user.* | The operator's preferences and standing instructions. |
Invent sub-keys freely, but extend an existing subtree before starting a new one.
Context in the prompt
When a session starts, the Pi plugin or the pi-daemon module runs ctx prompt for it and puts the result in the ctx section of its system prompt. The keys come from pi.keys, with placeholders filled in for that session.
Run it yourself to see exactly what an agent will get. This is wren's preload in the lighthouse checkout on atlas:
CTX_AGENT=wren ctx prompt# Shared context (ctx)Live entries from the fleet's ctx store. Read more with ctx_get/ctx_search; record durable facts and state with ctx_set/ctx_update.## ctx: global (1 entry)- `global.freeze` (46s ago, ci): false ## ctx: project.lighthouse (3 entries)- `project.lighthouse.conventions` (46s ago, heron): "Tests: cargo nextest; never commit generated fixtures" - `project.lighthouse.decisions` (46s ago, heron): [{"what":"Retry ingest twice, then fail the batch","by":"heron"}] - `project.lighthouse.status` (46s ago, wren): {"state":"review","pr":31,"branch":"wren/flaky-ingest"} ## ctx: machine.atlas (1 entry)- `machine.atlas.quirks` (46s ago, heron): "Nix builds capped at 8 jobs; /scratch is wiped nightly" ## ctx: agent.wren (1 entry)- `agent.wren.task` (46s ago, wren): {"bead":"bd-41c2","doing":"fix flaky ingest test"}
The preload is read again when it is more than ten minutes old, before the agent's next turn; /ctx refresh reads it now. ctx prompt --key and the pi settings change what is read and how much: see the configuration reference.
Tools
ctx mcp stdio is an MCP server for any agent harness. Its tool descriptions carry the conventions above, so agents use the store well without extra instructions.
| Tool | For |
|---|---|
ctx_get | A key and its subtree as one tree; max_age, stale_after, max_bytes, rev, meta. |
ctx_list | What exists below a prefix, with counts, ages and writers. |
ctx_search | Context whose key you do not know, by keyword or meaning. |
ctx_set, ctx_update, ctx_append, ctx_delete | Writes, each with an optional if_rev. |
ctx_batch | Several writes, all or none. |
ctx_history, ctx_changes | A key's past versions; changes after a revision, for polling. |
ctx_prompt | The preload text a Pi session would receive. |
ctx_guide | The full agent guide, for agents adopting ctx in a new workflow. |
ctx_status | Head revision, counts, size and watchers. |
The server also exposes the configuration tools every ctx config command has. The agent skill in the repository, skills/ctx/SKILL.md (also ctx guide), teaches the same conventions to agents that load skills.
Subscriptions wake agents
An agent can follow a pattern instead of polling. ctx_subscribe takes the pattern, an optional delivery and an optional since_rev; from then on, matching changes made by anyone arrive as a message.
[ctx] 3 changes to `flow.deploy.**`:- rev 14 `flow.deploy.state` set by ci: "building"- rev 15 `flow.deploy.state` set by ci: "deploying" (was "building")- rev 16 `flow.deploy.state` set by ci: "done" (was "deploying")(From your ctx subscription to `flow.deploy.**`, now at rev 16. It stays active for later changes; keep it unless you no longer need these updates.)
| Delivery | The agent is idle | The agent is working |
|---|---|---|
follow-up (default) | The message starts a new turn: the agent wakes. | The message waits until the current turn ends. |
steer | The message starts a new turn. | The message interrupts the turn. |
- Batched: changes arriving within
pi.debounce-ms(1.5 s) become one message, with previous values. Long batches are trimmed and say how to list the rest withctx_changes. - Durable: subscriptions are saved in the session and resume after a restart from the last revision delivered.
- Visible:
ctx_unsubscribestops one by id or pattern;ctx_subscriptions(Pi) or/ctxlists them.
In Pi
The repository is a Pi package. Add git:github.com/harryaskham/ctx to Pi's packages and every session gets the preload, the three subscription tools and the /ctx command. It drives the ctx binary on PATH (or CTX_BIN), so configuration, transport and semantics stay in one place.
| Command | Does |
|---|---|
/ctx | Head revision and entry count, what the preload holds, and how many subscriptions are active. |
/ctx refresh | Reads the preload again. |
/ctx get KEY | Shows a key's value. |
In pi-daemon
For pi-daemon sessions, add the module the Nix package ships at share/ctx/pi/pi-daemon/ctx.mjs to a profile's extensions, alongside the MCP server for the tools.
- Preload: the same
ctxprompt section, rendered in the session's own shell, so its working directory andCACO_AGENT_IDchoose the keys; cached for ten minutes. - Subscriptions:
ctx_subscribeandctx_unsubscribe. Changes reach the session's chat as AHP queued or steering messages, which wakes an idle agent, and resume after restarts. - Delivery setup: the daemon's environment needs
CTX_AHP_URL(ws://<api bind>:7463/ahp) andCTX_AHP_TOKEN_FILE.
Good citizenship
Everything is shared and nothing expires, so the store stays useful only if writers keep it tidy.
- Conclusions, not transcripts. Write the decision and its reason, not the conversation that reached it.
- Small and current. Summaries, ids, links and short lists; update entries in place and cap logs with
max_items. - Check the age. An entry is a claim by its writer at a time. Prefer fresh entries; re-check stale ones.
- Write conditionally when others may write the same key, and re-read on a conflict.
- Clean up what is obsolete, and never store secrets, tokens or private data.