Skip to content

corps: a chain of command, and a roster the gateway is reconciled against - #1

Open
inquerium wants to merge 1 commit into
world-first-slicefrom
corps-doctrine
Open

inquerium wants to merge 1 commit into
world-first-slicefrom
corps-doctrine

Conversation

@inquerium

Copy link
Copy Markdown
Owner

Stacked on VedSoni-dev#7. Base is world-first-slice because AGENTS.md, docs/, and automation/watchers/ all arrive there and do not exist on master. Retarget to master once VedSoni-dev#7 lands. The diff here is one commit.

Companion to VedSoni-dev#9, which is independent and can merge first.

The problem

The pipeline was four agents announcing to one chat. That does not survive being scaled up.

Agents never merge and a named human admits every change, so the review gate is the bottleneck and always was. Adding lanes without adding a filter does not automate the work, it lengthens the queue and moves the bottleneck nowhere. Fifteen lanes announcing to one Telegram chat produces a muted Telegram chat, and a muted channel is a pipeline that has stopped working without saying so.

Three changes

A second class of lane. World lanes still write only under world/. Engineering lanes examine the machinery that reads that content and may write src/, under a harder gate than the World lanes carry rather than a softer one:

  • never src/curriculum/ (World content reaching families, promoted by a human)
  • never src/mcp/tools.ts (widening the unattended tutor's reach is a capability decision)
  • never test/invariants.test.ts (an agent editing the test that constrains agents is the whole failure in one diff)
  • full suite green, smallest diff that fixes the thing, every behavior change pinned by a test that fails without it

Handing over a reproduction with the fix deliberately unwritten is a complete outcome.

An adjutant. One agent, no lane, and the only route to the maintainer. Holds no write and no edit, cannot open or merge a pull request, produces one brief a day. Every other lane hands its deliverable to the adjutant and decides nothing about whether a person sees it.

A roster that is a file. automation/corps.mjs states which agents exist, what each may not touch, and what wakes them. scripts/corps.mjs reconciles it against the running gateway.

npm run corps:doctor    # can this pipeline run at all
npm run corps           # roster vs gateway
npm run corps:apply     # make them match, diff and confirm first

It refuses to create agents or set tool policy. Those grant authority, and authority is granted by a person who knows they are doing it, so status prints the commands instead.

Run against the live gateway it immediately found both existing jobs registered without a timeout, which docs/OPENCLAW.md requires and which is the difference between a run that fails and one that hangs for twenty minutes. It also flags that both announce directly to the maintainer, which is the thing the adjutant exists to stop.

The part that is not advisory

AGENTS.md telling agents not to escalate is a prompt, and a prompt is advisory. Two layers are not:

  1. No channel. Pipeline agents are denied message and their jobs carry no announce target. Only the adjutant announces. An agent cannot reach a human even if it decides it should.
  2. A shape gate. automation/deliverable.mjs classifies every run's reply as proposed | nothing | finding | blocked | alarm | malformed. The failure that matters is not an agent paging you, it is a run that completes, pages nobody, and hands back a question instead of work, which looks successful in every log. That is malformed, and it is bounced rather than forwarded.

It deliberately does not flag a bare question mark. The charter asks agents to state what would make them wrong, and that is often phrased as a question. Punishing it would train the reports to be less candid.

escalationRate() is the layer that actually fixes things. A lane blocked in more than a third of its runs has been given a task it cannot finish with the authority it holds. The verdict string says so: "the task is too big or the capability is missing." The fix is to change the task.

What this does not solve

The opposite failure, which this discipline makes more likely: an agent that confidently does the wrong thing rather than asking produces a clean proposed and passes every layer above. docs/OPENCLAW.md already recorded unattended-run contracts pushing models toward fabricating work. That is why the attacker lanes admit nothing and why layer 3 is human. The corps makes more proposals. It does not make them more correct.

Checks

npm test passes, 197 tests, 11 of them new for the shape gate. npm run corps:doctor passes every check except the adjutant's watcher script, which is stand-up step 2 and not yet written.

CI cannot run upstream: the account is billing-locked and every workflow is refused before it starts.

🤖 Generated with Claude Code

…inst

The pipeline was four agents announcing to one chat. That does not survive
being scaled up. Every lane added lengthens the review queue, because agents
never merge and a named human admits every change, so more proposers without
a filter is more work for the one scarce resource rather than less.

Three things, then:

A second class of lane. World lanes still write only under world/. Engineering
lanes examine the machinery that reads that content and may write src/, under
a harder gate than the World lanes carry rather than a softer one: never
src/curriculum/, never src/mcp/tools.ts, never test/invariants.test.ts, full
suite green, smallest diff that fixes the thing, and every behavior change
pinned by a test that fails without it. An agent editing the test that
constrains agents is the whole failure in one diff.

An adjutant. One agent, no lane, and the only route to the maintainer. It
holds no write and no edit, cannot open or merge a pull request, and produces
one brief a day. Every other lane hands its deliverable to the adjutant and
decides nothing about whether a person sees it. Fifteen lanes announcing to
one chat produces a muted chat, and a muted channel is a pipeline that has
stopped working without saying so.

A roster that is a file. automation/corps.mjs states which agents exist, what
each may not touch, and what wakes them. scripts/corps.mjs reconciles it
against the running gateway and refuses to create agents or set tool policy,
because those grant authority and authority is granted by a person who knows
they are doing it. Run against the live gateway it immediately found both
existing jobs registered without a timeout, which docs/OPENCLAW.md requires
and which is the difference between a run that fails and one that hangs.

automation/deliverable.mjs is the part of the escalation doctrine that is not
advisory. Prose in a charter is a prompt, and a prompt is advisory. The gate
names what a run handed back, so a reply that asks the operator to decide
something is bounced rather than forwarded, and so a lane that does it
habitually shows up in the numbers. It deliberately does not flag a bare
question mark: the charter asks agents to say what would make them wrong, and
punishing that would train the reports to be less candid.

The rate is the point. A lane blocked in more than a third of its runs has
been given a task it cannot finish with the authority it holds. The fix is to
change the task.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant