●DESIGN — Claude Design gets a major update: design-system imports, direct canvas editing, and more export formats●CODE — Claude Design can start from your local codebase and hand a design off to Claude Code to implement●FABLE — Fable 5, a Mythos-class model made safe for general use, is now available in Claude Code v2.1.170●FIX — Mid-stream connection drops now preserve partial responses instead of showing a raw error●SCROLL — A new wheelScrollAccelerationEnabled setting disables mouse-wheel scroll acceleration in fullscreen●TIER — The Claude Design beta is available to Pro, Max, Team, and Enterprise customers●DESIGN — Claude Design gets a major update: design-system imports, direct canvas editing, and more export formats●CODE — Claude Design can start from your local codebase and hand a design off to Claude Code to implement●FABLE — Fable 5, a Mythos-class model made safe for general use, is now available in Claude Code v2.1.170●FIX — Mid-stream connection drops now preserve partial responses instead of showing a raw error●SCROLL — A new wheelScrollAccelerationEnabled setting disables mouse-wheel scroll acceleration in fullscreen●TIER — The Claude Design beta is available to Pro, Max, Team, and Enterprise customers
How to use Claude Code's new post-session hook to automate temp-file cleanup and log writing after a session ends, with real examples from a pipeline that processes several repositories in sequence.
A few times a month, my nightly publishing job would finish without removing the .next build artifact or appending its log entry — even though generation and the push itself ran fine every time. Only the final cleanup went missing. The cause was always the same: I had written cleanup as "the tail end of the main work," so whenever the run took a different branch, it never reached the last steps.
The June 18, 2026 update added a post-session hook (SessionEnd) to Claude Code — a hook that always runs after a session ends. It turned out to be exactly the structural guarantee I needed for the work I kept losing because it lived at the bottom of the main flow. As an indie developer running several sites in sequence, here is what I actually moved into it and where I tripped.
Why cleanup at the tail of the flow gets dropped
The body of a session branches on errors, early returns, and conditionals. Cleanup placed at the very end only runs when you take the happy path. What I wanted was the same protection a shell trap or a language-level finally gives you, but applied to a Claude Code session — and that is precisely the niche SessionEnd fills.
In my case, three things kept getting dropped: removing the temporary build output (.next), appending that day's update log, and checking free disk space for next time. None of them affect article quality, but left alone they fill the disk until the next session cannot even start.
The basic shape of a SessionEnd hook
You register hooks under hooks in settings.json, keyed by event name. SessionEnd fires right before the session closes.
One thing worth remembering: a SessionEnd hook's exit code and stdout do not change the outcome of a session that is already wrapping up. Unlike a Stop hook, it is not meant to block and resume work — it is for the "one reliable chore after the fact." I confused it with a Stop hook at first and tried to call further work back from inside the cleanup script, which failed. Treat SessionEnd as a point of no return and the design becomes clear.
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦A working SessionEnd hook config and why its exit code does not change the session outcome
✦Concrete scripts for moving temp-file removal and log appends into the hook
✦A real failure from putting teardown in the hook, and how to avoid it
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
I folded the three tasks into a single script. The session payload (JSON) arrives on stdin, so you can read the working directory and session ID from it.
#!/usr/bin/env bash# .claude/hooks/on-session-end.shset -uo pipefail# Session info arrives as JSON on stdinPAYLOAD="$(cat)"CWD="$(echo "$PAYLOAD" | python3 -c 'import sys,json; print(json.load(sys.stdin).get("cwd",""))')"LOG_DIR="${HOME}/automation/logs"mkdir -p "$LOG_DIR"# (1) Remove temporary build output[ -d "${CWD}/.next" ] && rm -rf "${CWD}/.next"# (2) Append the day's log (take the date in JST)TODAY="$(TZ=Asia/Tokyo date +%F)"echo "$(TZ=Asia/Tokyo date +%T) session ended in ${CWD}" >> "${LOG_DIR}/${TODAY}.txt"# (3) Check free disk space; only warn if below thresholdFREE_MB="$(df "$HOME" --output=avail -m | tail -1 | tr -d ' ')"if [ "${FREE_MB:-0}" -lt 500 ]; then echo "WARN: free ${FREE_MB}MB at session end" >> "${LOG_DIR}/${TODAY}.txt"fiexit 0
Pinning the log date to TZ=Asia/Tokyo is deliberate. A bare date returns UTC in some environments, so a run late at night in Japan can write into the previous day's log file. That bit me once — the log shifted by a day and was painful to trace later. Make timezone explicit from the start in anything that touches dates.
What I actually moved across four sites
I run several technical blogs under the name Dolice, each in its own repository, processed one after another. Until now I pasted nearly identical cleanup code at the end of each site's flow. When the same code lives in four places, you fix one and forget the others — and that is exactly the kind of accident that happens.
Moving it into a SessionEnd hook collapsed the cleanup into a single script and removed it from each site's flow. The table below lays out where each task lived before and after.
Task
Before
After
.next removal
End of each site flow (duplicated x4)
One SessionEnd hook
Log append
Mid-flow (dropped on branches)
One SessionEnd hook
Disk check
Top of next startup
One SessionEnd hook (early warning)
Beyond removing duplication, pulling the disk check forward to "end of this run" rather than "start of the next one" mattered: I now learn about a problem a full night earlier.
Where I tripped, and how to avoid it
Three pitfalls I hit during the move — all from real automated runs.
Expecting interaction inside the hook: SessionEnd runs as the session closes, so any prompt that waits for an answer gets none. It has to complete fully non-interactively.
A script failure that loses the log: with set -e still in place, the script exited early on a case where there was nothing to delete, never reaching the log append. Cleanup scripts should run to the end even when individual steps fail, so I swallow non-fatal errors (that is why the example uses set -uo pipefail instead of set -e).
Relative-path accidents: the hook's working directory at run time may not be what you assume. Build delete and log paths from an absolute base — $HOME or the cwd from stdin — to avoid wiping the wrong place.
The third point deserves extra care because cleanup is a deleting operation. I keep delete targets fixed to a narrow directory name like .next and avoid wildcard sweeps entirely.
What belongs in the hook, and what stays in your hands
Not everything should move into a hook. My dividing line is: "does a failure here corrupt the result of the main work?" Idempotent steps that run after the real output (article generation and push) is done — cleanup, logging, disk checks — belong in SessionEnd.
Conversely, anything that determines the outcome, like the push itself or a quality-gate decision, should stay in the main flow. Those judge success by exit code and need to be retried on failure. Put them in an end-of-session hook and you cannot turn back when they fail.
Nature
Where it belongs
Examples
Idempotent, teardown, recording
SessionEnd hook
.next removal, log append, disk warning
Outcome-deciding, needs retry
Main flow
Quality gate, git push, count consistency
This split mirrors how I think about Stripe payment webhooks: separate the outcome work you want to land exactly once from the recording work you can safely re-run, and operations get far easier to live with.
A first step
Start small. If there is one "thing I always do but that is not the point" sitting at the end of your sessions, factor it out into on-session-end.sh and register it on SessionEnd. For me it began with a single unglamorous line — removing .next. Even just ending the dropped chores changes how the next morning feels.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.