02 Reflection
Noticing that a session contained something worth keeping.
Runs on Stop, per turn. Its job is to schedule
attention, not to judge.
The occasion is structural — "did this turn have enough substance to be
worth a thought" — measured by nudge_after_tool_calls (12),
nudge_after_turns (3), or min_surprises (2 failed
tool calls), subject to nudge_cooldown_s.
What it looks for#
Not "were you wrong about anything?" — that is a judgement the reflector has to reach for, and it reliably answered no on sessions full of corrections. The question is where did the user have to steer you, which is evidence sitting in the transcript. It is the same split the rest of ROSE applies: count the observed outcome, judge only what needs judging.
A correction, a rejection, a "no, like this", a restated requirement, a complaint about quality, a preference you did not know they held. Each is a round of the user's time a better-informed agent would not have cost them. For each, the reflector asks what it would have needed to know at the start, and the answer is usually one of:
| # | Kind | Why it leads |
|---|---|---|
| 1 | A standard or preference this user holds | The three most often missed, and the three that remove the most future steering. They are not mistaken beliefs, so a taxonomy asking only about wrongness cannot see them at all. |
| 2 | A method they expect applied | |
| 3 | A quality bar | |
| 4 | A false belief about a tool, language or platform | Counts even though it surfaced as a bug. The test is whether a belief was wrong, not whether it arrived with an error message. |
| 5 | A false belief about this project | — |
| 6 | A modelling error | You represented something in a way that is not true of it. |
Then it filters on usefulness rather than worthiness:
- would knowing this at the start have removed at least one round of steering?
- does it apply to some task other than this exact file?
- is it still true tomorrow?
Three things it does instead of capturing#
- Already served, still ignored. If the user had to say something that was already in a lesson the agent was shown, that is not a gap in what is known — it is a lesson that is not landing. The reflector names the node id and captures nothing.
- A capture it should have made. If the conversation shows the agent
running
rose additself, or the user asking why something was not learned, an earlier pass missed it. The reflector works out what about these criteria let it through and captures that, in thereflectionfamily. - A defect in ROSE. If what it found is a bug in the harness rather
than a lesson for the store, it runs
rose reportand asks whether you want it filed. It never files anything itself.
The backoff, and why it is versioned#
Nudges that keep producing nothing lengthen the cooldown, up to a cap of one hour. But "found nothing" and "there was nothing to find" are different states, and a backoff that cannot tell them apart throttles hardest exactly when the reflector is broken.
That happened here. Bad criteria produced six barren nudges, the cooldown grew from 15 minutes to four hours, and rewriting the criteria did not release it — so the fix could not run to prove itself. The criteria are now fingerprinted and every nudge records the fingerprint it was issued under; a streak only counts events sharing the current one, so changing a prompt resets it by construction.
Where it runs — learning.nudge_mode#
| Mode | Reflector sees | Cost | Interrupts you |
|---|---|---|---|
background (default) | a transcript digest, ~3k tokens | one small call | no |
fork | the whole session, inherited | ~0.1× its tokens | no |
block | the agent's own live context | none extra | yes, one turn |
off | — | none until session end | no |
fork spawns claude --resume <id>
--fork-session detached. --fork-session allocates a new
id, so the live session is never written to. It is affordable because
prompt-cache reads bill at 0.1× and the cache keys on prefix
content, not session identity — the fork hits what the live session
just wrote.
If nudges keep producing nothing, the cooldown backs off automatically
(nudge_backoff_after).