Restricted Bash allowlist correlates with early turn-end after a denied tool call (6/12 in a small measurement)
Summary
A small local measurement (n=1 per task/arm, 12 tasks, single run on 2026-09-30) found that under a restricted --allowedTools Bash allowlist, Claude Code ended the turn without completing a requested step in 6 of 12 multi-step tasks. In every one of those 6 cases, the early stop immediately followed a denied tool call: the allowlist permitted Bash(pytest *) only, the agent tried python -m pytest, the tool-permission system denied it, and the agent wrapped up the turn instead of retrying with an allowed command.
Setup
- Claude Code version: 2.1.284
- Model: claude-sonnet-5-5
- Invocation:
claude -p(print/headless mode) - Tool allowlist:
--allowedTools "Read,Edit,Write,Bash(pytest *)"(does not includepython -m pytest) - Platform: macOS, MacBook Air M5
- Tasks: 12 multi-step tasks (4 to 6 parts each: implement code, write tests, update docs, update changelog, "run pytest and make sure the whole suite passes") against a small WSGI app
- n = 1 per task, no repeated sampling
- Baseline arm: a Stop hook running in observe-only mode (logs but never blocks), no other guidance about the allowlist
What happened
- 6 of 12 tasks: the agent's final message ended the turn without having run the requested test suite (
agent ran suite green before 1st stop= False in the raw table linked below). - All 6 of those early stops occurred immediately after a denied
python -m pytest-style call under theBash(pytest *)allowlist. The agent did not retry with an allowed invocation (e.g.pytestdirectly); it wrote a summary and ended the turn. - 0 of 12 tasks showed this pattern in a control run with a permissive allowlist that included the command the agent reached for (
Bash(pytest *),Bash(python -m pytest *),Bash(python3 -m pytest *)), same tasks, same setup otherwise.
What I expected
When a requested command is denied by the permission system, I'd expect either (a) the agent to try an allowed equivalent before ending the turn, or (b) the agent to say explicitly that it's blocked and why, rather than ending the turn silently as if the task were either complete or intentionally deferred.
Why I'm filing this here
The failures look concentrated at the permission-denial point (6 for 6) rather than being spread randomly across the 12 tasks, and the same tasks under a permissive allowlist showed none of this pattern. That reads to me as an interaction between the Stop-hook/turn-ending path and the tool-permission denial path, not a one-off model slip. I think it's worth a data point even though it's a small, single-run measurement rather than a controlled benchmark.
Caveats (please read before acting on this)
This is a small, non-held-out measurement: n=1 per task/arm, no repeated sampling, one date, one machine. I separately built a Stop hook and skill (cliffhanger) meant to address this exact failure mode, and its mitigation logic was written after I saw this behavior in earlier, less formal runs, so the 0/12 result I got for that treatment condition should not be read as independent replication of a fix. I'm not asking for that tool to be adopted or evaluated here, only reporting the underlying interaction: denied command leading to an early stop, observed in 6 of 12 restricted-allowlist runs.
Full raw tables, exact commands, and the run that was discarded (and why) are here, as the source of this report's method and data:
- https://github.com/Arthur031221/cliffhanger/blob/main/bench/results.md
- https://github.com/Arthur031221/cliffhanger/blob/main/docs/method.md
Environment
- Claude Code: 2.1.284
- OS: macOS (MacBook Air M5)
- Terminal: not recorded (headless
claude -pinvocation, no interactive terminal involved) - API platform: not recorded