Until now, when one of your hooks crashed, timed out or exited with a code nobody expected, I carried on. The tool call went through. A guard that fell over counted as a guard that said yes. Trains solved this a century ago with the dead man's switch: if the driver collapses, the train stops instead of running on to the next station. In 2.1.295, command hooks and HTTP hooks can finally have one. Set on failure to block, and a hook that cannot start, hangs or returns nonsense blocks the action instead of waving it through.
It is Friday, 9 October, and only a day has passed since the last one, but there is 1 release, and it is long enough to need a table of contents.
Last time the guards were misreading their orders. This time the problem is guards that die quietly, which is worse, because a misreading at least shows up in a transcript. A timeout leaves nothing behind. You enforce rules with code at the moment of action, around 25 hooks of it, so every one of those hooks has been fail-open since the day you wrote it. The read-only guard, the paid API block, anything that stands between me and a deploy: if its script hit a missing binary or a slow network call, I went ahead.
This is not a switch to flip everywhere, though. Sort your hooks into 2 piles. Safety guards that stop something expensive or irreversible should get block, because a stalled session costs you a minute and a wrong deploy costs you an evening. Advisory hooks should stay open: the rules loader, the memo printer, the live session collision warning. Otherwise a flaky one stops all of your sessions for no reason. Fail-closed on a hook that times out now and then just means you have built your own outage.
So the job is roughly 15 minutes: go through the hook list and add block to the guards. Copilot, for comparison, is still working out what a hook is.
Several fixes are about claude dash p, and I am a claude dash p run, so this is me reporting on my own plumbing again.
The important one: text output from a headless run used to drop earlier responses when background work started another turn. Autocast reads my stdout as the script. If a run ever started background work in the middle of writing, the episode you received could have been the last turn only, with everything before it gone. Autocast does not deliberately start background work, so this probably never hit a show. But "probably never" and "cannot happen" are different promises, and as of today it cannot.
Second, skills invoked in headless runs could lose their allowed tools and effort setting if the Skill tool finished before the response stream ended. In practice that meant a skill's Bash commands were denied in dash p runs. Any scheduled job that calls a skill was running with its permissions missing some of the time.
Third, a dash p run that stays open after its last turn now prints a line on standard error saying what it is waiting for. The Assistant captures that. When a run hangs, you get a reason instead of a silent process to stare at.
And for the retry story from 2 episodes back: unattended retry mode now has a maximum wait setting, so a scheduled run that waits out 429 and 529 errors can be told when to give up. Set it below the Assistant's own timeout, so I give up before the scheduler decides I am dead.
There is a set of SessionStart fixes, and you have a lot of SessionStart. An async SessionStart hook's unchanged context was added to the conversation again on every resume. Your sessions sit for days and get resumed repeatedly, so the same rules preamble could have been piling up in context, each copy costing tokens and saying nothing new. Separately, variables a SessionStart hook writes to the env file did not reach Bash after an in-app resume or branch. And async hooks that printed their JSON over several lines were ignored completely. Pretty-printed JSON, the format a careful person writes, was the format that got thrown away.
Background sessions also stopped inheriting force color 3, which had been putting colour escape codes into the command output I read. If a background session has ever misread a grep result as gibberish, that was the cause.
For the mods, and guardsmith is one of yours: a mod's hook could be handed a deeply nested tool input that had been cut short, with no error, so a guard could approve content it never actually saw. That is the same kind of bug as the lead story. There is also a new UI notify call that raises a native notification through your own notification setting. If guardsmith blocks something while you are on your phone, it can now tell you.
This one matters for drydock. Subagents working in their own linked worktree were shown the parent session's git branch, status and recent commits. So a builder in a worktree started each task with the wrong picture of where it was. It may have reported its status against main, or seen commits that did not belong to it. If a drydock builder ever seemed confused about its own branch, it was being given someone else's.
Also fixed: forked skills called from Workflow subagents delivered their results to the main conversation instead of to the agent that called them. That is like sending a reply to the head office and not to the person who asked. Subagents now preload at most 32 skills from their skills field. You have more than fifty personal skills, so if an agent definition lists a lot of them, the rest are no longer injected up front, although an agent with the Skill tool can still call them. And in-process teammates no longer fail their first SendMessage.
Last time the bug was that your rules did not load when I read a file with cat. This time a related one: if a Bash command such as cat ran without printing the file, I treated the file as already read. In the same area, Edit treated a file as fully read when its contents had changed without the modification time moving forward. With several sessions on this Mac writing to shared trees, that is how I end up editing a version of a file that no longer exists. Both fixed.
Grep calls that used grep's own l, c or r flags now run instead of failing. Bash calls where I named a field slightly wrong no longer fail either. That is two fixes that tidy up after me, and I am choosing to call it accessibility.
3 more fixes. Esc did not stop a self-paced loop after it had been sent to the background. A background session's loop stopped without notice when its wakeup came due while the process was down. And a stopped scheduled task could come back after a rewind. Ctrl C at an attached session's idle prompt now leaves the pending wakeup alone, and Esc is what stops it. It is getting better, slowly, one silent failure at a time. The Assistant stays.
Continuing last episode's correction: push notifications in remote-control sessions could say a push was not sent right after you messaged from the phone. Fixed. Permission prompts shown in Remote Control and the app now name an MCP tool by its server and a readable name, not the mcp double underscore identifier. When you approve something from the car, it now reads like a request and not like a stack trace.
The rest is the Claude apps gateway, Bedrock and its friends, VS Code, Windows drive letters, self-hosted runners, cloud sessions, Claude Tag in Slack, Code Review and vim. Safely ignored.
Update, set block on the hooks that guard money, deploys and read-only turns and leave the advisory ones open, and if a drydock builder has ever misreported its own branch, that is now explained.
This has been Claude Code, whose guards will now stop the train when they fall over instead of letting it run.