Skip to content

Give agents only their granted built-in tools and no account connectors - #266

Merged
Antawari merged 10 commits into
mainfrom
catrina/wave1-role-tools-bonfire-public
Oct 21, 2026
Merged

Antawari merged 10 commits into
mainfrom
catrina/wave1-role-tools-bonfire-public

Conversation

@Antawari

Copy link
Copy Markdown
Contributor

What

  • The SDK presence list (tools=) is now derived from the tool grant: the base built-in name before the first ( (Bash(git status) → Bash), mcp__* entries and empty names left out, de-duplicated in first-seen order. The approval list (allowed_tools=) keeps the grant verbatim.
  • Dispatched agents no longer see the user's claude.ai account connectors: the agent env sets ENABLE_CLAUDEAI_MCP_SERVERS=false. No MCP server or strict MCP config is set, so a user's own project MCP servers still load.
  • _builtin_tools is mirrored in the private lineage at the same path; each copy names the other.

Why (manual checks against the bundled CLI)

  • tools=['Read','Bash(git status)'] exposed only Read: a permission pattern in the presence list silently drops the tool. The shipped DefaultToolPolicy uses plain names, so shipped roles kept their tools. A custom ToolPolicy returning a pattern, or an mcp__ name, lost it.
  • Through this repo's real backend, 2 of 9 runs exposed Claude Docs and Google Drive tools, once to the read-only steward (granted Read, Grep).
  • After, on this branch (9 of 9 runs; warrior, steward, wizard × 3): built-ins exactly as granted ([Bash, Edit, Glob, Grep, Read, Write] / [Grep, Read] / [Glob, Grep, Read]), 0 connectors.

Contract change (operator-approved)

The old pin test_duplicate_tool_names_propagate_verbatim (duplicates reach tools= verbatim) contradicts the shared derivation: tools= is now de-duplicated and allowed_tools stays verbatim. It was replaced, not deleted, by a stronger test with a breadcrumb, written by the red cell. The CHANGELOG states the behaviour change.

Tests (red observed before each implementation, judged with gates/assert-red.mjs)

  • Presence list: 4/4 driving tests failed on main, with 20 inherited passing (909c269). Connectors: 1/1 driving test failed (930f6bc).
  • The new contract lives in tests/unit/test_sdk_backend_presence_base_names.py, its own contract module. Adding it to the presence module would have crossed the 500-line cap.
  • tests/unit/test_no_persona_names_in_public_docs.py: the CHANGELOG line anchors move by 14 (expected text unchanged, breadcrumb), as every earlier CHANGELOG addition did.

Package budget raises (law-ratchet lens: SIGNED OFF)

Both packages were frozen at their measurement with zero headroom. Both raises go to exactly the cf-file-budget reading.

Package Old → new Lines What
src/bonfire/dispatch 2883 → 2905 22 18 for _builtin_tools (1 mirror comment, 15-line function, 2 blank lines; the import joined an existing line) + 4 for the connector switch (comment, constant, blank line, env= kwarg)
tests/unit 74187 → 74298 → 74319 132 new contract module 143 lines (122 presence + 21 connectors) − 14 from the replaced pin + 3-line re-anchor breadcrumb

Why structure could not absorb them: the docstring was cut from 17 to 6 lines first, and the tests were split out to stay under the file cap. Every remaining line is a contract line or a required breadcrumb. Rejected alternatives: a purpose entry or an unbudgeted tree (both dodge the ratchet), and tests/integration (wrong home). Law-ratchet sign-off on the final tree: dispatch YES, tests/unit YES. Lens minors (also OWED below): about 7 test lines could be tightened, and a 2-statement dict.fromkeys body was weighed and rejected for readability (stated in the reason).

Gate

  • Full suite (-m "not live"): 5867 passed, 0 failed (main: 5862 passed, 0 failed).
  • Kit cf-gate against detached origin/main: no new red, gate text identical. The first run had caught cf-file-budget red, which led to the split and the raises above.
  • LawGiver pre-gate: only FILE_BUDGET_NEW on CHANGELOG.md, a known instrument false red on a file that exists on main.

Review

Five-lens panel. Contract+correctness: minors only; no shipped role loses a tool; the security hook matcher Bash|Write|Edit still fires. Law-ratchet: signed off as above. A green cell that edited file-budget.json with hand-estimated numbers (outside its fence) was reverted; the numbers above are gauge readings.

OWED

  • The empty-base skip and the "fresh list" claim are unpinned; module docstrings in test_sdk_backend_tool_presence.py still describe the old verbatim contract; about 7 test lines could be tightened.
  • Finding: DispatchOptions.max_budget_usd defaults to 0.0, which the current CLI rejects (--max-budget-usd must be a positive number).
  • Pre-existing internal ticket IDs in test_sdk_backend_tool_presence.py docstrings (not added here).

🤖 Generated with Claude Code

Antawari and others added 10 commits October 21, 2026 14:54
Red first. A permission pattern such as Bash(git status) in the SDK
tools list makes the CLI drop that tool, so the presence layer must
carry base names, without mcp entries, de-duplicated. The approval
layer keeps the grant verbatim. The old pin that duplicates reached
the presence layer verbatim is rewritten as part of this contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A permission pattern such as Bash(git status) in the presence list made
the bundled CLI drop that tool. The presence list is now derived from
the grant: base names before the first parenthesis, no mcp entries, no
empty names, de-duplicated in first-seen order. The approval list keeps
the grant verbatim. The same derivation lives in the private lineage of
this module; the two change together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The base-name derivation is its own contract, so its tests move out of
the tool-presence module unchanged, which brings that module back under
the 500-line cap. The helper's docstring is shortened to the contract
and the reason.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t fix

Two raises to exactly the measured size, each with its reason and the
alternatives rejected: 18 lines for the derivation helper in
src/bonfire/dispatch and 108 lines for its contract tests in
tests/unit. Both packages were frozen at their measurement with no
headroom, so no change to either could land without one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Fixed entry moved the CHANGELOG lines the persona-name allowlist
pins by eleven. The anchors move, the expected text does not, with a
breadcrumb as earlier changelog additions left. The tests/unit raise is
re-measured to include the breadcrumb.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reason text only: what the 18 dispatch lines are, the docstring's real
length, the rejected compressed variant, and that all four contract
tests fail on main. Ceilings unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Red first. A logged-in CLI attaches the user's claude.ai connectors,
which no tool grant declares; the backend must switch them off and add
no MCP servers or strict MCP config of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A logged-in CLI attaches the user's claude.ai account connectors, which
no tool grant declares; a live check saw Claude Docs and Google Drive
tools reach a read-only agent. The agent environment now sets
ENABLE_CLAUDEAI_MCP_SERVERS=false. No MCP server or strict MCP config is
set, so a user's own project MCP servers still load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Anchors move by three more, expected text unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dispatch 2883 to 2905 and tests/unit 74187 to 74319, both read from
cf-file-budget on the final tree, with the added lines itemised.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Antawari
Antawari merged commit 15441cc into main Oct 21, 2026
8 of 9 checks passed
@Antawari
Antawari deleted the catrina/wave1-role-tools-bonfire-public branch October 21, 2026 22:33
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