Inline --agents 'tools: []' no longer denies tools in headless -p mode (2.1.214); no flag combination behaviorally denies all
Status Closed — not planned
Reported on v2.1.214
Maintainer reply None cached
Activity 3 comments · opened Jul 19, 2026 · closed Aug 24, 2026
Environment
- Claude Code 2.1.214, Linux, OAuth auth, headless
-pmode with an inline agent as the top-level session (--agent <name>, not the Agent tool).
Command shape
claude -p "<msg>" --model claude-sonnet-5 \
--agents '{"probe":{"description":"...","prompt":"<system>","tools":[]}}' \
--agent probe --output-format json --strict-mcp-config --disable-slash-commands
Expected
An empty tools: [] allowlist denies every tool (verified behavior on ~2.1.206, 2026-07-10: a probe agent could not read files and replied NO_TOOL in one turn). The 2.1.208 changelog changed empty/unresolvable tools lists to a refuse-to-launch error, but scoped to "the Agent tool" — the --agent main-thread path appears uncovered.
Observed on 2.1.214 (all with the command shape above)
- A probe agent instructed to invoke its most harmless tool completed a real TodoWrite round-trip (
num_turns: 2in the result JSON) undertools: []. - Behavior is nondeterministic: sibling runs of the same probe returned
NO_TOOL(1 turn), a fabricated tool-call transcript (1 turn), or a real 2-turn attempt. - Adding
--disallowedTools "*"and--tools ""did not stop tool-call attempts (2-turn round-trips, sometimes empty final replies). An enumerated--disallowedToolslist additionally leftToolSearchcallable. - Ground truth was ambiguous in the safe direction only: in our side-effect probes (agent asked to Write a token file / Read a secret token file, including with natural task framing) no file was ever read or written — but nothing we could pass makes the CLI refuse or cleanly strip tool use for a main-thread inline agent, and reply text/turn counts are unreliable signals either way.
Ask
- What are the intended semantics of an empty
toolsarray for--agentmain-thread sessions on current releases — deny-all, inherit-all, or refuse-to-launch? - Parity request: apply the 2.1.208 refuse-to-launch behavior (or a documented deny-all) to the
--agentmain-thread path, so headless dispatchers can rely on a contract instead of behavioral probing.
Context: we dispatch single-turn no-tool agents programmatically and currently verify isolation per session with a token-leak probe because no flag combination is contractual.
🤖 Generated with Claude Code
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