Skip to content

Act on the P2–P6 findings: make the channel out real, and the verbs findable #343

Description

@bdelanghe

Three fixes, all in .claude/, all derived from the posture matrix measured on #337. Grouped because they are one unit of work — "a session can report, and can find the verbs" — and because each separately would cost its own pin ceremony.

1. The channel out is classifier-gated, and boot.sh clobbers the file that could fix it

infra#577 shipped a credential-free, connector-free report route. P4 still could not reach it — the auto-mode classifier blocked curl before it ran, twice, deterministically. In P4's words:

the routine picked curl specifically to avoid needing an MCP tool: the gate is in front of Bash egress, so that choice does not avoid it.

So "a checkout-less session has a channel out" is conditional, and no change to the door can make it otherwise — the gate is upstream of the network.

The org already has the mechanism. .claude/settings.json carries:

"permissions": { "allow": ["Bash(bash .claude/org-repair.sh)"] }

That is exactly how org-repair.sh is pre-approved past the classifier. The same shape, narrowed to the door endpoint, makes the report channel reliably reachable.

But boot.sh:161 writes $CFG/settings.json with cat > — it clobbers, and writes only a hooks block. So today it would erase any allowlist (and any user setting) on every bare boot. Two consequences:

  • the allowlist cannot be installed until the write merges instead of overwriting
  • this is already a live bug independent of this issue: a session's own ~/.claude/settings.json is destroyed at boot

Scope: make the write merge-preserving, and add a narrow allow entry for the pathbase-door report endpoint. Narrow is load-bearing — Bash(curl:*) is a blanket egress grant and a different security posture; it must not ride in on this.

2. read_session returns the PARENT's transcript inside a subagent

Measured by P5. read_session with no arguments returned the parent session's 453 turns and none of the subagent's own. Its words:

a subagent that trusts read_session will silently read its parent's history believing it is its own.

verb-server.mjs resolves through $CLAUDE_CODE_SESSION_ID, which in a subagent is the parent's. It returns plausible, wrong data with no error — the worst failure class in the set, because nothing signals it.

Scope: name whose transcript came back, and give the caller a way to ask for its own versus the parent's. Silent is the defect; either answer is fine once it is stated.

3. The verb names in our own docs do not resolve

Measured by P3, and independently by P4 and P5:

ToolSearch select:read_session,read_chat returned 'No matching deferred tools found' — the real names are prefixed mcp__bounded-verbs__, so even the exact-name select missed on the bare names.

claude/context.md and #326's framing both name the verbs bare. A session that has been told the name still cannot find the tool. That is precisely the trap #325/#326 exist to prevent, reintroduced by the documentation rather than the mechanism.

Scope: use the prefixed names wherever a session is told what to look for. One-line class of change; the highest value-per-byte fix in this issue.

What this does NOT fix

Cost, stated up front

Fixes 1 and 2 touch files inside the pinned bootstrap payload, so this needs the pin ceremony and a payload publish before it takes effect for any new session. Fix 3 is repo content and takes effect on merge.

Measured on #337 (P2–P6). Related: #325, #326, #339 (whose causal claim these runs refute), #342, .github-private#514, .github-private#848.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions