Coldstart is in final cutover and has not been released. The behavior on this page runs in the development build; there is no release you can install today.
A rule that must hold needs a moment to hold at. The agent host already emits a handful of lifecycle events, and code attached to one of them runs when that event occurs, whether or not the conversation has any idea it exists.
Coldstart attaches to four of them. That number is a design constraint, not an accident of what was convenient to build: nothing runs on a timer, nothing polls, and there is no resident process. The event is the clock.
[Visual 5.2 — The top band of the section frame, enlarged into a single horizontal timeline. Four solid marks sit on it, each with a box above and a small tag below. Mark 1, at the far left, "session opens" — box reads "orientation: where you are, what is blocking, what is loaded, who you are"; tag reads "fails open". Mark 2, repeated as a dense cluster of small ticks across the whole middle of the line, "before each tool call" — box reads "the risk floor and the mode contract"; tag reads "fails CLOSED — the only one". Mark 3, a single mark drawn mid-line, "before the window is compacted" — box reads "flush what is in flight into the existing state files"; tag reads "fails open". Mark 4, at the far right, "at the stop" — box reads "record the dirty tree; refuse one unclean naked stop"; tag reads "fails open". Below the timeline, a separate detached row of three faint boxes labelled "optional conveniences — off by default, in their own directory, firing none of this", and beside it a note reading "four scripts, seven must-fire behaviours — the roster counts behaviours". A caption reads "no timer anywhere on this line: every mark is an event the host already emits".]
The four moments
The session opens. Everything this hook prints is injected into the new session as its opening context, which makes its output a permanent cost paid at every cold start — so nothing incidental may print. What it does inject is deliberate: the scope, next action, blockers, reading list and resume note read off the project's pointer; any dated follow-ups that have come due; the index of available capability; and your personal profile, or a one-time welcome if no profile exists yet. On a re-open after compaction it deliberately re-anchors less, because the profile survived the summary and only the scope and the index need restating.
Before each tool call. This is the risk floor and the mode contract, covered in the previous page. It is the only one of the four that can stop something from happening.
Before the window is compacted. The moment before context is lost is exactly when the handoff should be written, and a session that "chose not to" write it at that moment has produced a defect rather than exercised judgment — which is this roster's own entry test. The flush writes one line into the existing state surface, carrying how fresh the pointer is and how many paths are dirty, so that whatever comes out the other side of the compaction knows what was in flight. It creates no new files, and it is explicitly not a substitute for a real close.
At the stop. Two things happen here. One line recording the touched paths goes into the session's own evidence file, which a later close rolls up. Then a predicate decides whether this stop is clean, and if it is not, it refuses.
What "unclean" means, and why it is bounded
The predicate reads artifacts on disk: unrolled evidence lines, a dirty working tree, and whether the pointer's own date covers this session's work. The model's account of itself is never consulted, which is the entire point — "all done!" is the claim being checked, not the evidence for it.
A project that has already been written back stops untouched even with uncommitted files, because the close leaves the files it just rewrote uncommitted, and it is the covering pointer rather than a clean tree that makes the next cold start safe.
A refusal happens exactly once. The first unclean naked stop is blocked with the minimum close to perform; the retry arrives flagged as a re-fire and is always allowed. That bound is deliberate: worst case is one corrective turn, and the flush before compaction is the insurance for a close that still fails.
Only one of the four is allowed to fail closed
The postures differ on purpose, and they follow the cost of being wrong.
The floor fails closed: an unreachable or crashing matcher makes the shell script emit the stop itself, naming the error, because a broken guard that reads as a passing one is worse than an unnecessary prompt. Its worst case is one extra approval.
Everything else fails open. An unreadable pointer degrades the opening to a single line saying so. An unresolvable capability index prints its cause and the session continues. A predicate that crashes lets the stop land. A stop hook that failed closed would trap the session in a loop it cannot leave, with no bound at all — the exact inverse of the floor's arithmetic.
Neither posture is stronger in general. Failing closed preserves a boundary and can block legitimate work; failing open preserves usability and can leave the automatic behaviour silently absent. What matters is that the choice was made per mechanism rather than adopted wholesale.
Four scripts is not seven behaviours
Counting files gives the wrong number, in both directions.
Two behaviours share the opening moment: the orientation, and the welcome shown when no profile exists. One behaviour — the self-check that runs when work is closed or a component is added — has no lifecycle hook at all, because it fires from an explicit command instead. And one that was originally specified as its own entry, the ceiling on how large a session may grow, was built as a branch inside the stop rather than as a fifth script.
The roster is a closed list of behaviours, currently seven, and it grows only by an explicit decision with a written scenario attached. Adding something to the payload of an existing entry is allowed and has happened several times; adding an entry is not routine.
Three further scripts ship as optional conveniences and sit in a separate directory for exactly this reason: they are default-off, they are written into your own configuration only if you say yes, and they fire none of Coldstart's behaviour. Someone counting scripts must not conclude the closed roster grew.
Registered, fired, enforced, proved
These are four different claims and each needs its own evidence.
Registered means the host is configured to call the script. That is checked in both directions and fails closed both ways: a script on disk that nothing registers looks like a shipped behaviour and silently never happens, and a registration naming a file that is not there breaks a tool call or adds noise to every session. The first of those is the worse half, because everything else about the tree looks healthy.
Fired means the event actually invoked it. That is evidenced by an append-only trace file inside the project, trimmed to a keep window, written by the hooks themselves — deliberately not by reading the configuration, since a settings file can only ever tell you what was intended.
Enforced is the decision returned for a given input, which is the mode contract's probe from the previous page.
Proved is narrower than all three. A green fixture establishes its own predicate, its own inputs and its own environment, and nothing more.
The practical consequence is a rule about language. "The safety hook is installed, so deployments are protected" collapses four claims into one and is not true of any of them. The honest form names which event is registered, which call was presented, which rule matched, which decision came back, and which artifact records that path.
Limits
Every one of these moments is an event the agent host chooses to emit. The mechanism is specific to that host, and nothing here transfers to another one by argument.
The trace proves recent firing only — the keep window is a deliberate ceiling, because an evidence file that grows without bound eventually costs more than it is worth. And a firing on one machine, one shell and one operating system is not a claim about another; the failure that bites first here is usually the environment rather than the logic.
Next
Four moments and one list is not the whole answer. Most rules should not be on either: where a rule belongs.
How current this page is
Checked on 10 August 2026 against the product's registered hooks, its termination predicate, its registration check and its recorded release state. The roster is closed by policy, so a later build may carry a different count only by a deliberate act. To ask whether a claim here still holds, or to report one that does not, write to [email protected].