From session-orchestrator
Verifies session plan completion, creates issues for gaps and carryover work, runs quality gates and safety review, commits changes, mirrors to GitHub, generates summary. Use via /close.
npx claudepluginhub kanevry/session-orchestrator --plugin session-orchestratorThis skill uses the workspace's default tool permissions.
> **Platform Note:** State files (STATE.md, wave-scope.json) live in the platform's native directory: `.claude/` (Claude Code), `.codex/` (Codex CLI), or `.cursor/` (Cursor IDE). All references to `.claude/` below should use the platform's state directory. Shared metrics live in `.orchestrator/metrics/`. See `skills/_shared/platform-tools.md`.
Guides strict Test-Driven Development (TDD): write failing tests first for features, bugfixes, refactors before any production code. Enforces red-green-refactor cycle.
Guides systematic root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
Guides A/B test setup with mandatory gates for hypothesis validation, metrics definition, sample size calculation, and execution readiness checks.
Platform Note: State files (STATE.md, wave-scope.json) live in the platform's native directory:
.claude/(Claude Code),.codex/(Codex CLI), or.cursor/(Cursor IDE). All references to.claude/below should use the platform's state directory. Shared metrics live in.orchestrator/metrics/. Seeskills/_shared/platform-tools.md.
Read skills/_shared/bootstrap-gate.md and execute the gate check. If the gate is CLOSED, invoke skills/bootstrap/SKILL.md and wait for completion before proceeding. If the gate is OPEN, continue to Phase 1.
Read back the session plan that was agreed at the start. For EACH planned item:
[Carryover] <original task description>priority:<original>, status:readystatus:readyRead skills/session-end/discovery-scan.md for embedded discovery dispatch and findings triage.
Skip if
persistenceisfalsein Session Config (STATE.md won't exist).
Review safety metrics from the session. This is informational — it does NOT block the session close.
<state-dir>/STATE.md to extract:
PARTIAL), agents that spiraled (SPIRAL), agents that failed (FAILED)Safety review:
- Agents: [X] complete, [Y] partial (hit turn limit), [Z] spiral/failed
- Enforcement: [N] scope violations, [M] command blocks
- Isolation: [K] agents in worktrees, [J] fallbacks
SPIRAL or FAILED, ensure carryover issues exist (cross-reference with Phase 1.2)Read skills/session-end/metrics-collection.md for JSONL schema and conditional field rules.
Dispatch the session-reviewer agent to verify implementation quality before the quality gate:
On Codex CLI, dispatch via the
session-revieweragent role defined in.codex-plugin/agents/session-reviewer.toml.
subagent_type: "session-orchestrator:session-reviewer" with:
git diff --name-only against the base branch)Verification Reference: See
verification-checklist.mdin this skill directory for the full quality gate checklist.
Run ALL checks listed in the verification checklist. If any check fails: fix if quick (<2 min), otherwise create a priority:high issue. Do NOT commit broken code.
Read skills/session-end/vault-operations.md for validator bash contract and reporting matrix.
Read skills/session-end/drift-operations.md for checker bash contract and reporting matrix. Complements 2.1: vault-sync validates frontmatter inside the vault tree; drift-check validates narrative claims (paths, counts, issue refs, session-file refs) in top-level repo docs.
Skip this subsection if
vault-staleness.enabledis nottrue(default:false).
Read vault-staleness.mode from $CONFIG (default: warn). Valid values: off | warn | strict.
If mode === 'off', skip Phase 2.3 entirely.
Both probes already ship in skills/discovery/probes/. Invoke each via Node import (no shell-out):
import { runProbe as runStaleness } from '$REPO_ROOT/skills/discovery/probes/vault-staleness.mjs';
import { runProbe as runNarrative } from '$REPO_ROOT/skills/discovery/probes/vault-narrative-staleness.mjs';
const projectStaleness = await runStaleness(projectRoot, config);
const narrativeStaleness = await runNarrative(projectRoot, config);
Each probe returns { findings: Array, metrics: Object, duration_ms: Number } and auto-appends a JSONL summary record to its respective metrics file.
totalFindings = projectStaleness.findings.length + narrativeStaleness.findings.length
mode === 'warn' (default): report findings to closing report Docs Health line. Never block close.mode === 'strict':
totalFindings === 0: continue, log Vault staleness: clean (mode=strict).totalFindings > 0: BLOCK the close. Present the findings list and offer override:
## Deviations:
- [<ISO timestamp>] Phase 2.3: Vault staleness strict-mode findings overridden by user. Findings: <count> (projects: <N>, narratives: <M>).Pass the aggregated counts and mode forward to Phase 6 Final Report (Docs Health line — see Phase 6 below).
Delete <state-dir>/wave-scope.json if it still exists:
rm -f <state-dir>/wave-scope.json
This should have been cleaned up by wave-executor after the final wave, but crashed sessions or interrupted executions may leave it behind. A stale scope manifest from a previous session could incorrectly restrict the next session's enforcement hooks.
STATUS.md / STATE.md if they exist (metrics, dates, status)CLAUDE.md if patterns or conventions changed during this session<state-dir>/rules/ — if a new pattern was established, suggest a new rule fileSkip this subsection if
docs-orchestrator.enabledconfig is nottrue(default:false). Also skip entirely ifdocs-orchestrator.modeisoff.
Read docs-tasks from STATE.md frontmatter. This field is written by wave-executor Pre-Wave 1b when docs-orchestrator.enabled: true and session-plan emitted a ### Docs Tasks (machine-readable) block.
Use scripts/lib/state-md.mjs to parse the frontmatter safely — do NOT re-implement YAML parsing inline. Example accessor:
node --input-type=module -e "
import {readFileSync} from 'node:fs';
import {parseFrontmatter} from '${PLUGIN_ROOT}/scripts/lib/state-md.mjs';
const raw = readFileSync('<state-dir>/STATE.md', 'utf8');
const fm = parseFrontmatter(raw);
const tasks = fm['docs-tasks'];
if (!Array.isArray(tasks)) { process.stdout.write('ABSENT'); process.exit(0); }
process.stdout.write(JSON.stringify(tasks));
"
Fallback — missing field: If docs-tasks is absent from frontmatter, attempt to re-parse the session-plan output's ### Docs Tasks (machine-readable) YAML fenced block from conversation context. This is degraded but functional.
No tasks found at all: Log "ℹ docs-orchestrator enabled but no docs-tasks persisted — skipping verification" in the session report and skip Phase 3.2 entirely. This is NOT an error.
Silent-failure guard: If STATE.md is unreadable, if frontmatter YAML is malformed, or if docs-tasks is present but not a list — these MUST produce an explicit error entry in the session final report. Do NOT skip silently:
⚠ Phase 3.2: docs-tasks parse error — <reason>. Manual docs verification required.
Read session-start-ref from STATE.md frontmatter. Full accessor and fallback chain are documented in plan-verification.md § SESSION_START_REF accessor. Summary:
session-start-ref field in STATE.md frontmatter.git diff --name-only origin/main...HEAD (no specific base SHA).If git diff itself fails (network issue, corrupt repo), log:
⚠ Phase 3.2: git diff failed — <stderr>. Docs verification skipped.
and skip Phase 3.2. This is an explicit error, not a silent skip.
CHANGED_FILES=$(git diff --name-only "$SESSION_START_REF..HEAD")
Cache this list for the per-task loop below. If the command exits non-zero, surface the error per the guard above and skip Phase 3.2.
The following mini-table mirrors skills/docs-orchestrator/audience-mapping.md (authoritative source — consult it for updates):
| Audience | Target file patterns |
|---|---|
user | README.md, docs/user/**/*.md, docs/getting-started.md, examples/**/*.md |
dev | CLAUDE.md, docs/dev/**/*.md, docs/adr/**/*.md |
vault | <vault>/01-projects/<slug>/context.md, <vault>/01-projects/<slug>/decisions.md, <vault>/01-projects/<slug>/people.md |
Each docs-task carries its own target-pattern field (set during session-plan Step 1.8, derived from the audience-mapping table above). Use task.target-pattern as the primary match target; the table above is for human reference and fallback when target-pattern is absent.
For each task in docs-tasks:
Resolve target: glob-match task.target-pattern against the cached CHANGED_FILES list.
Not matched → GAP:
task.target-pattern appears in the diff.gap.Matched → inspect diff:
git diff "$SESSION_START_REF..HEAD" -- <matched-file>
ok.gap.<!-- REVIEW: source needed --> markers within changed regions: outcome partial. This means content was written but requires human review before release. partial does NOT block in strict mode — it is always a warning, by policy choice. Document both the ok content and the markers in the report.Record {id, audience, target-pattern, wave, status: ok|partial|gap} for the aggregate report.
Read docs-orchestrator.mode from Session Config (default: warn).
mode: warn (default, non-blocking):
/close proceeds regardless of gap count.mode: strict (blocking on any gap):
ok or partial: proceed — append report, continue close.gap:
AskUserQuestion with these options (mark Recommended):
Phase 3.2 found documentation gaps. How would you like to proceed?
1. Address gaps and retry Phase 3.2 (Recommended)
2. Override — close session with gaps (deviations logged)
3. Abort close
## Phase 3.2: Documentation Gaps Detected (mode=strict)
Choose one:
1. **Address gaps and retry Phase 3.2** *(Recommended)*
2. Override — close session with gaps (deviations will be logged)
3. Abort close
Gap tasks: <list task IDs and target-patterns>
## Deviations section of STATE.md:
- [Phase 3.2] docs-orchestrator strict-mode gaps overridden by user. Tasks: <ids>. Timestamp: <ISO 8601>.
Then append the report and proceed with close./close entirely. User must re-invoke.mode: off: This path is not reached because the Phase gate at the top of 3.2 exits early for mode: off. Documented here for completeness.
Emit the following block to be included in Phase 6 Final Report under ### Documentation Coverage (docs-orchestrator):
### Documentation Coverage (docs-orchestrator)
Mode: <warn|strict>
Tasks verified: <total>
| Task ID | Audience | Target pattern | Wave | Status |
|---------|----------|----------------|------|--------|
| <id> | <user|dev|vault> | <pattern> | <N> | ✅ ok / ⚠ partial / ❌ gap |
...
Summary: <N> ok, <N> partial (REVIEW markers present — human review needed before release), <N> gap
For partial tasks, append a note per task:
⚠ <target-pattern>: contains <!-- REVIEW: source needed --> markers — content written but not fully source-cited. Review before release.
For gap tasks in warn mode, append:
ℹ Gap tasks were not addressed. No docs-writer output found for these patterns. Consider scheduling in a follow-up session.
If this session made substantial changes, create or update:
<state-dir>/session-handover/ doc with: tasks completed, resume point, metrics changed, issues opened/closed<state-dir>/STATE.md with session digestReview <state-dir>/rules/ files that are relevant to this session's work:
Ownership Reference: See
skills/_shared/state-ownership.md. session-end is authorized to setstatus: completedplus the optionalupdatedtimestamp (#184) — no other fields.
Gate: Only run if
persistenceis enabled in Session Config and<state-dir>/STATE.mdexists.
status: completedupdated: <ISO 8601 UTC> in the frontmatter (issue #184). Use scripts/lib/state-md.mjs → touchUpdatedField for safety:
node --input-type=module -e "
import {readFileSync, writeFileSync} from 'node:fs';
import {touchUpdatedField} from '${PLUGIN_ROOT}/scripts/lib/state-md.mjs';
const p = '<state-dir>/STATE.md';
writeFileSync(p, touchUpdatedField(readFileSync(p, 'utf8'), new Date().toISOString()));
"
Silent no-op if the file has no frontmatter.If STATE.md doesn't exist, skip this subsection.
Pre-dispatch snapshots (refs/so-snapshots/<sessionId>/wave-*) are created by wave-executor before each wave dispatch so that session-start can offer recovery if a session is interrupted mid-wave. On a clean close those snapshots are no longer needed and should be deleted. In addition, orphaned refs from older sessions that were never cleaned up (e.g. after a hard crash) are garbage-collected using an age-based policy (14 days).
Gate: Only run if
persistenceistruein Session Config. Skip entirely when persistence is off (snapshots are never written in that mode).
node --input-type=module -e "
import { listSnapshots, deleteSnapshot, gcSnapshots } from '${PLUGIN_ROOT}/scripts/lib/coordinator-snapshot.mjs';
// Step A: delete this session's snapshots (clean close → we don't need them)
const mine = await listSnapshots({ sessionId: '${SESSION_ID}' });
for (const s of mine) {
const r = await deleteSnapshot({ refName: s.ref });
if (!r.ok) console.error('snapshot cleanup:', r.error);
}
// Step B: GC orphans older than 14 days (non-fatal)
const gc = await gcSnapshots({ olderThanDays: 14 });
console.log(\`snapshot cleanup: deleted \${mine.length} from this session + \${gc.deletedCount} expired orphans (scanned \${gc.scanned}).\`);
"
Failures in either step are logged to stderr but do not block session close — a missed cleanup is self-healing via the 14-day GC on the next session.
This cleanup is the counterpart to the session-start Phase 1.5 recovery prompt: once a session closes cleanly, future sessions must not be offered recovery for its snapshots.
Gate: Only run if
persistenceis enabled in Session Config AND platform is Claude Code (session memory at~/.claude/projects/is Claude Code-only). Learnings (Phase 3.5a) and metrics (Phase 3.7) still write to.orchestrator/metrics/on all platforms.
~/.claude/projects/<project>/memory/session-<YYYY-MM-DD>.md with:
name, description (1-line summary), type: project## Outcomes — per-issue status (completed / partial / not started) with evidence## Learnings — patterns discovered, architectural insights, gotchas## Next Session — priority recommendations, suggested session type, blockers~/.claude/projects/<project>/memory/MEMORY.md:
## Sessions heading (create if missing), add:
- [Session <date>](session-<date>.md) — <one-line summary>Read skills/session-end/learning-patterns.md for extraction heuristics, confidence updates, passive decay, and JSONL write procedure.
Read skills/session-end/session-metrics-write.md for JSONL append, vault-mirror invocation, and behavior matrix.
git add <file> — NEVER git add . or git add -A.orchestrator/metrics/sessions.jsonl (session summary from Phase 3.7).orchestrator/metrics/learnings.jsonl (learnings from Phase 3.6)<state-dir>/STATE.md (session state, if persistence enabled)git diff --cached — verify every change is from THIS sessionUse Conventional Commits format:
type(scope): description
- [bullet points of what changed]
- Closes #IID1, #IID2 (if applicable)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
For sessions with many changes, prefer ONE commit per logical unit (not one mega-commit).
git push origin HEAD
# Only attempt if 'mirror: github' is in Session Config AND remote exists
git remote get-url github 2>/dev/null && git push github HEAD 2>/dev/null || echo "GitHub mirror: not configured"
VCS Reference: Use CLI commands per the "Common CLI Commands" section of the gitlab-ops skill.
For each finding with severity critical or high from Phase 1.5:
Create a VCS issue using the detected platform CLI:
[Discovery] <description> (truncated to 70 chars)**Probe:** <probe>\n**File:** <file>:<line>\n**Severity:** <severity>\n**Confidence:** <confidence>%\n**Recommendation:** <recommendation>type:discovery, priority:<severity> (critical→critical, high→high)Log each created issue ID for the Final Report
Update discovery_stats.issues_created count
Create gap issues: for newly-discovered problems
Update milestones: if milestone progress changed
Present to the user:
## Session Summary
### Completed
- [x] Issue #N: [description] — [evidence: tests passing, files changed]
- [x] Issue #M: [description]
### Carried Over
- [ ] Issue #P: [what's left] — new issue #Q created
- [ ] [description] — blocked by [reason]
### New Issues Created
- #R: [title] (priority: [X], status: ready)
- #S: [title] (priority: [X], status: ready)
### Metrics
- Duration: [total wall-clock time]
- Waves: [N completed]
- Agents: [total dispatched] ([X complete, Y partial, Z failed])
- Files changed: [N]
- Per-wave breakdown:
- Wave 1 (Discovery): [duration] — [N agents] — [K files]
- Wave 2 (Impl-Core): [duration] — [N agents] — [K files]
- ...
- Tests: [passing/total]
- TypeScript: 0 errors
- Commits: [N] pushed to [branch]
- Mirror: [synced/skipped]
- Docs Health: Vault staleness — [render one of the three cases below based on Phase 2.3 result]
- Findings present (warn mode): `[N stale projects, M stale narratives] (mode=warn). See .orchestrator/metrics/vault-staleness.jsonl.`
- Skipped (disabled or mode=off): `skipped (disabled | mode=off).`
- Clean run: `clean (mode=<mode>).`
- Enforcement: [N violations blocked / M warnings] (or "N/A" if enforcement off)
- Circuit breaker: [N agents hit limits, M spirals detected] (or "none")
- Metrics written to: `.orchestrator/metrics/sessions.jsonl`
- Learnings: [N] new, [M] confirmed, [K] contradicted/expired — written to `.orchestrator/metrics/learnings.jsonl`
### Next Session Recommendations
- Priority: [what should be tackled next]
- Type: [housekeeping/feature/deep recommended]
- Notes: [any context for next session]
Documentation Coverage anchor: If Phase 3.2 ran and produced task verification results (i.e.
docs-orchestrator.enabled: trueanddocs-taskswere found), the results appear here as a### Documentation Coverage (docs-orchestrator)subsection emitted by Phase 3.2 Step 7. The content is written dynamically — it is not pre-populated in this template. Whendocs-orchestrator.enabledisfalseordocs-taskswere absent, this subsection is omitted entirely.
| File | Purpose |
|---|---|
plan-verification.md | Phase 1 plan verification and metrics collection |
verification-checklist.md | Phase 2 quality gate checklist and checks |
discovery-scan.md | Phase 1.5 embedded discovery dispatch and findings triage |
metrics-collection.md | Phase 1.7 JSONL schema and conditional field rules |
vault-operations.md | Phase 2.1 validator bash contract and reporting matrix |
drift-operations.md | Phase 2.2 drift-checker bash contract and reporting matrix |
learning-patterns.md | Phases 3.5a + 3.6 extraction heuristics, confidence updates, passive decay, and JSONL write procedure |
session-metrics-write.md | Phase 3.7 JSONL append, vault-mirror invocation, and behavior matrix |
git add . or git add -A — parallel sessions may have uncommitted work in the treegit add . — stage files individually to avoid capturing parallel session workgit diff --cached before committing — verify only YOUR changes are staged