From Tool Calls to a Teachable Episode
AutoHarness uses a specific question to decide when a Claude Code session has produced enough material for reflection: has the agent done work, or has it only continued the conversation? This chapter follows that boundary from tool activity through the bounded transcript handoff and into a reflector's proposal. The result is a useful distinction for operators: scheduling an episode and interpreting an episode are separate jobs, and neither one is the same as storing a new skill.
Work, not conversation, closes the episode
A conversation can be long without teaching the system anything durable. Someone may discuss an approach, ask for clarification, or revise a plan without invoking a tool. Conversely, one substantive turn can inspect files, edit a test, run a command, and produce a correction worth remembering. AutoHarness therefore advances its reflection activity counter on main-session tool calls observed before tools run, rather than treating every conversational turn as an equal unit.
That choice changes the meaning of cadence. A chat-only exchange does not push the session toward a reflection. A working stretch does. The Stop event still decides whether the configurable threshold has been reached, but it does not create the activity itself. When the threshold is crossed, the session counter is reset and a detached background job receives the work window. The user's critical path is not supposed to wait while another model reads the episode and proposes a skill.
This is a scheduler, not a quality filter. Crossing the threshold says that enough activity occurred to justify looking, not that the episode contains a good lesson. A session can do a great deal of routine work and yield nothing reusable. A short correction can contain a durable convention. AutoHarness leaves that content judgment to the reflector and the deterministic checks that follow it.
The distinction also keeps background work from becoming self-feeding. Reflection runs in a child session, but child-session hooks carry a plugin-owned guard. The child's Stop and SessionEnd events do not start another reflection, and the child's library-comparison reads are not counted as evidence that a skill helped the main task. Without that separation, the maintenance process could inflate its own denominators, recursively launch more children, or make curation look like user adherence.
The trigger is deliberately conservative because reflection is maintenance, not a second agent working in parallel on the user's problem. A lower threshold can make the library learn faster, but it also creates more child sessions and more opportunities to distill incidental details. A higher threshold reduces that background activity, but makes a lesson wait longer and increases the importance of the session-end flush. The configuration exposes this trade-off rather than pretending there is one correct cadence for every workflow.
There is also a useful failure rule: a malformed or missing session identity does not become a reason to guess. The Stop and SessionEnd handlers fail safe when they cannot associate activity with a valid session. That may lose a reflection opportunity, but it avoids attaching one user's episode to another state file. In a maintenance system, a missed lesson is visible as absence; a lesson attached to the wrong session can silently alter future behavior.
The boundary at Stop and SessionEnd
The normal path begins before Stop. Each relevant PreToolUse event increments the main session's activity count. Stop then asks a narrow question: is the count at or above the reflection threshold? If not, no reflection starts and the counter remains available for later work. If so, AutoHarness launches the detached handoff with the session identity and transcript location, then resets the activity count so the next stretch begins cleanly.
There is a second path for incomplete stretches. A user can end a session below the threshold after doing meaningful work. If AutoHarness simply waited for the threshold, that tail would disappear from its learning path. SessionEnd checks the remaining count, requests a flush of the unfinished episode, and then clears the session counter. A zero-length tail produces no reflection. A nonzero tail receives a chance to teach, even though it was not large enough to trigger the ordinary cadence.
The two paths serve different operational purposes. Stop makes reflection periodic during a continuing work session. SessionEnd prevents the periodic rule from becoming a data-loss rule at the boundary of a session. Neither path interprets the transcript, and neither path writes a skill. They only establish when a bounded observation should be handed to the next stage.
The distinction between “window size” and “threshold” is easy to miss. During a threshold-triggered reflection, the captured range is the material since the previous watermark, not necessarily a transcript whose size equals the configured activity threshold. A session may make many tool calls that generate little text, or a few calls that generate large tool records. At SessionEnd, the remaining activity count tells the system how much unfinished activity to flush, while the capture layer still applies byte limits. Activity controls when to look; byte bounds control how much can cross the handoff.
That separation gives the design two kinds of predictability. Operators can reason about cadence in terms of work, while the child context remains bounded in terms of bytes. Neither measure promises complete causal coverage. It only makes the missing context a consequence of explicit limits rather than an accidental result of a parser or an unbounded tool dump.
The diagram's most important edge is not the arrow from the reflector to the queue. It is the absence of a direct arrow from the reflector to the live skill tree. The queue is the boundary between “a child model suggested this” and “the system may now consider storing this.” The following stage can reject or reshape the suggestion without needing to trust the model's ability to manage files.
What evidence crosses the boundary
AutoHarness deliberately treats the host transcript as an opaque event log. Capture does not try to reconstruct a clean chat by assuming that every record is a user message, assistant answer, or tool result in a simple sequence. That restraint matters because real logs contain metadata and tool records whose apparent roles can mislead a parser. The reflector, which is already responsible for interpreting the episode, receives the raw JSONL-shaped material instead of a lossy interpretation made by the hook.
Opaque does not mean unlimited. Capture remembers a byte offset for each session and reads only the material after the last reflection. If the transcript has been rewritten or the offset is no longer valid, it fails safe by starting a bounded reread rather than trusting a negative or stale position. Oversized records are clipped. If the whole window exceeds its cap, the newest tail is retained and a truncation marker makes the loss visible. This favors recent causally relevant work while acknowledging that the reflector may not see the beginning of a long episode.
The handoff has a privacy boundary as well. Redaction runs before the window leaves the capture path. The repository's rules cover representative secrets and personal identifiers, and the tests check that example keys and email addresses do not survive into the captured text. But the implementation is pattern-based and intentionally errs toward over-redaction. That protects against some recognizable forms; it is not a proof that every secret, credential, or personal datum will be detected.
Older context is supplied separately through a digest. The digest retains bounded user and assistant text and the names of tools used before the current window, but it omits tool outputs and tool inputs. That gives the reflector orientation—what problem the session was working on and which kinds of actions occurred—without presenting the digest as a verbatim evidence source. The current window is the evidence slice; the digest explains where that slice sits in the larger session.
This separation creates a deliberate trade-off. A reflector needs enough context to understand why a correction occurred, but passing the entire history would spend more context and expose more material. A bounded window can omit an earlier cause; a redaction rule can remove text that would have clarified the lesson; a digest can tell the model that a tool was used without showing its output. AutoHarness makes those losses explicit through caps and truncation rather than pretending that the child sees the whole session.
The watermark also makes reflection incremental. After a successful handoff, the plugin records where the window ended and the next pass starts after that point instead of rereading the same episode. If compaction or another rewrite makes the stored position stale, the safe fallback is a bounded reread, not an attempt to write a corrected position into the host transcript. Capture never mutates that transcript. The plugin owns its offset and handoff state, while the host remains the authority for the raw record.
In practice, this means the reflector is given an evidence packet shaped by two decisions: what work has not yet been handed off, and what that work can safely fit into the child context. It does not receive an omniscient session replay. That is a healthier contract for a proposal-generating model because it makes uncertainty part of the input rather than hiding it behind a confident summary.
The reflector interprets, it does not persist
Once the redacted window and its context arrive, the reflector performs the part that requires language judgment. It reads the episode, looks at a description index of existing skills, and receives the format rules that a new or updated skill must satisfy. Its instructions prefer comparison before creation: if an existing skill covers the scenario, patch or update it; if a new rule contradicts an old one, reconcile the old statement rather than leaving two instructions that disagree; if a lesson is worth keeping, express it at the level of a reusable class of work rather than as a transcript of one session.
That comparison-first request directly answers the opening problem. A second test correction should enrich a testing skill instead of creating a near-duplicate for each file. The reflector can also propose supporting detail, a removal of obsolete material, or an archive/delete-style intent. The important word is propose. The model chooses a candidate lesson and supplies a reason and evidence quote, but it cannot decide that its own prose is safe simply by writing it.
This division is especially important because a useful lesson may contain unsafe or misleading text. The reflector sees user and tool content that can carry accidental instructions or malicious prompt injection. It also has access to an existing library whose contents may be incomplete or contradictory. A top-level hook denies write tools to reflector and child sessions, while the proposal API accepts only structured actions. Those controls do not make the model's judgment correct. They constrain the damage that a mistaken judgment can do before a later admission stage examines it.
The reflector is also asked to leave an account of why a proposal exists. Its reason and evidence are not a semantic guarantee, but they make a later landing explainable and give the promoter material to store with the resulting skill. A proposal that cannot even state its lesson, reason, and evidence is not merely inelegant; it is missing the provenance needed to maintain a persistent rule. This is why the chain treats the evidence quote as part of the proposal contract rather than as optional commentary.
The same chain is available when a user invokes /learn deliberately. That path does not turn the interactive session into a privileged editor. It stages an intent for the ordinary promoter to drain, so background learning and user-requested learning share the same ownership, validation, and evidence boundary. The system can therefore treat “please remember this” as a request to evaluate a lesson, not as permission to bypass the controls.
The episode is complete when the reflector has placed a proposal in the durable intent queue. At that point, AutoHarness has preserved a bounded, redacted account of work and converted it into a candidate change. It has not yet created memory. The next boundary must decide whether the candidate is well-formed, safe, attributable, and allowed to affect the live skill surface.