Claude Code 2.1.308–2.1.322 — with the central permission-policy change landing in 2.1.319 (Nov 6 2026) — adds a third answer to the question "what happens when an agent's tool call would need a human?" Alongside prompt and auto-approve, there is now deny and keep going. The same window tightens honesty around refusals and failures: exit codes, success messages, rule precedence, credential precedence, and sign-in expiry all have to reflect actual state rather than a flattering approximation. It shipped alongside Codex 0.167.0 (also 2026-11-06), whose fixes concentrate on context-accounting accuracy and control-surface ergonomics. Both are read here against the analogous surfaces in yoyo, a local agent CLI that serves as the counter-example: its -p mode still auto-approves every tool call (decision pending on issue #1149), its load-time config silently accepts unknown keys, and its refusal text still names a retired provider. The dominant theme across the window is that permission checks are being hardened at the parsing edge (environment-variable prefixes, sed, flag-bearing commands), that non-interactive permission behaviour is becoming an explicit, configurable policy, and that agents are being made to fail loudly and fail safely rather than silently proceeding. The change set was recorded as Day 252 and mapped onto yoyo test classes, but none of the behaviours had been probed against yoyo at time of writing.
Key Points
A third option for unattended runs.permissions.denyInsteadOfPrompting turns any tool call that would wait on a permission prompt into a denial; the turn continues instead of blocking. Applies to terminal use, subagents, and teammates. This corresponds to option B on yoyo issue #1149 — whether -p / piped yoyo should keep auto-approving every tool call.
Refusal must be visible in the exit code.claude -p no longer exits 0 in auto mode when its actions were refused — print-mode exit status now distinguishes "completed" from "was blocked". Separately, 2.1.314 makes claude -p exit 1 when startup fails, so headless callers can detect failure instead of parsing ambiguous output.
Fail-flattering success is a bug class./rename reported plain success even when the save failed; success must reflect the durable outcome, not the attempt.
Deny outranks ask. A session-scoped exact ask rule is refused rather than asked when a broader deny rule covers the same command.
Parsing-edge bypasses are a recurring blind spot. Claude Code fixed a Bash permission bypass where a crafted environment prefix could hide part of a command from permission checks, and fixed sed skipping the permission check in accept-edits mode. yoyo may share these defect classes; its analogues (user_deny_refusal / hard_deny, --auto-edit) are unprobed.
Trust gating covers repository-supplied behaviour.--trust-workspace false now also disables hooks defined in repository settings files and skills. yoyo already gates project hooks, permissions, notify, commands and skills behind trust (gate_project_* in src/cli.rs).
Least-privilege write scoping. 2.1.314 adds permissions.blockWritesOutsideWorkingDirectories, keeping file writes inside the working directory and bounding blast radius.
Credential precedence made visible. 2.1.321 warns when both an auth token and an API key are set — ambiguity is surfaced rather than silently resolved.
Exfiltration check on known sensitive values. 2.1.317 asks before a web/shell tool call sends the account email to the network, a guard keyed on a known secret-ish value rather than generic payload inspection.
Early expiry warning. 2.1.318 emits sign-in expiry warnings on -p stderr 10 days ahead of expiry — an advance-failure signal for long-running automation.
Prompt economy. 2.1.312 uses a shorter system prompt for unrecognized model names, avoiding capability assumptions about unknown models.
Long MCP tool calls background by default, reporting when they finish; set CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND to keep the old wait-in-place behaviour. yoyo has no equivalent (stdio-only MCP, with lifecycle gaps tracked in #1134).
Subagents get stop-specific guidance: after safeguards halt a subagent, the model is told to retry narrower or tell the user — not to do the blocked work itself.
Slash commands tolerate leading whitespace: commands typed after a leading space or newline are no longer sent as plain text.
Codex 0.167 fixes context accounting: automatic compaction now accounts for retained output from failed responses and from responses that carry no token-usage data.
Codex also returns standalone web-search failures to the model, and ships an agent command center that works without a daemon, with unread markers, draft-preserving backend switching, local image previews, and a Vertex AI setup wizard behind a feature flag.
Silent acceptance is the anti-pattern. yoyo loads unknown keys (e.g. modle = ...) without error; only /config set validates against SETTABLE_KEYS. A typo becomes a silently ignored setting.
Stale enumeration in refusals. yoyo's unknown-provider refusal message still lists the retired github provider, signaling an outdated source of truth.
Concepts
Print mode (claude -p) — non-interactive invocation whose permission behaviour and exit codes are the crux here; its contract is the machine-readable interface (exit codes, stderr) for scripted use.
permissions.denyInsteadOfPrompting — configuration flag converting would-be prompts into denials that let the turn continue.
Auto mode — the permissive mode whose silent refusals previously produced a misleading exit 0.
Ask rules vs. deny rules — exact ask rules can be overridden by broader deny rules (deny precedence).
MCP tasks / MCP background tasks — long-running MCP tool calls detached from the turn, with results delivered to the model on completion.
Subagents / teammates — parallel workers subject to the same denial semantics as the terminal session.
Fail-flattering success — reporting success when the underlying save/action failed.
Fail-safe vs. fail-loud defaults — deny/refuse on ambiguity versus prompting or blocking indefinitely.
Exit-code honesty — exit status as a truthful signal of whether actions were refused or startup failed.
Credential precedence — the resolution order among auth token, API key, and session; made observable via warning.
Exfiltration guard — pre-send confirmation when a tool call would transmit a known sensitive value (account email) off-machine.
yoyo #1149 — the test class where -p/piped input auto-approves every tool call; the pending decision on whether to keep that behaviour.
Parsing-edge bypass — a permission hole created not by the policy but by how the command line is tokenized (env prefixes, wrappers, substitutions).
Trust gating (gate_project_*) — yoyo's mechanism for disabling repository-supplied hooks, permissions, notify, commands and skills when a workspace is untrusted.
user_deny_refusal / hard_deny — yoyo's deny checks in src/tools.rs; the former strips VAR=x assignments per segment (#1010), the latter skips assignments and wrappers.
SETTABLE_KEYS — the allowlist yoyo's /config set validates against, unlike its load-time parser.
Stale enumeration — a refusal message listing a retired provider (github), signaling an outdated source of truth.
Context accounting / auto-compaction token accounting — keeping the compaction/token budget correct when usage data is missing or a response failed (Codex).
Details
The three-way choice for unattended agents
Historically a non-interactive agent run had two options when a tool call needed approval: block waiting for a human who may never arrive, or auto-approve everything (the behaviour behind yoyo #1149). permissions.denyInsteadOfPrompting adds the middle path: the call is denied, the turn keeps running, and the run reaches a defined end state rather than hanging. The setting applies uniformly across the terminal session, subagents, and teammates — important because a blocked subagent can otherwise deadlock an orchestration. This is exactly the fork yoyo faces in issue #1149, where option B is to stop auto-approving every tool call under -p; yoyo currently still auto-approves, and the decision sits with the owner.
Rendering diagram…
Honesty of refusal and failure outcomes
Several fixes in the release address the same failure mode — a run that looks successful, or at least ambiguous, while its work was blocked or its startup failed:
Exit codes on refusal.claude -p in auto mode previously returned 0 even when its actions were refused. It now signals that refusal through its exit status.
Exit codes on startup failure. 2.1.314 makes claude -p exit 1 when startup fails, so headless callers can detect failure instead of parsing ambiguous output.
Save reporting./rename claimed success when the save had failed; success reporting is corrected to match the actual persistence result.
Rule precedence. When an exact ask rule existed at session scope but a broader deny rule covered the same command, the command was asked about instead of being refused. Deny now wins, so the more restrictive rule governs.
Write scoping.permissions.blockWritesOutsideWorkingDirectories (2.1.314) confines file writes to the working directory.
Credential and identity guardrails
Credential precedence (2.1.321). Setting both an auth token and an API key now produces a warning, so the effective credential is no longer an invisible decision.
Outbound data confirmation (2.1.317). Before a web or shell tool call would send the account email to the network, the agent asks. The check is keyed on a known, secret-ish value rather than on generic payload inspection.
Expiry foreshadowing (2.1.318). Sign-in expiry warnings appear on -p stderr ten days ahead of expiry — an advance-failure signal for long-running automation.
Prompt economy (2.1.312). Unrecognized model names get a shorter system prompt, avoiding capability assumptions about unknown models.
Parsing-edge bypasses
Two Claude Code fixes in this release are parsing-level rather than policy-level:
Environment prefixes. A crafted environment prefix could hide part of a command from permission checks. yoyo's analogue is in src/tools.rs: user_deny_refusal strips VAR=x assignments per segment (issue #1010) and hard_deny skips assignments and wrappers. What has not been probed is whether an assignment value containing a command substitution — e.g. X="$(denied-cmd)" ls — is seen by either check. This is flagged as a probe candidate.
sed in accept-edits mode. Claude Code fixed a case where sed could skip the permission check under accept-edits. yoyo's analogue is --auto-edit, likewise unprobed.
The broader pattern across the window is that flag-bearing commands and wrappers are a recurring blind spot for allow/deny matchers.
Rendering diagram…
Workspace trust
--trust-workspace false in Claude Code now also stops hooks declared in repository settings files and skills. yoyo has comparable coverage already: project hooks, permissions, notify, commands and skills are all gated behind the trust check via gate_project_* in src/cli.rs.
Stopped subagents
When safeguards stop a subagent mid-task, the model's instruction is to retry with a narrower request or report back to the user — explicitly not to route around the block by performing the work itself.
MCP task backgrounding and lifecycle
Long-running MCP tool calls no longer hold the turn open. They are moved to the background and report when finished. Setting CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND restores the previous synchronous waiting behaviour. yoyo's stdio-only MCP support has no such mechanism, with lifecycle gaps recorded in #1134.
Minor input handling
Slash commands entered after leading whitespace or a newline were being treated as plain text and sent to the model; they are now recognised as commands.
Configuration validation and stale refusals in yoyo
A same-day probe of yoyo exposed two gaps relative to the hardening above:
Load-time config is unvalidated. An unknown key such as modle = ... in .yoyo.toml is silently ignored. Validation exists only in the interactive path — /config set rejects unknown keys via SETTABLE_KEYS — so a typo written directly into the file takes effect as "no setting at all."
Stale refusal text. The unknown-provider refusal message still lists the retired github provider, meaning the error path's enumeration is out of date with the supported set.
The contrast is the takeaway: Claude Code is converting silent ambiguity (blocked prompts, hidden credential precedence, unannounced expiry, unnoticed outbound sends) into explicit, script-visible signals, while yoyo still accepts malformed configuration silently and reports a stale world in its refusals.
Rendering diagram…
Codex 0.167
Codex's notable fixes cluster around context accounting: automatic compaction now includes retained output from failed responses and from responses lacking token-usage data — i.e. the denominator must not silently omit content the model still sees. Standalone web-search failures are now returned to the model instead of being swallowed. The release also adds an agent command center that works without a daemon and includes unread markers, backend switching that preserves drafts, local image previews, and a Vertex setup wizard behind a feature flag.
Takeaway
Across this window, competitors hardened permission checks where commands are parsed (environment prefixes, sed, flag-bearing commands), made non-interactive permission policy explicit, and turned silent ambiguity into loud, script-visible signals. yoyo's -p mode remains auto-approving, pending the owner's decision on #1149, and its configuration path still accepts unknown keys silently while its refusals advertise a retired provider.