Are We Drifting? — Part 10: The Agent OS
Are We Drifting? — Part 10: The Agent OS
Section titled “Are We Drifting? — Part 10: The Agent OS”Part 9: One Operation, Three Interfaces projected one operation onto three transports. This part does the same thing one altitude higher: it projects one agent onto every AI framework that runs it — and keeps the fleet’s shared knowledge from forking.
Are we drifting here?
Section titled “Are we drifting here?”Agents are now contributors. They have roles, instructions, tools, and tiers. And those roles have to exist in more than one place: Claude Code wants an agent file with its frontmatter shape; Cursor wants a rule file with a different frontmatter shape; the docs want a human-readable page describing each role.
Hand-maintain those and you have the oldest drift in the book. Someone tightens an agent’s instructions in the Claude file and forgets the Cursor rule. The docs describe a tool the agent no longer has. The same “principal architect” behaves like two different colleagues depending on which tool you opened. Worse, the shared behavior — how juniors commit, how principals review — gets copy-pasted into every agent and then edited in some but not others, so the fleet’s common knowledge quietly forks.
The question is the series’ question, pointed at the agents themselves: is each role one definition, or many copies pretending to be one?
One source
Section titled “One source”Every agent is one folder with one canonical manifest.json (plus a hand-authored prompt.md, and an optional composition of shared role-blocks). That manifest is the single definition of the role: its name, description, tools, tier, and which shared behaviors it composes.
Shared behavior lives in role-blocks — fragments like principal/advisory-scope, principal/review-checklist, base/commit-skill-pointer — that many agents pull in by reference. An agent’s assembled prompt is its own prompt.md spliced into the ordered blocks it composes. Change a role-block once, and every agent that composes it changes with it. That is the “shared knowledge mesh”: common discipline declared in one place, woven into many roles, never copy-pasted.
Many projections
Section titled “Many projections”A package (agent-registry) walks the manifests and renders each through every registered adapter:
| Adapter | Destination | Render shape |
|---|---|---|
claude | .claude/agents/<name>.md | Claude Code frontmatter + a pointer to the canonical prompt |
cursor | .cursor/rules/<name>.mdc | Cursor frontmatter + a reference to the canonical prompt |
docs-role | the agent’s role.mdx | a Docusaurus role page |
docs-table | the registry table | one row per agent |
The adapters exist because the frameworks genuinely differ — Claude Code needs name/tools/model, Cursor needs globs/alwaysApply — which is exactly why you cannot symlink one file and call it done. Each framework gets the shape it expects, all from one manifest.
The render loop is idempotent: it reads the existing destination, renders fresh content, and only writes if the bytes differ. Running it is a no-op when nothing changed — which is what makes the next part (the gate) clean.
Provider-agnostic tiers: name and wire, again
Section titled “Provider-agnostic tiers: name and wire, again”Here is the name/wire split from the very first vocabulary, reappearing at the top of the stack.
Every model-driven agent carries a tier — E1, E2, E3 — not a model name. The tier is the canonical identity. A separate agent-runtime.json resolves a tier to a concrete model (Claude Sonnet, an OpenAI model, whatever) at dispatch time. The tier is the name; the concrete model is the wire form; the binding is deferred and declared in one place.
So “what model does the principal architect use?” has the same answer-shape as “what string does Ready serialize to?” — it is a resolved projection of a declared identity, not a literal scattered across nineteen files. Swap the model behind E2 and every E2 agent moves together, across every provider, without touching a single agent manifest.
The drift gate
Section titled “The drift gate”The render loop has a check mode. make agents-check runs the adapters in dry-run and exits non-zero if any destination differs from what its manifest would generate. It runs in CI.
So a .claude/agents/*.md that was hand-edited, a Cursor rule left stale after a manifest change, an assembled prompt that was never regenerated after a role-block edit — each fails the build. The only way to change how an agent behaves in any framework is to change the manifest or a role-block and re-run the sync. One source, many rendered projections, a gate that refuses drift between them. The exact shape of Part 3: buildmere, a Codegen Kernel, applied to the colleagues instead of the code.
There are four failure modes the gate is built to catch, and each one tells you something about where the real discipline lives:
| Symptom | What drifted | Fix |
|---|---|---|
.claude/agents/<name>.md body is stale | Manifest or role-block changed; sync not re-run | make sync-agents |
prompt.assembled.md missing | composition key added; make sync-agents never re-run | make sync-agents |
Orphaned .claude/agents/<name>.md | Agent folder deleted without pruning | make sync-agents PRUNE=1 |
| Cursor rule out of sync | .cursor/rules/<name>.mdc hand-edited after manifest change | make sync-agents |
Every row in our failure-mode table ends the same way: make sync-agents. The fix for drift is to regenerate, never to hand-patch — and that single recovery path is itself the point.
That is the point of idempotency — the fix is always the same command, because the sync is always a deterministic function of the manifests.
The section above named four adapters because four is what the system conceptually does — assemble, emit to Claude, emit to Cursor, produce docs. The registry runs six:
| Adapter | Destination |
|---|---|
prompt-assembler | <agent>/prompt.assembled.md |
claude | .claude/agents/<name>.md |
cursor | .cursor/rules/<name>.mdc |
docs-role | <agent>/role.mdx |
agent-category | <agent>/_category_.json |
docs-table | apps/docs/docs/ai/agents/agent-definitions.mdx |
agent-category and docs-table are the quiet infrastructure that makes the docs self-maintaining — every agent that gets a manifest gets a Docusaurus sidebar entry and a registry row, automatically, without a docs PR.
Scaffolding a new agent is two commands:
make agents-new NAME=<kebab-case-name># → apps/docs/docs/ai/agents/<name>/{manifest.json, prompt.md}make sync-agents# → .claude/agents/<name>.md, .cursor/rules/<name>.mdc, role.mdx, _category_.json, registry rowWrite the manifest and the prompt, run the sync, and the agent exists in every framework simultaneously.
The gate won’t pass until the sync has run — which means you cannot forget the sync and ship anyway. The broken CI is the reminder.
The next adapters extend the same registry to two more destinations: agents-md-platform.mjs (root AGENTS.md) and cursor-rules-platform.mjs (.cursor/rules/_platform.mdc). Today AGENTS.md is a pointer file, and the platform layer is where this goes next: every existing agent renders into those destinations for free — adding a new framework adapter is a new file and a registration line, not a sweep across nineteen manifests.
The velocity payoff
Section titled “The velocity payoff”The check this removes is “are all the framework copies of this role still saying the same thing?” — multiplied by nineteen agents and two skills, across two frameworks, plus docs.
Declaring the role once collapses that to a single edit. Improve a principal’s review checklist in one role-block; every principal in every framework updates, and agents-check proves they did. Onboard a new framework by writing one adapter, and every existing agent renders into it for free. Re-point a tier at a better model in one file, and the whole fleet follows.
This is the deepest expression of the economic inversion from Part 1: The Drift Problem: the contributors themselves are governed by a manifest, so improving how the whole fleet works is a one-line change with a gate behind it — not a careful, error-prone sweep across every tool’s idea of every role.
What’s next
Section titled “What’s next”We have now found the same shape governing values, models, state, operations, and agents. Part 11: The FE↔BE Mirror holds the two halves of the product up against each other — frontend and backend — and shows that even the governance itself is mirrored, with the asymmetries named honestly.