plugins/coordinator/skills/workstream-complete/SKILL.md
Wrap up finished work — capture lessons, update docs
npx skillsauth add oduffy-delphi/coordinator-claude workstream-completeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Close out a finished vein of work: capture lessons and update documentation to reflect completion. No handoff — this is for work that's done, not being passed forward.
/workstream-completeand/handoffare mutually exclusive — never combined./workstream-completecaps a workstream;/handoffpasses one on. A session terminates via exactly one of them (or via/workday-complete//merge-to-main/ commit-and-stop). If the work is in-flight and needs a successor, STOP — invoke/handoffinstead and do not run this skill. If you are tempted to run both ("end the session AND write a handoff"), the underlying state is two workstreams: end the finished one here, hand off the in-flight one separately with/handoff, framing which is which.
Capture lessons and update plan/project documentation to reflect completion. If work is incomplete, use /handoff instead. Multiple agents may be running concurrently — this skill closes out ONE session without heavy repo-wide operations.
This skill is mirror-shaped to /handoff: a small set of sequential gates plus a TODO-LIST cluster of independent post-work cleanup steps. Treat them as such — do not ladder-walk the todo-list. Convention: docs/wiki/skill-step-parallelization.md.
Sequential gates (real data-dependency edges — must be in this order):
docs/plans/<feature>.md) must be staged in Step 3 before commit. Step 2.4 is a micro-chain off Step 2 in the todo-list cluster (see below); its output is part of Step 3's fan-in union, identical in shape to the existing Step 2.9-integrator-edits → Step 3 staging edge.Todo-list (execute in any order, batch parallel where two independently read/write different files — with the Step 2→2.4 micro-chain exception noted below):
tasks/lessons.md). The 1→1.2 edge is real; run them sequentially as a unit; the pair parallelizes with the other slots.docs/plans/, tasks/<feature>/todo.md, etc.), then plan-doc reconciliation. The 2→2.4 edge is real: Step 2.4 reconciles the plan doc Step 2 just updated. Run them sequentially as a unit; the pair parallelizes with the other slots. Skip Step 2.4 if no governing plan exists.**Status:** fields)archive/completed/YYYY-MM/; internal chain 2.6.1→2.6.7 is real but isolated to this slot)These six slots touch disjoint surfaces. Among peer slots, none consumes another's output — where two slots operate on different paths, run them in the same response via parallel tool calls. Step 3 is a fan-in: it stages the union of all files touched by the cluster; peer ordering is irrelevant, only their position before Step 3 matters.
Read tasks/lessons.md (if it exists). If anything was learned this session that isn't already captured, add it — but apply the intake filter first.
Create on first use: If lessons exist to capture AND the file does not exist yet, create it with a # Lessons — [Project Name] header, a one-line purpose note, and the <!-- EM-maintained; see CLAUDE.md § Self-Improvement Loop --> comment, then append the entry. If no lessons to capture and the file doesn't exist, do not create it.
Feature scope: <feature> is derived from the current work context:
tasks/<feature>/todo.md, use that feature namefeature/<name> branch, use <name>tasks/lessons.md (global)Qualifies: user corrections, surprising API/tooling behavior, patterns that worked or failed, debugging insights. Doesn't qualify: one-off fixes, pipeline-run details, anything already in code/CLAUDE.md/MEMORY.md. Test: "Will this save time in the next 4 weeks?"
Format: bold title + 1-2 sentence rule, max 3 lines. Prefer merging with an existing entry. Skip if nothing new.
For each new lesson, ask: "Would this apply to any project type using the coordinator pipeline?" Autonomous self-classification; no review step.
[universal] on the bold title line; (b) append one-liner to ~/.claude/tasks/coordinator-improvement-queue.md: - YYYY-MM-DD | <source-repo> | tasks/lessons.md:<line> | <summary> | proposed target: <coordinator file>. Skip if that <source-file>:<line> already exists.Find and update relevant plan/task documentation to reflect what was completed:
tasks/<feature>/todo.md, tasks/plans/, docs/plans/, ~/.claude/plans/, tasks/todo.md/tasks/plan.md. If a plan exists for work this session touched, read and update it — sessions diving from handoffs often never explicitly opened the plan.Spec backlink:
archive/specs/2026-05-26-session-end-deviation-reconciliation-gate.md§ Goal, D1–D5.
Governing-plan predicate — fires only when a governing plan/spec exists (docs/plans/YYYY-MM-DD-<feature>.md, RFC, enriched stub, or handoff-body-as-live-spec). Negative-spec: if no governing plan exists, skip entirely. Do NOT invent a plan to reconcile against. No ceremony tax on plan-less sessions. → docs/wiki/ceremony-calibration.md.
Plan documents contain sections that /distill crystallizes into wiki entries (the ALLOWLIST). When what shipped diverged from the plan's forecast, correct these sections in the plan doc before the Step 3 commit so distill synthesizes shipped reality, not the stale forecast:
SHIPPED: <what-shipped> (was: <plan-forecast>). For decisions that shipped unchanged, no annotation is needed.SHIPPED: <actual-signature> (was: <planned-signature>).ID | Criterion | Test | Binding-Class | Status) are consumed by check-acceptance-oracle.sh. In-place correction of an AC table is scoped to the Status/note columns only (e.g. Status → shipped-differently with a note cell). Free-text mutation of the Criterion or Test cells would corrupt the structured oracle the parser expects. Substantive "what shipped vs forecast" delta routes to the ## Deviations table (below) and to the Decisions Made section — NOT a free-text edit of Criterion/Test cells.The (was: <plan-forecast>) annotation maps to distill's [SUPERSEDED] nugget class — superseded provenance only; what crystallizes is the shipped reality.
## Deviations audit sectionAfter correcting ALLOWLIST sections, append the following section to the plan doc (or extend it if already present from an earlier partial session):
## Deviations
| deviation | reason | commit |
|-----------|--------|--------|
| <brief description of what diverged from the plan> | <why it diverged> | <commit sha or "pending"> |
One row per meaningful deviation. This section is provenance-only — it is not crystallized by /distill (it is dropped as [EPHEMERAL]). The essential deviation fact survives in the corrected ALLOWLIST sections' (was: …) annotations; the verbose reasons live here and in git history.
Step 2.9's spec-completion lens is a soft input to this step, not a hard predecessor — Step 2.4 reconciles what the EM knows from session context. If Step 2.9 surfaces additional drift, fold those findings before Step 3. Two write-back types: Step 2.4 performs forecast→reality corrections; Step 2.9's integrator path performs defect-fix write-backs. Both fan into Step 3's staging union.
End of session is the last chance to ensure status fields match reality. This catches work that completed but whose status wasn't updated — common after compaction or rapid context shifts.
**Status:** fields in docs/active/, docs/plans/, or similar), verify their status reflects what actually happened:
docs/plans/consolidated-execution-tracker.md), verify that chunks worked on this session have accurate status entriesSweep the session's commits for completed work that isn't already in the project tracker (docs/project-tracker.md) or the per-entry completion archive under archive/completed/. This catches bug fixes, ad-hoc requests, and quick tasks that bypassed the spec pipeline.
Skip if no archive/ directory exists and no docs/project-tracker.md exists — the project hasn't adopted unified tracking yet.
git log --oneline for commits since session start. For each substantive commit (skip merges, doc-only, quick-saves), check if already represented in the tracker or archive/completed/YYYY-MM/ (by SHA). Group related commits into one entry.
Before writing any per-entry file, check whether a legacy monolith file exists at archive/completed/YYYY-MM.md (i.e., directly at the root of archive/completed/, NOT under a YYYY-MM/ subdirectory). If found AND COORDINATOR_OVERRIDE_LEGACY_MONOLITH is not set to 1:
git mv archive/completed/YYYY-MM.md archive/completed/legacy/YYYY-MM.md
Create archive/completed/legacy/ if it does not exist. The git mv is idempotent — subsequent runs find no monolith-at-root and skip silently. If COORDINATOR_OVERRIDE_LEGACY_MONOLITH=1, skip the git mv (the EM has already handled migration manually).
(a) If a plan was touched this session (any file under docs/plans/ or tasks/*/todo.md), chain = that plan's filename stem (e.g., 2026-05-19-completion-log-phase1).
(b) Else if a handoff was picked up this session, chain = the handoff's filename stem.
(c) Else if a workstream slug appears in any handoff frontmatter consumed this session, chain = that slug.
(d) Else chain = null (omit from filename; write as archive/completed/YYYY-MM/YYYY-MM-DD-adhoc-<sid6>.md).
Nature is classified automatically — no interactive prompt. Dispatch a small Sonnet sub-call (~1 KB output) with:
git diff --name-only for this session's commits)git log --oneline for this session)Sonnet classifies to one of [roadmap | bugfix | tech-debt | infra] and returns a nature: value + one-sentence rationale. Tag the entry nature_inferred: true.
Interactive override: If COMPLETION_NATURE is set in the environment before invoking /workstream-complete, use that value as nature: directly and write nature_inferred: false. The env var bypasses the Sonnet dispatch entirely.
Why AUTO-INFER not interactive-prompt: workstream-complete fires in autonomous chains where no human is present; a skip-default would bias --where nature=<x> queries. See plan § Chunk 3 for full rationale.
$em_sid and derive <sid6>$em_sid sourcing (env-var-primary):
$em_sid is set in the environment, use it directly.$CLAUDE_CODE_SESSION_ID — the platform-injected session id (Claude Code ≥ ~2.1.150). Per-session and unclobberable by a sibling session, so it is authoritative..git/coordinator-sessions/.current-session-id (last-writer-wins sentinel — session-init.sh writes it on every SessionStart; only a fallback for old Claude Code, per docs/wiki/claude-code-platform-gotchas.md). If the sentinel read is ambiguous (flips between ids across reads), two sessions are live — do not trust it; the env var in step 2 is the answer.meta.json-based lookup — it is circular (you need $em_sid to find the directory containing meta.json).<sid6> = last 6 characters of the resolved $em_sid. If $em_sid cannot be resolved, generate a 6-char hex fallback from the current timestamp (date +%s | tail -c 7 | head -c 6).
The <sid6> suffix ensures uniqueness per session with no race condition.
Behavioral rule (tripwire): Workstream-complete MUST invoke
coordinator-session-loe.sh(oraggregate-chain-loe.shfor chain-terminal) to write per-session LoE into the completion entry. Skipping this step produces an incomplete entry that Phase 3 consumers and workweek-complete cannot query. No override mechanism; theloe:block is always written.
Determine whether this is a single-session or chain-terminal session using the same detection logic as Step 2.9 chain-end detection:
/pickup (no predecessor handoff consumed)./pickup AND is ending via /workstream-complete (not /handoff or /spinoff).Single-session path:
loe_block=$(~/.claude/plugins/coordinator/bin/coordinator-session-loe.sh \
--format yaml-frontmatter 2>/dev/null)
If the script is absent or returns non-zero, degrade gracefully: set loe_block to:
loe:
agent_dispatches: null
opus_dispatches: null
em_tokens: null
tshirt: null
Chain-terminal path:
Resolve the consumed predecessor handoff path (the handoff archived by Step 2.7 this session). Resolution order:
/pickup time.tasks/handoffs/archive/<YYYY-MM>/ for entries with consumed_by: <this session_id>.Then invoke the chain aggregator:
loe_block=$(~/.claude/plugins/coordinator/bin/aggregate-chain-loe.sh \
--terminal-handoff "<resolved-predecessor-path>" \
--format yaml-frontmatter 2>/dev/null)
If the script is absent or returns non-zero, degrade the same way as the single-session path. The resolved $loe_block is embedded into the completion entry frontmatter in Step 2.6.6.
For each untracked completed work item (or one entry if work is cohesive), write:
archive/completed/YYYY-MM/YYYY-MM-DD-<chain-slug>-<sid6>.md
(chain null → YYYY-MM-DD-adhoc-<sid6>.md). Create the YYYY-MM/ subdirectory if absent.
File shape:
---
title: "<Concise past-tense one-line description>"
created: YYYY-MM-DD
nature: <roadmap|bugfix|tech-debt|infra>
nature_inferred: <true|false>
chain: <chain-slug or null>
commits:
- <sha1>
- <sha2>
status: pending-release
chain_terminal: <true|false>
authored_by: <em_sid or null>
loe:
agent_dispatches: <N or null>
opus_dispatches: <N or null>
em_tokens: <N or null>
tshirt: <XS|S|M|L|XL|null>
# chain-terminal only — omit for single-session entries:
# chain_sessions: <N>
# chain_span_days: <N>
# chain_starting_handoff: <path>
---
<One paragraph prose summary: what shipped, key decisions, anything notable.>
Frontmatter field semantics:
nature_inferred: true when AUTO-INFER Sonnet path was used; false when COMPLETION_NATURE env var was set.chain_terminal: true when opened via /pickup and ending via /workstream-complete; false for single-session work.authored_by: is $em_sid if resolvable; null otherwise.status: pending-release for all new entries.loe: populated from Step 2.6.5a; chain-terminal sessions carry aggregate values + chain-summary fields from aggregate-chain-loe.sh; single-session entries carry only the four base fields. loe.tshirt null = script unavailable.No separate collision handling needed — <sid6> ensures uniqueness by construction.
Not every commit is a work item. Group related commits into a single archive entry. Skip trivial commits (typo fixes, formatting). If a session produced no substantive commits beyond doc/lesson housekeeping, no archive entry is needed — skip silently.
actionedWhen the session's work resolves a cross-repo memo in this repo's cross-repo/inbox/, flip status: open → actioned (with optional decision: line) so the inbox accurately reflects channel state.
Detection — non-automatable; prompt the EM (no reliable programmatic signal connects commits to memo resolution):
cross-repo/inbox/*.md in the current repo. Parse YAML frontmatter; filter to status: open (or absent → treat as open).N. <basename> — <title or first heading> (from: <from>, topic: <topic>). Then ask once, plain prose: "Any of these resolved this session? If yes, give me the numbers; I'll flip status: actioned and add a one-line decision: you dictate. (Type none if none.)"status: actioned and append decision: <PM-supplied line> to the frontmatter. Then sweep it out of the inbox: git mv cross-repo/inbox/<file> cross-repo/archive/<file>. Create cross-repo/archive/ if absent. Both the edit and the move fold into Step 3's commit.Out of scope here: sender side; memos the session created or moved; memos in cross-repo/archive/. Do NOT touch any other repo's cross-repo/.
Why here: batching at session close is cheaper than inline at resolution time.
Counterpart to Step 2.65, sender-side. If this session (or any earlier session in the chain) ran cross-repo-memo or made a doctrine-seeding direct write into a sibling repo, do NOT list those memos / seeds as "pending PM-relay" or "pending your action" in the Final Summary, in any Flag to PM: block, or in a follow-on /handoff body. The PM was handed the receiver path once at send time — that is the relay. The receiving repo's /workday-start Step 1.45 inbox surfacing is the canonical channel; staleness is already flagged there.
Why: sender-side knowledge of memo status decays fast; the receiver's inbox maintains it authoritatively. Trust the channel.
Banned phrasings: "PM-relays pending your action", "Cross-repo memo X awaiting relay", "doctrine-seed Y pending sibling-EM action." The only legitimate sender-side mention is at the moment the CLI runs; after that turn, the memo is the receiver's surface.
→ docs/wiki/cross-repo-communication.md § Don't re-nag the PM about already-sent memos.
When this session was opened with /pickup, the consumed handoff still lives in tasks/handoffs/ (mutation-only at pickup time). If this session is ending via /workstream-complete rather than /handoff, archive the predecessor now.
Detection: scan tasks/handoffs/*.md, read frontmatter consumed_by:. Resolve session id: $CLAUDE_CODE_SESSION_ID first; .git/coordinator-sessions/.current-session-id fallback. Zero matches → skip. One match → archive. Multiple matches → log to stderr and archive all.
Action: git mv tasks/handoffs/<file> archive/handoffs/<file>. Create archive/handoffs/ if absent. On git mv failure (already moved by a concurrent /handoff), log to stderr and continue. The move folds into the Step 3 commit.
No claim release call needed — cs_archive at Step 3.5 carries the entire session directory (including handoff-claims/) into .archive/. Skip entirely if exiting via /handoff — the two paths are mutually exclusive.
After Step 2.7, regenerate tasks/handoff-tracker.md:
node plugins/coordinator/bin/render-handoff-tracker.js
Skip silently if the script is absent or fails. Stage tasks/handoff-tracker.md in Step 3's scoped commit.
Update the documents that future sessions read for orientation — closing the read-write loop with /workstream-start and /workday-start.
Orientation cache (tasks/orientation_cache.md): Do not author the cache body. Do not patch sections. Do not re-derive content section-by-section. The cache schema (pipelines/workday-start-internals.md § 5.5) is owned by ceremony writers (/workday-start, /update-docs). /workstream-complete is a mid-session writer with a single, narrowly-scoped capability: pinboard append.
Pinboard rule (the only cache mutation permitted here): if this session surfaced something the next session start MUST see, and it would otherwise be lost (a transient surface gotcha; a critical blocker context; an environment-specific caveat that fooled this session and will fool the next), write exactly one line to ## Pinboard via the routine:
bash plugins/coordinator/bin/regenerate-orientation-cache.sh \
--invoker workstream-complete \
--pinboard "YYYY-MM-DD <writer-slug>: <one-line note>"
One-slot escape valve — a second write overwrites, not appends. Cleared at every ceremony regen. If you want to write more than one line, that's a wiki edit, handoff body, or lessons.md entry. If nothing pinboard-worthy, do nothing. If the cache file doesn't exist (ls tasks/orientation_cache.md before asserting), skip.
Project tracker (docs/project-tracker.md): If it exists and this session completed or progressed tracked items, update their status rows. Only touch rows this session affected — don't re-derive the whole tracker.
Action items (first match: ACTION-ITEMS.md, docs/active/ACTION-ITEMS.md, docs/ACTION-ITEMS.md): If one exists and this session resolved any listed items, check them off or remove them per the file's existing conventions.
Documentation index (docs/README.md): If it exists and this session created new guides, added research files, or completed plan documents, patch the relevant table. Only touch rows this session affected.
Concurrency note: Targeted patches only — safe with concurrent agents working on different items.
Assess whether this session's diff warrants a code review pass before committing. EM makes the call using the table below — this step is judgment, not ceremony.
Diff-shape table:
| Session shape | Default scale |
|---|---|
| Doc-only edits, lesson capture, no executor dispatched, no code touched | None |
| Single-file fix <50 LOC, no shared schema touched, no executor | None (but commit message names the change) |
| Any executor dispatched, OR >50 LOC code change, OR shared schema/seam touched | code-reviewer (Sonnet, locked — see agents/code-reviewer.md) |
| Chain-end (started with /pickup, ending without /handoff//spinoff) AND chain diff is non-trivial | code-reviewer on chain diff |
| Chain-end AND chain diff too large for a single reviewer (>500 LOC rough anchor, ≥3 segments, or multi-surface) | Partitioned code-reviewer dispatches — see § Partitioning large surfaces. Named reviewers (the Staff Engineer, personas) are for plans and architecture, not code output. Sonnet code-reviewer is the ceiling at workstream-complete |
Precedence rule: chain-end rows (4, 5) override workstream-complete rows (1, 2, 3) when both apply — the chain diff is the integration-risk artifact.
Anchored-ranges note: the numeric anchors (50 LOC, 500 LOC, ≥3 segments) are decision anchors, not hard thresholds — diff shape matters more than line count.
Partitioning large surfaces across multiple code-reviewer dispatches (row 5):
Fan out into parallel code-reviewer dispatches over coherent slices (by package boundary, concern, or directory cluster) — no lens-orthogonality manifest or synthesizer required. Mechanics:
code-reviewer prompt names its slice explicitly (paths or commit subset) and an "out of scope: the rest of the chain diff" line.coordinator:review-integrator per slice or collates and dispatches one integrator over the union.--reviewer code-reviewer; record partition shape in the wrap-up sentence.No named-reviewer escalation from code review. Code output review is Sonnet code-reviewer only — partition across slices as needed. Architectural findings from code-reviewer → tasks/lessons.md + surface to PM; do not escalate to a named reviewer within the code-review path.
The weekly /workweek-complete Step 7 merge-gate is a separate, independent ceremony — do not skip workstream-complete review and "surface to PM for workweek."
Anti-ceremony-bias tripwire (code-reviewer floor — both directions):
"Plan-time and post-implementation review catch different defect classes — complementary, not substitutional. If you're considering skipping
code-reviewerbecause the diff feels small or 'we already reviewed the plan' — run it.code-revieweris the floor on row-3+ sessions, not a negotiable add-on. If you're drafting a waiving-with-rationale sentence on a row-3+ session, the rationale is the tell. EM keeps waive authority on genuinely shallow row-3 diffs; the test is the diff shape, not the row number. →docs/wiki/workstream-complete-review.md§ why-post-implementation-review-is-not-redundant."
Chain-end detection:
$CLAUDE_CODE_SESSION_ID env var first (platform-injected, unclobberable); .git/coordinator-sessions/.current-session-id sentinel fallback only when the env var is empty./pickup AND ending without /handoff or /spinoff invocation this session.list-review-trail-records.sh (live AND archived — live-only glob misses prior-week reviews). Plan-level the Staff Engineer reviews are NOT trail records; a "the Staff Engineer reviewed the plan" handoff note does NOT satisfy the chain-end code-reviewer floor. No trail record covering the sha-range = unreviewed.Diff scope:
git log $(git merge-base origin/main HEAD)..HEADgit log $LAST_REVIEW_SHA..HEAD ($LAST_REVIEW_SHA = most-recent trail record via list-review-trail-records.sh | tail -1 whose sha_range head passes git merge-base --is-ancestor <sha> HEAD; iterate oldest to newest; fall back to session-start SHA if none passes).Dispatch: invoke coordinator:review-code Branch A.2 with the resolved diff scope.
Spec cross-reference (loop closure) — include in dispatch brief when a spec exists:
When work is governed by a spec/plan/stub, name the spec path in the code-reviewer dispatch brief and instruct it to apply the Spec completion lens (per agents/code-reviewer.md § Spec completion lens). Apply on row 3/4/5 sessions; omit on row 1/2. If multiple specs apply, name all of them; the reviewer treats the union as the completion oracle. When partitioning the diff (§ Partitioning large surfaces), name each reviewer's spec slice explicitly.
Negative-spec: if no spec governs this session, omit the spec section from the brief — do not invent one. No spec named ⇒ reviewer skips the lens entirely.
Findings disposition — fix everything, including nitpicks:
"If a finding is worth surfacing, it is worth fixing now. The diff is fresh, the EM has context, and the cost to fix at workstream-complete is a fraction of what it costs three weeks later in a debugging session. A reviewer verdict of
OKwith three 'below blocking threshold' observations is NOT a license to commit and move on — those observations are the review output, and they get fixed in this session before commit. This applies symmetrically across severities: P0/P1/P2/nitpick/observation/note/'consider' — all fold in viacoordinator:review-integratorbefore the marker-trail write. The only legitimate skip path is a real tradeoff (cost/value, scope/polish, architectural direction) that escalates to PM per § Reviewer findings — apply, don't ratify incoordinator/CLAUDE.md. 'Recorded below blocking threshold' in the EM's wrap-up sentence is the tell that this rule was skipped. Re-open the diff, fold the findings, then write the marker."
After integration, the trail's --verdict field still records the reviewer's original verdict (ok / warn / blocked) — verdict tracks what the reviewer found on the pre-fix diff, not what shipped. Downstream load-shedding consumes the verdict; the trail is not a fix-completion log.
Marker write: after review integration completes, invoke:
~/.claude/plugins/coordinator/bin/coordinator-write-review-trail.sh \
--sha-range <A..B> --reviewer <code-reviewer|patrik|code-reviewer+patrik|waived|ubt-compile> \
--scope <chain|session> --verdict <ok|warn|blocked|waived|pending> --diff-loc <N>
Negative-spec:
--reviewer waived --verdict waived. Greppable as verdict=waived.Staging discipline: files edited by coordinator:review-integrator must be staged via explicit path in Step 3 — not git add -A.
UBT pending-marker (UE plugin work only): If bin/check-ubt-build-fresh.sh exists in the cwd, invoke it in --mode pending. Captures the build verdict as a deferred record; resolution happens at /workday-complete Step 0c. This step is a no-op for non-UE repos (script absent) — the [ -x bin/<name>.sh ] pattern is the canonical convention for conditional UE-specific steps in coordinator skill bodies; future UE conditionals (clippy, etc.) follow this shape.
[ -x bin/check-ubt-build-fresh.sh ] && \
bin/check-ubt-build-fresh.sh --since "$(git merge-base origin/main HEAD 2>/dev/null || git rev-parse HEAD~1)" --mode pending
Fires on big workstreams — same trigger as Step 2.9 rows 3/4/5. Skip silently on row-1/row-2 trivial sessions.
Step 2.9 is the line-level lens; these are the cross-cutting lenses. Run as a quick self-check (not a reviewer dispatch unless a lens surfaces something needing depth):
machine-local/, installer scripts, sentinel files, registry entries, env config)? If yes, confirm the clean-install path reproduces it — local green tests are not evidence a fresh machine installs the work. → global CLAUDE.md § Install-surface completeness; docs/wiki/install-surface-completeness.md.docs/README.md, docs/wiki/, and any Atlas/narrative index. Confirm stale references are repointed (not duplicated). → CLAUDE.md § Documentation and Knowledge System.security-audit-worker / dep-cve-auditor reviewer-routed workers per CLAUDE.md § Reviewer-Routed Workers (fuller routing protocol: docs/wiki/reviewer-routed-workers.md) — do not self-assess novel auth/secret surfaces.Output shape: a short checklist in the Step 4 Final Summary — one line per lens, clear / <one-line finding + disposition>. Findings that are tradeoff-free corrections fold in this session (per CLAUDE.md § Reviewer findings — apply, don't ratify); real tradeoffs surface to PM. The lenses are an offer-shaped self-audit, not a blocking gate — but on a big workstream, "all clear" must be an affirmative statement, not a silent skip.
Pre-terminate dirty-tree gate (fail loud on unattributable files). Before the workstream-complete commit, run git status --porcelain and classify every dirty path. EOL phantoms are benign — never case (c): a file where git diff --quiet -- <path> exits 0 is a Git-for-Windows stat-staleness artifact (docs/wiki/concurrent-em-hazards.md § H23) — leave it untouched; swept by coordinator-renormalize-index at session start. Classify each remaining path:
scope: block, an active handoff, or a consumed_by: field in handoff frontmatter naming another session's id.git add -- <path> && git commit -m "chore: adopt orphaned WT change <path> — unattributed at workstream-complete".git stash push -u -m "orphaned-WT <YYYY-MM-DD> workstream-complete: <path> — left by unknown session" -- <path>. Name the stash so the next session can find and adjudicate it (per CLAUDE.md "Probe edits in git stash push -u / pop").The forbidden outcome is terminating with case-(c) files still dirty and unnamed. Orphan .tmp.<pid>.<nanos> files are a special case (Edit-tool atomic-write crash, per CLAUDE.md § Verifying Executor Output) — diff against target before deleting; do not stash them blind.
Note: This gate is inline (not a snippet) across all three session terminators (workstream-complete, handoff, workday-complete) because the per-surface variation (<terminating action>) is intentional — snippet-sync is for byte-identical text. → ceremony-calibration.md.
git add -A. Name each path explicitly: git add <path1> <path2> .... Typical set: tasks/lessons.md, docs/plans/<feature>.md (if Step 2.4 ran), archive/completed/YYYY-MM/<entry>.md, docs/project-tracker.md, action-items, docs/README.md, tasks/handoff-tracker.md (if Step 2.75 ran). Unfamiliar dirty files → Step 3.0 gate first; "leave alone" is only correct for case (b) named-owner files."workstream-complete quick-save". (The post-commit hook will auto-push on work/feature branches.)git log "origin/$(~/.claude/plugins/coordinator/bin/coordinator-current-branch)..HEAD" 2>/dev/nullgit push origin mainArchive this session's claim directory — required at both /workstream-complete and /handoff to avoid forcing the next concurrent EM into a 24h wait.
Run:
sid="${CLAUDE_CODE_SESSION_ID:-$(cat "$(git rev-parse --show-toplevel)/.git/coordinator-sessions/.current-session-id" 2>/dev/null)}" && \
source ~/.claude/plugins/coordinator/lib/coordinator-session.sh 2>/dev/null && \
cs_archive "$sid" 2>/dev/null || true
Idempotent. Failures are non-fatal (24h reaper is the safety net). Skip if session id can't be resolved or lib is unavailable. Prefer $CLAUDE_CODE_SESSION_ID; .current-session-id is last-writer-wins fallback only.
If this session executed an oracle-bearing plan (one that went through coordinator:review and carries a bindable ## Acceptance Criteria table with gate-bound rows) and any gate-bound ACs remain red or unrun, emit an offer-shaped notice before the final summary:
"You have unresolved acceptance tests in
<plan-path>: <count> red/unrun gate-bound AC(s). Runbash check-acceptance-oracle.sh <plan-path>before merging via/merging-to-main."
Never a hard block — teeth live at coordinator:merging-to-main Step 0. Advisory only. Skip silently if no oracle-bearing plan was involved or all gate-bound ACs are green.
Present a brief end-of-session summary:
## Session Complete
**Work done:** [1-2 sentence summary]
**Lessons captured:** [N new / none]
**Work archived:** [N items written to archive/completed/YYYY-MM/<filename>.md / none needed / project not using unified tracking]
**Docs updated:** [list of updated files]
**Orientation refreshed:** [orientation cache patched / tracker updated / action items checked off / nothing to update / no orientation docs exist]
**Pushed to remote:** [yes — branch name / no — reason]
Flag to PM: Explicitly note the push so they can verify nothing breaks for other consumers.
If $ARGUMENTS is provided, use it as context for what was accomplished this session.
tools
Orient session — preflight, load context, choose work
development
Triangulate plan-claim / code-reality / review oracles to classify each plan into DELIVERED+REVIEWED / DELIVERED-UNREVIEWED / PARTIAL / IN-FLIGHT / ABANDONED. Run after any crash or 'did we actually finish what we think we finished?' moment.
testing
Check for a published coordinator update and advise a preserve-by-default migration path — never a blind overwrite.
development
Rotational arch audit — scores systems, audits top-priority, packages spinoff candidates. Never edits code; updates Last-targeted-audit clock.