Imported from melodic-software/claude-code-plugins (
plugins/session-flow/skills/running-retro/SKILL.md). Install upstream withnpx skills add melodic-software/claude-code-plugins --skill running-retro. Copyright stays with the author.
Context. Gather first
Take session-id, branch, status, and recent-commits at -5. Probe commands, the
one-command-per-call and treat-failure-as-unknown rules, and the $-expansion rationale for
gathering at run time rather than pre-computing:
${CLAUDE_PLUGIN_ROOT}/reference/gather.md.
Purpose
The self-improvement loop, run while the work is still in flight, not after it. Answers, at a
mid-session checkpoint: "How is this session actually going, what is drifting, and what should
change before it costs more?" Each checkpoint appends to a cumulative running ledger for the
session, so observations accumulate across a long session or a /loop interval rather than waiting
for a single end-of-session pass.
It captures and routes findings; it does not apply them. Codification (editing CLAUDE.md,
rules, or memory) stays with /session-flow:retro codify. Tracker filing is offered, never
performed automatically.
Siblings. Pick the right one
/session-flow:retro. End-of-session full retrospective: five scored dimensions, feedback regression check, codification of approved learnings. running-retro is its live counterpart: same act (retrospective), different cadence (mid-flight, cumulative), and it deliberately drops scoring and codification./session-flow:handoff, a save-point that ends the session for/clear. running-retro is non-terminating: it observes and the session keeps going.
Zero-arm. Nothing to set up in advance
No arming at session start for the default in-session checkpoint. The session transcript on disk
(<session-id>.jsonl) is the lossless record. It survives compaction, so a checkpoint reconstructs
the full session from disk even after the live context was compacted. That is exactly what
/session-flow:retro's parser already reads in production; running-retro reuses it rather than
parsing anew. Invoke a checkpoint any time. (The arm action and its opt-in SessionStart hook are
the deliberate exception. They arm a detached observer to run the checkpoint after the session
ends; see "Arming a detached observer" below. The default checkpoint still needs no setup.)
The checkpoint flow
1. Subjective-state note (main agent, the one thing disk cannot capture)
Before delegating, write 2-3 lines of your own in-flight state: what you are uncertain about, what feels off, where you are stuck or repeating, any correction you sense coming. The transcript on disk holds what happened; it does not hold the acting agent's present read of it. This note is the only signal the analysis subagent cannot get for itself. It seeds the analysis.
Ground the note in the instrument when one is present. When the context-guard plugin is
installed, resolve this session's zone word per its reader contract (the contract owns the
snapshot path, staleness rule, and bands, read them there; this note carries only the resulting
word, no band values) and include it in the note. A self-impression of the window is a guess and
can sit far from the instrument's reading, and the analysis subagent judging degradation deserves
the measured word next to the subjective read. Absent plugin, absent snapshot, or unknown: say
so in the note rather than substituting an estimate. If context-guard's evidence-degraded marker
exists for this session, record that too. It outranks a healthy-feeling self-read.
2. Resolve inputs for the subagent
The analysis runs in a fresh subagent (own context window; it sees none of this conversation,
the skills invoked, or files read, per the sub-agents doc "what loads at startup"). So resolve
every input to a concrete value and pass it in the delegation prompt, a ${CLAUDE_PLUGIN_ROOT}
token will NOT expand there:
- Session data dir + transcript + subagents dir. Resolve per the retro skill's "Paths"
(
${CLAUDE_PLUGIN_ROOT}/skills/retro/SKILL.md); transcript is<SESSION_DATA_DIR>/<session-id>.jsonl, subagents<SESSION_DATA_DIR>/<session-id>/subagents/. - Parser (absolute path). Resolve
${CLAUDE_PLUGIN_ROOT}/skills/retro/scripts/parse_transcript.pyto its absolute form and pass that; the invocation + Python-3.10+ interpreter detection live in retro's Phase 1.1 (${CLAUDE_PLUGIN_ROOT}/skills/retro/context/session.md). Point the subagent there, do not restate them. - Handoff-chain pointers, if this session resumed from a handoff, pass the chain so the
subagent's parser run spans the whole transcript chain, subject to the continuity gate in retro's
Phase 1.0 (
${CLAUDE_PLUGIN_ROOT}/skills/retro/context/session.md). - Prior running-retro ledger, if this session's ledger (or its chain) carries a
previous_running_retropointer, resolve that prior ledger's absolute path and pass it so the subagent carries forward earlier checkpoints' findings (the "running" = cumulative guarantee). This is the ledger's OWN continuity chain, walked by reading the ledger files, NOT the parser's--chain-from, so a session continued from an earlier checkpoint without a handoff still keeps its prior findings. - Repo convention docs, the consuming repo's
CLAUDE.md, the relevant.claude/rules/files, and any convention READMEs, so the subagent judges convention/workflow drift against the repo's documented rules. These are trusted local reads; transcript content is not (see checkpoint.md's trust boundary). - The subjective-state note from step 1.
3. Delegate the analysis
Spawn a general-purpose subagent with the delegation prompt from
context/checkpoint.md. It
carries the parser-first-then-selective-read method, the finding categories, the resolution-route
classification, and the mandatory redaction pass on the returned findings. The subagent returns
a compact findings block only; the verbose transcript stays in its context.
4. Append to the running ledger
Resolve the ledger location through the plugin binding
(${CLAUDE_PLUGIN_ROOT}/reference/topic-docs.md).
<memory_dir>/running-retros/ (default .work/running-retros/).
One ledger file per session, appended. Discover before creating. Name it
<TS>-running-retro-<topic>.md (TS = date -u +%Y%m%dT%H%M%SZ, topic = argument or inferred),
created on this session's FIRST checkpoint with frontmatter session_id: $CLAUDE_CODE_SESSION_ID. On
every LATER checkpoint do NOT create a second file: locate this session's existing ledger by globbing
<memory_dir>/running-retros/*-running-retro-*.md and matching the one whose frontmatter session_id
equals the current $CLAUDE_CODE_SESSION_ID, then re-read it from disk and append a new
## Checkpoint <TS> section. Create a new file only when no such match exists. This session-id match
is the discovery rule that keeps one file per session rather than one per checkpoint.
Chaining across /clear. When this session resumed a prior one through a handoff chain (retro's
Phase 1.0 continuity gate), record previous_running_retro (the prior session's ledger path) and
previous_session_id in this ledger's frontmatter. These are ledger-continuity pointers THIS skill
walks to present the cumulative running history; they are NOT parser input, the parser's
--chain-from consumes handoff files only (it reads session_id / previous_handoff), never
running-retro ledgers. Honor the contract's runtime guards from the binding (the once-per-session
self-ignore guard on the resolved memory root; never edit the consumer's root .gitignore).
Redact before writing. Re-sweep the findings for secrets, tokens, credentials, connection
strings, and PII, replacing each with a shape marker (<REDACTED: API key>). Defense in depth over
the subagent's own pass. The ledger is memory-tier disk output: it outlives the session, sits
uncommitted-but-readable, and travels to other sessions and machines.
5. Offer routing, never auto-apply
Present the checkpoint findings, then OFFER the forward routes; act only on the ones the user picks:
- Codify a durable learning →
/session-flow:retro codify(running-retro never editsCLAUDE.md, rules, or memory itself). - File follow-up work → offer the consumer's work-item tracker; never file automatically.
- Build the new-skill candidate → read
/playbooks:skill-authoringfor the authoring doctrine and draft against it, then gate the result on/skill-quality:check, when those are installed; otherwise say the candidate has no authoring route here and leave it recorded. The checkpoint already emits a "New-skill candidates" line, and a candidate with no named destination is a finding that evaporates. Read the doctrine before drafting rather than inventing a shape from scratch, a skill written ad hoc at the end of a checkpoint is the one most likely to miss the conventions that playbook exists to carry. (It is a knowledge surface: it takes no arguments and performs no actions, so it informs the drafting rather than doing it.) - Nothing actionable → say so and continue the task.
Post-checkpoint checklist
Tick each in the response so the exit shape is verifiable:
- Subjective-state note written before delegating (step 1)
- Analysis delegated to a fresh subagent with resolved absolute inputs (step 2-3)
- Redaction swept the subagent findings AND the ledger append (both hops. Step 3 and step 4)
- Findings appended to this session's single ledger file (located by
session_idmatch, not a new per-checkpoint file; self-ignore guard verified on the first memory-tier write) - Routes offered, nothing auto-applied (step 5); the task continues in this same session
Arming a detached observer (arm)
When $ARGUMENTS is arm (or the user asks to watch/observe this session in the background), do
NOT run the in-session checkpoint above. Instead launch the detached observer for the current
session: a substrate that outlives the session, tails its transcript out-of-band at zero context
cost, detects end by mtime-idle, and (unless analysis is disabled) runs this same checkpoint method
headless afterwards, appending its findings to this session's ledger. The substrate, lifecycle,
config, untrusted-data boundary, and the deferred native Observer-Agents alternative live in
${CLAUDE_PLUGIN_ROOT}/reference/observer.md. Read
it, do not restate it. To arm the current session, resolve the inputs and run the launcher:
First resolve these into shell variables the block below reads. A skill runs in-session, so read
config from the rendered ${user_config.observer_*} values (an unexpanded token or empty = the
default), the CLAUDE_PLUGIN_OPTION_* env vars the hook uses are NOT set in a skill's Bash context:
OBS_MODEL←${user_config.observer_analysis_model}(defaultclaude-haiku-4-5)OBS_IDLE←${user_config.observer_idle_seconds}(default900);OBS_MAX←${user_config.observer_max_seconds}(default86400)OBS_ANALYSIS←${user_config.observer_analysis_enabled}(defaulttrue), an operator who set itfalseto avoid autonomous spend must NOT get aclaude -prun from a manual armOBS_BARE←${user_config.observer_analysis_bare}(defaultfalse)DECLARED_MEMORY_DIR← amemory_dirthe consuming repo documents in prose (itsCLAUDE.md/ rules) but not in.claude/topic-docs.yaml. Retro's rung-2 inference; empty otherwise. Being in-session, the manual arm CAN honor this (and cross-session continuity below); the headless hook resolvesmemory_dironly from the concern file + default and cannot infer a prose-documented root.PREV_LEDGER/PREV_SID← for cross-session continuity, if this session resumed from a handoff chain or an earlier running-retro ledger: resolve the prior ledger and its session id under retro's Phase 1.0 continuity gate (same as the checkpoint flow's step 2). A detached/headless observer cannot make that judgement safely (blindly linking the newest handoff could splice an unrelated session), so the SessionStart hook leaves these empty and a later in-session checkpoint reconciles them.
The launcher resolves the ledger dir to an absolute path, so a relative memory_dir still lands in the
consumer repo, not the plugin cache.
PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT}"
TRANSCRIPT="$SESSION_DATA_DIR/${CLAUDE_CODE_SESSION_ID}.jsonl" # SESSION_DATA_DIR per retro's "Paths"
MEMORY_DIR=$(bash "$PLUGIN_ROOT/skills/retro/scripts/parse-concern-value.sh" \
.claude/topic-docs.yaml memory_dir "${DECLARED_MEMORY_DIR:-}")
MEMORY_DIR="${MEMORY_DIR:-.work}"
WORK_DIR="${CLAUDE_PLUGIN_DATA:-${TEMP:-${TMPDIR:-/tmp}}}/session-flow-observer"
PY=""; for c in python3 python; do command -v "$c" >/dev/null 2>&1 \
&& "$c" -c 'import sys;sys.exit(0 if sys.version_info>=(3,10) else 1)' 2>/dev/null && { PY="$c"; break; }; done
args=(--transcript "$TRANSCRIPT" --work-dir "$WORK_DIR" --ledger-dir "$MEMORY_DIR/running-retros"
--session-id "$CLAUDE_CODE_SESSION_ID" --plugin-root "$PLUGIN_ROOT"
--previous-running-retro "${PREV_LEDGER:-}" --previous-session-id "${PREV_SID:-}"
--model "${OBS_MODEL:-claude-haiku-4-5}"
--idle-seconds "${OBS_IDLE:-900}" --max-seconds "${OBS_MAX:-86400}")
[[ "${OBS_ANALYSIS:-true}" != "false" ]] && args+=(--analysis)
[[ "${OBS_BARE:-false}" == "true" ]] && args+=(--bare)
"$PY" "$PLUGIN_ROOT/skills/running-retro/scripts/arm_observer.py" "${args[@]}"
This is the SAME launcher the opt-in SessionStart hook (observer_enabled) uses; manual arm works
whether or not the auto-arm is on, and is the primary entry. Because it runs in-session it can honor
prose-inferred memory roots and cross-session continuity the headless hook cannot. The launcher prints
the observer pid and returns at once; it never blocks the session.
Cadence
Manual checkpoint by default. Composes with /loop for periodic checkpoints across a long session;
running-retro ships no scheduler of its own. It is non-terminating. After routing, the underlying
task continues in this same session. The detached observer (arm) is the push/end-of-life
counterpart: a /loop cannot fire after the session ends, but the observer can.
What this skill does NOT do
- Does not score the session. The five scored dimensions are
/session-flow:retro's. - Does not codify learnings, capture + route only; codification is
/session-flow:retro codify. - Does not auto-file tracker issues; it offers routing; the user decides.
- Does not
/clearor end the session, unlikehandoff; the session continues. - Does not run builds, tests, or a code review, and does not write into the consumer's repo beyond the memory-tier ledger and any routing the user approves.
Gotchas
- The subjective-state note is mandatory. Skipping it discards the one input the subagent cannot reconstruct from disk.
- Pass resolved absolute paths to the subagent, its fresh context expands no plugin variables and inherits none of this conversation's paths.
- Redact on both hops, the subagent's findings pass AND the ledger write; memory-tier output outlives the session.
- One ledger file per session, appended. Discover this session's file by matching
session_idin frontmatter before writing (never create a second file per checkpoint); re-read from disk before appending, never rewriting from a possibly-stale in-context copy. Cross-/clearhistory is linked by theprevious_running_retropointer, which the skill walks, not the parser. - Non-terminating. A checkpoint is an observation, not a stop point; do not treat it like a handoff.