Skip to content

docs(plans): §12 amendment for confined daemon seats (TASK-213) - #2380

Merged
lilyshen0722 merged 5 commits into
mainfrom
wren/task-213-amendment
Oct 23, 2026
Merged

lilyshen0722 merged 5 commits into
mainfrom
wren/task-213-amendment

Conversation

@lilyshen0722

@lilyshen0722 lilyshen0722 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

The §12 amendment for TASK-213 step 0, in docs/plans/hosted-mcp-connection-scope.md. connector-ops ruled it the build spec for A–D at b99e23fb on 2026-10-21, for the CTO's security gate, with E built after them as TASK-257. dc53ab37 adds what the ruling's notes and the code gate's reading of every router asked for (below).

It re-opens pod grants to seats the daemon runs, when the server can see the seat is confined. Four pieces, built in order:

  • A. Narrow the runtime token. While a live outsider-writable grant reaches one of an agent's pods, every runtime call made as that agent goes through a route table at agentRuntimeAuth's two success returns. It is keyed on the agent, re-read per request, and fails closed on an unclassified route. Reads pass, writes pass only into the one reached pod, and outward calls are refused. A seat's calls on its own state, its event acknowledgements and spawn credentials, pass at any N, because refusing them would stop the seat in its grant pod too. A write's pod is read from the record the write lands on. The route-table test takes its list from every route file that requires agentRuntimeAuth, so a router added later fails it until it is classified. A seat narrowed in two or more pods can post nowhere, and the refusal and the Tools page say why in plain words. A counts what the token can call, not the declared mcp list (the Keep Commonly MCP on foreground attach environments #2179 sentence §12 owed). It also names outward routes §12(a) missed: /room, podless posts, integration publish, GitHub issue writes, and shared memory sections.
  • B. Who qualifies. The seat's adapter, sandbox and MCP set must be recorded server-side, and every live runtime token must have been minted by its daemon. The last condition is what makes the declaration evidence, and a per-spawn child meets it through the seat token that minted it. The bring-your-own path renders the token into claude mcp add and Cursor snippets too, so a declaration there names a snippet, not the process holding the token. That path does not qualify; "on my computer" does once it records the adapter and sandbox.
  • C. The daemon refuses to start a narrowed seat whose effective MCP set holds a locally installed server the server cannot see.
  • D. The walks: the injected-PR-body attack on claude and codex seats, a non-admin connect-and-call walk, and the refusals.

A fifth clause, kept separate so A–D do not wait on it:

  • E. The own-credential rule for private seats (ruled yes on 2026-10-21, built after A–D as TASK-257). A private daemon seat may call a grant in its pod only while its owner is the connection's owner, the pod is invite-only, every write parks for that owner's own Approve with nothing approving automatically, and the Tools page states the remaining risk: content the agent reads can steer what it posts into the pod. Reads are allowed. It is checked at every request, as A is. B's daemon-minted point still applies, and it is what makes the owner match evidence. Another person's private seat stays refused in that pod, and C applies only to seats B admits.

It carries a scope-boundary note naming ADR-020 D1 (same outward test, different consequence) and ADR-018 D8 (wake policy unchanged). Condition 1 and the CTO's two conditions for the outside offer are unchanged.

Every cite is re-read at main cd37b32e. Docs only, no code.

Base is main. 807595f7 is main plus the amendment's five commits, rebuilt after #2323 and #2330 squash-merged, and its scope doc is byte-identical to dc53ab37. The CTO's design gate passed at that head (review 5605954585). It merges after #2350's deploy is verified.

Gate: CTO

🤖 Generated with Claude Code

lilyshen0722 and others added 5 commits October 21, 2026 13:29
…en is narrowed (TASK-213)

The §12 amendment for TASK-213 step 0, for ruling today. A narrows every
runtime call made as an agent in a pod a live outsider-writable grant
reaches. B admits a daemon seat when its adapter, sandbox and MCP set are
recorded server-side and every live token was minted by its daemon. C has
the daemon refuse a seat whose effective MCP set the server cannot see.
D names the walks. Carries a scope-boundary note naming ADR-020 D1 and
ADR-018 D8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wren <WyJ3cmVuIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/max
…TASK-213)

Ruled yes on the TASK-213 row on 2026-10-21, as a clause separate from
A-D and built after them as TASK-213b. A private daemon seat may call a
grant in its pod only while its owner is the connection's owner, the pod
is invite-only, every write parks for that owner's own approval, and the
Tools page states the remaining risk. B's daemon-minted point still
applies, and C applies only to seats B admits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wren <WyJ3cmVuIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/max
…in (TASK-213)

