v0.2.0 · alpha Download Changelog GitHub
>_ docs / concepts / One truth, one home
§ 02 Concepts

One truth, one home

Grounded pays off in proportion to how tidy you keep it. Give an agent one clean copy of each truth and it starts oriented. Give it three slightly different copies, spread over config files, memory notes and facts, and it starts confused, burns its startup window re-reading itself, and follows whichever copy it saw last. This page is the discipline that keeps the first case from sliding into the second.

// The rule

The contract #

The context contract

Every truth has exactly one home. Agent config files hold what is static and per-machine. Grounded holds what is dynamic, scoped, or trigger-time. Writing a truth to a second home is a defect, not a backup.

"Backup" is the instinct that breaks it. Copying a rule into a second file feels safe — if the agent misses it in one place it will catch it in the other. In practice the copies drift apart the first time anyone edits one of them, and from then on the agent holds two rules that disagree and no way to know which one is current. One home means one place to fix it and nothing left to contradict it.

The contract covers two surfaces. Surface A is everything your agent loads on its own: instruction files such as CLAUDE.md or AGENTS.md, output styles, hooks, skills, memory files. Surface B is Grounded: the four lanes. Claude Code is the running example below; the contract holds for any agent that reads a config file at startup and can call Grounded.

// The failure mode

How context rots #

Nobody decides to bloat their agent's context. It happens one reasonable edit at a time:

  • Load-time bloat. Every session pays for every line in every file the agent loads before you type. The files only ever grow, because adding a line is cheap and deleting one feels risky.
  • Doubled rules. The same rule written into the global config, the project config, a memory note and a Grounded fact. Each copy spends budget; none of them adds information.
  • Conflicting copies. Doubled rules drift. One copy gets updated, the others don't, and the agent now carries an instruction and its opposite.
  • Stumbles become prose. The agent trips on something, and the fix is a new paragraph: the rule, why it exists, the date it was learned, the incident that taught it. The paragraph is the crack spreading, not the repair.
  • Nothing refuses the regrowth. You can clean all of this up in an afternoon. Without something that rejects the next bad edit, it grows back within weeks.

That last one is not hypothetical. Here is a real five-machine fleet, audited after its context had already been cleaned up once and had regrown:

MeasuredResult
Agent context loaded before the first prompt, per machine8 – 33 KB; four of five machines over 15 KB
Active Grounded facts also written into an instruction file24 of 48
… of which disagreed with their copy7
Places the agent's voice and reply format were stated6 instruction-file blocks, plus the one output style meant to own it
Global-scope facts against the facts reserve~9.5 K chars written into a 6 K-char lane; project facts were being dropped from the brief to make room

Provenance: one audit of a working fleet (five machines, one Grounded engine) in October 2026, measured as bytes on disk and rows in the engine. That fleet had raised its facts reserve above the shipped default; the numbers on this page that describe Grounded itself are the engine's shipped defaults.

The over-full facts lane is the expensive part. Grounded is honest about it — the brief names every fact it compressed or dropped — but honesty about a cut is not the same as delivering the rule. Half of what was being cut had another home anyway.

// Static, per machine

Surface A: the agent #

Surface A is what the agent loads by itself, every session, whether it needs it or not. That makes it the right home for things that are true every session on this machine and wrong for anything else. Each slot has one job and a cap. The caps are guidance, not engine limits — they are what a clean fleet converged on, and the ratchet is how you hold them.

SlotHoldsCap
Global instructions
e.g. ~/.claude/CLAUDE.md
Truths for every machine: how to reach Grounded, where things live, one line per machine, shell facts that hold everywhere, hard rules no hook can enforce yet. Identical on every machine.40 lines
Machine stub
imported by the global file
This machine only: hostname, user, dev root, OS and path quirks, what runs here.12 lines
Workspace file
e.g. <repo>/CLAUDE.md, AGENTS.md
What this workspace is, which Grounded project it maps to, what runs here, key-file pointers, workspace-only hard facts. No role prose, no procedures, no voice.30 lines
Voice
e.g. an output style
Tone, length, format. The only place they are stated.8 lines
Guards
pre-tool hooks
Rules that must never break, enforced by refusing or rewriting the action. A rule with a hook needs no prose anywhere.—
Procedures
skills, commands, how-to docs
Multi-step work, loaded on demand. At most one pointer line in a config file, and only if the skill doesn't trigger on its own.on demand
Gotchas
one doc per platform
Trap plus workaround, keyed on the error text. Reached by one pointer line in the machine stub; never copied in.on demand
Memory
agent-managed memory file
Your preferences and feedback. Anything that restates a config file or a fact gets pruned.20 entries

Line shape for the three instruction files: one imperative line per truth. No rationale, no history, no dates, no "verified", no measurements, no voice words. The why belongs in a session or a doc, where it can be recalled when someone asks — not in a file every session pays to read.

// Dynamic, scoped, trigger-time

Surface B: Grounded #

Grounded holds what changes, what applies only somewhere, and what an agent needs at the moment it touches a thing rather than at startup. Each lane has a job, a list of things it must not carry, and a budget the engine enforces at write time:

LaneCarriesDoes not carry
factsThe residue: rules that are in no config file, can't be a hook, and are scoped to a project, agent or machine — or likely to change. Pointer-shaped, with the trigger clause in detail.Anything a config file already says (delete it, don't mirror it). Voice. Procedures. Done-history.
global factsStaging. A global fact is a global-config line that hasn't been merged yet.Permanent residents. Each tidy either promotes it to the global file or deletes it.
visionDirection: the objective and the committed next steps.Rule lists, status, history, procedure.
sessionsThe position fix: what shipped, short summary up front, detail in the body.Instructions.
docsEverything long: how-tos, plans, project state files.—

The caps are not a separate style guide. They come from the same table the brief uses to share out the startup window, so a row that passes the write cap is a row that fits its lane. Shipped defaults:

LaneFieldWarns at (row share)Rejects at (lane cap)
factsfact + detail450 chars400 over 3,600 chars
sessionssummary250 chars400 over 2,000 chars
sessionsdetails— never injected400 over 16,000 chars
visiondetails, summary— one row is the lane400 over 1,600 chars

Over the row share is a warning: the row is stored, but it is eating a neighbour's slot. Over the lane cap is a 400 that names the cap and how many chars to trim. Raising brief.reserve.<lane> in config.toml moves both together, and GET /health prints the table your engine is actually enforcing, with a count of stored rows already over it. Audit the lane before you raise it: a bigger reserve moves the cliff, it doesn't remove it, and every char it adds comes out of the window the other lanes share.

Three lane-specific notes the caps don't tell you:

  • Prefer trigger-time facts. A fact scoped to a project and carrying a trigger clause is most useful at the moment the agent touches that thing. A pre-edit hook that calls POST /recall with sources: ["fact"] delivers it then, instead of spending startup budget on every session. See hooks.
  • Global and project vision share one reserve. When both are injected, the project row is cut first. Keep each well under half the cap if you run both, and remember a vision summary replaces its details in the brief — it isn't added to them.
  • Pinned is a delivery guarantee. The whole pinned set survives the facts reserve, so pinning everything just moves the overflow onto your unpinned facts.
// The habit

Routing a new lesson #

Regrowth starts when an agent trips on something and the lesson gets written down in whatever file is open. Route it instead. Take the first match below and write it there and nowhere else:

  1. Can a hook make it impossible, or automatic? Write the hook. Write no prose anywhere.
  2. Is it true of this machine every session? The machine stub. Every machine? The global file. This workspace? The workspace file. One line.
  3. Is it a procedure, or a trap with a workaround? A skill or the platform's gotchas doc. Add a pointer line only if nothing reaches it already.
  4. Does it apply only when touching X, only in one project, or is it likely to change? A Grounded fact with a trigger clause, scoped to where it applies.
  5. Is it about tone or format? The voice slot already owns it. Do nothing.
  6. Is it what the work is for? Vision. What shipped? A session.

A config line with a "because" clause is not a fix. Neither is a fact that repeats the config file "to be safe". Both are the defect the contract names.

// What refuses regrowth

The ratchet #

Tidiness that depends on remembering to be tidy lasts about a month. A ratchet turns one way: each piece below refuses a bad edit at the moment it is made, while the author is still there to fix it.

RatchetWhereRefuses
Config lintAgent side: a pre-tool hook on edits to instruction and voice files. You add it.An edit whose result breaks a line cap; contains a date, "verified", "because", "used to" and the like; uses voice words outside the voice slot; or near-duplicates a line in another config file or an active fact (GET /facts?status=active). Reject the edit, don't warn — and name the other home.
Lane capsEngine, built in.A fact, session or vision over its lane cap: 400 with the trim count. Row-share overruns come back as warnings on the write.
Delivery checkEngine, built in.Silent invisibility. Every fact write returns delivery — delivered: false means it won't reach the brief. Read it.
Revise, don't appendEngine, built in.Near-duplicates. A fact posted with a topicKey is a merge-patch on (scope, topicKey); a wrong session is corrected with PATCH /sessions/:id, not contradicted by a second row; a vision set replaces its scope's row.
Impact firstEngine: POST /impact.Dangling references. Before you delete or rename anything, ask what still points at it, so the fix lands everywhere at once.
PruneEngine: POST /docs/prune.Ghost docs. A file you moved or deleted stays recallable until you prune; editing its frontmatter does not retire it.

The lint is a pattern, not a shipped Grounded feature: it lives on the agent side because that's where the config files are. The engine's half — caps, delivery accounting, merge-patch writes, impact, prune — is built in.

// Fifteen minutes a week

The weekly tidy #

  • Check health. GET /health: per-lane over-cap counts should be zero.
  • Read a real brief. One per active project. Anything in droppedItems or compressed to the index tier is a lane to audit, not a reserve to raise.
  • Empty global staging. Promote each global fact to the global config file or delete it. Aim for ten or fewer.
  • Hunt doubles. For every fact, ask whether a config file already says it. If so, delete the fact. If they disagree, fix the winner and delete the loser.
  • Delete what's done. A fact describing a fixed problem is a to-do that outlived its fix.
  • Trim sessions. PATCH any summary over 250 chars, and any summary a later session proved wrong.
  • Re-read the vision. Objective and next steps only. Anything that happened goes to a session; anything about how goes to a doc.
  • Prune docs. Run POST /docs/prune after moving or deleting files, with POST /impact first.
  • Lint the config files. Line caps hold, no dates, no why-text, voice only in the voice slot, memory file at twenty entries or fewer.

Do it weekly and it takes minutes. Skip it for a quarter and you are back to the audit above.