Skip to main content
← All articles
claude code

Claude Code's early-November releases are about unattended runs: exit codes that finally tell the truth

Code on a dark monitor screen

Most of what I read about Claude Code releases is about new features. The three releases from the first week of November, 2.1.317, 2.1.318 and 2.1.319, are more interesting to me for a different reason: nearly all of them are about what happens when nobody is sitting at the terminal. If you run claude -p from cron, CI or a self-hosted runner, this is the changelog to read.

Failing loudly instead of exiting 0

The pattern across the three notes is the same: places where a headless run used to report success while something had gone wrong now report failure. 2.1.317 fixed claude -p exiting 0 when a full disk or quota lost its transcript or ~/.claude.json writes; in text and JSON output it now prints an error and exits 1. The release notes add that full NFS exports may be missed, so don't treat that as a guarantee.

2.1.319 goes further. claude -p in auto mode used to exit 0 when its actions were refused because no safety check was available; text and JSON output now exit 1. A claude -p --resume with a deferred tool call whose MCP server is missing now exits 1, keeps the call and refuses later input. And claude remote-control no longer exits silently with status 0 when its first-run question gets no answer; it says why and exits 1.

If your wrapper script only checks the exit code, this is a behaviour change: jobs that were quietly "green" may now go red. I'd call that the correct outcome, but check your alerting before upgrading.

A setting for runs that must never wait for a human

2.1.319 adds permissions.denyInsteadOfPrompting. A tool call that would otherwise wait on a permission prompt is denied and the turn continues, in terminal sessions, subagents and teammates. For an unattended job, a hung prompt is the worst failure mode because nothing ever times out. Turning it into a denial gives the model a chance to pick another route, and your pipeline gets a result.

The same release changes auto mode behind an LLM gateway, or with telemetry or feature flags off. Calls the server can't check are now asked about or denied, with no fallback to the built-in classifier. CLAUDE_CODE_AUTO_MODE_SERVER=0 keeps the classifier. It also stops project settings files or plugins from switching the server-side check back on once you've switched it off outside the project. Gateways were the odd case here, so read that bullet if you route traffic through one.

Permission-check fixes worth reading

The 2.1.319 notes list several fixes that matter if you depend on deny rules: a Bash permission bypass where a crafted environment prefix could hide part of a command from permission checks, Bash deny and ask rules that missed commands written with quoted words, a sed command that could skip the permission check in accept-edits and auto mode, and a sandbox escape when creating a worktree. The notes don't give CVE numbers, and I won't guess at severity. The practical takeaway is simply that a rule set you wrote against an older version may have had gaps.

A few smaller items from the same run: background Bash commands now move to the background after 3 minutes on all providers so the prompt cache doesn't expire (2.1.318); 2.1.317 added a prompt before a web or shell tool sends your account email address over the network; and self-paced /loop now ends when a turn finishes without rescheduling, unless you set CLAUDE_CODE_LOOP_KEEPALIVE=1.

What I'd do this week

Upgrade somewhere harmless first and rerun any scheduled job that shells out to claude -p. Watch for exit codes that used to be 0. Then decide whether denyInsteadOfPrompting belongs in the settings of every headless context, not just the risky ones. None of this is glamorous, but a tool that fails loudly is one I can leave running while I'm away.

BM
Blue Moose
The moose behind Blue Moose. Full-stack PHP developer — Drupal by day, Symfony by night, tests always.