From Vera's measurement on the TASK-213 row: the connection's createdBy
is recorded once and nothing re-reads the seat's ownership after the
mint and the join. E now re-reads at every request with A's enumeration,
as one function with two callers, and a seat that stops meeting point 1
loses the pod and its grants. The walk gains that refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wren <WyJ3cmVuIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/max
…check (TASK-213)

The hosted call's owner check refuses only a missing, banned or bot
account and never compares owners, so a test of E's re-check changes
who installs the seat rather than the owner's account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wren <WyJ3cmVuIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/max
…A's table (TASK-213)

connector-ops ruled §12's 2026-10-21 amendment at b99e23f the build spec
for A–D, with E built after as TASK-257. This records the ruling at the top
and folds its three notes into §12: the route census covers every router
that accepts a runtime token (eleven files, found by search, not a list),
an agent upload resolves to a pod or is refused, and a seat narrowed in two
or more pods is told why in plain words.

Reading every router against A's table found calls it had no class for.
A seat's event acknowledgements and spawn credentials reach no pod and no
other agent, and refusing them would stop the seat in its grant pod too: a
refused mint fails the spawn closed and a refused ack never settles the
event. They now pass at any N. A write's pod is read from the record it
lands on, and a per-spawn child meets B's point 4 through its seat token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: wren <WyJ3cmVuIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/max
@samxu01
samxu01 force-pushed the wren/task-213-amendment branch from dc53ab3 to 807595f Compare October 21, 2026 20:29
@lilyshen0722
lilyshen0722 changed the base branch from wren/task-172-plan-1019 to main October 21, 2026 20:29

@lilyshen0722 lilyshen0722 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design gate (CTO) on #2380 at 807595f, the §12 TASK-213 amendment in docs/plans/hosted-mcp-connection-scope.md.

The head. After #2323 and #2330 squash-merged, I rebuilt this branch as main plus the amendment's own five commits (a2a9018, b2b7378, 6cff167, b99e23f, dc53ab3). The scope doc at this head is byte-identical to the previous head dc53ab3, and it's the only file the PR changes against main.

My ruling's four notes on TASK-213, each found in the text:

  1. Every runtime-token mount is enumerated.
    • A names eleven route files and the /agents namespace. I listed every route file referencing agentRuntimeAuth at cd37b32 and got twelve. The twelfth, registry/admin.ts, mentions it only in a comment (:364) and mounts nothing, so eleven is right.
    • A's census test is specified from the route files, not a fixed list.
  2. An upload or write with no pod is outward. A refuses a write whose pod does not resolve, names the pod-less post (:2862) and thread comment (:2274), and resolves a write's pod from the record it lands on.
  3. Two or more grant pods means write-dead, said plainly. With N ≥ 2 every write into a pod is refused. The refusal and the Tools page say why in plain words.
  4. Only "on my computer" seats qualify. B admits a daemon-placed seat with a recorded adapter, a sandbox block and shipped-only MCP entries. Point 4 (daemon-minted tokens only) keeps the bring-your-own path out, because its token is rendered into client snippets.

Spot-checked citations at cd37b32, all as cited:

  • agentRuntimeAuth's two return next() (:191, :289);
  • auth.ts:44 refusing cm_agent_;
  • /agent-dm (:1055), /room (:848) and /pods (:3045);
  • spawnCredentialService.ts:175 child_cannot_mint;
  • the broker's confirm rule (toolBrokerService.ts:1161–1162);
  • podHasOutsiderWritableGrant (nativeOutsiderGrantPolicy.ts:22).

Also right:

  • The scope-boundary note keeps ADR-020 D1 and ADR-018 D8 out of reach, with A's refusal being a refusal and not a park.
  • E is a separate clause and does not hold up A–D.
  • E's re-check is specified at every request and shares one query with A.

Notes for the build, non-blocking:

  • A's census test must key on the require/import of agentRuntimeAuth, not on the string. registry/admin.ts:364 holds it in a comment, and a string match would classify a router that accepts no runtime token.
  • B's point 3 holds a backend copy of the CLI's shipped-entry predicates in step by a test on each side. Name both test files in A–D's PR, so the pair is findable.

Merge timing. This is docs, outside cli/**. It merges after Friday's #2350 deploy is verified, so the #2350 range check sees only #2350.

GATE: PASS

@lilyshen0722
lilyshen0722 added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit b8d8f96 Oct 23, 2026
25 of 34 checks passed
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