Platform Note: State files use the platform's native directory:
.claude/(Claude Code),.codex/(Codex CLI), or.cursor/(Cursor IDE). Shared metrics live in.orchestrator/metrics/(v2) with fallback to<state-dir>/metrics/for pre-v2.0 legacy data. Seeskills/_shared/platform-tools.md.
Evolve Skill
Phase 0: Bootstrap Gate
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.
Phase 1: Config & Data Loading
1.1 Read Session Config
Read and parse Session Config per skills/_shared/config-reading.md. Store result as $CONFIG.
1.2 Check Persistence
Extract persistence from $CONFIG. If persistence is false, abort with message:
"Learnings require persistence to be enabled in Session Config. Add
persistence: trueto your Session Config block (CLAUDE.md for Claude Code, AGENTS.md for Codex CLI)."
1.3 Determine Mode
Read mode from $ARGUMENTS:
- If empty or not provided, default to
analyze - Valid modes:
analyze,review,list,dialectic - If invalid mode provided, report error and list valid modes
1.4 Load Data
Lazy-create defensive (#185): If .orchestrator/metrics/learnings.jsonl does not exist (pre-#185 repo or bootstrap skipped), create an empty file and emit an info log — do NOT hard-fail:
LEARNINGS_FILE=".orchestrator/metrics/learnings.jsonl"
if [[ ! -f "$LEARNINGS_FILE" ]]; then
mkdir -p "$(dirname "$LEARNINGS_FILE")"
: > "$LEARNINGS_FILE"
echo "info(#185): auto-created $LEARNINGS_FILE (was missing)" >&2
fi
This defensive step is idempotent and cheap — it ensures /evolve analyze|review|list never fails because of a missing artifact file.
- Read
.orchestrator/metrics/sessions.jsonl(session history). If it does not exist, check<state-dir>/metrics/sessions.jsonlas a legacy fallback (where<state-dir>is.claude/,.codex/, or.cursor/per platform). If neither exists, warn: "No session history found. Run at least one session first." - Read
.orchestrator/metrics/learnings.jsonlif it exists. If not found, check<state-dir>/metrics/learnings.jsonlas a legacy fallback. - Count existing learnings, note any where
expires_at< current date (expired)
Phase 2: Mode Dispatch
Route based on mode:
analyze→ Phase 3review→ Phase 4list→ Phase 5dialectic→ Phase 6
Phase 3: Analyze Mode (default)
Extract learnings from session history.
Vault Integration: If
vault-integration.enabledistruein Session Config, confirmed learnings are mirrored to the configured Obsidian vault after the atomic write (Step 3.5, step 9). Seedocs/session-config-reference.mdfor thevault-integrationconfig block.
Step 3.1: Read Session Data
- Read all entries from
.orchestrator/metrics/sessions.jsonl(or<state-dir>/metrics/sessions.jsonlif the v2 path does not exist — see Phase 1.4 fallback) - Parse each JSONL line as JSON
- Sort by
completed_atdescending (most recent first) - If no sessions found, abort: "No session data available. Complete at least one session before running evolve."
Step 3.2: Pattern Extraction
For each of the 8 learning types, apply these heuristics:
1. fragile-file (type: fragile-file)
- Look at wave data: if the same file appears in 3+ waves'
files_changedwithin a session, it is fragile - Cross-session: if a file appears in 3+ different sessions'
files_changed, flag it - Subject = file path (relative to project root)
2. effective-sizing (type: effective-sizing)
- Compare
total_agentsandtotal_wavesacross session types - Calculate average agents per wave for each session type
- Subject = canonical identifier like
deep-session-sizingorfeature-session-sizing - Insight = "Deep sessions average X agents across Y waves" or "Feature sessions work well with X agents/wave"
3. recurring-issue (type: recurring-issue)
- Look at
agent_summary— iffailedorpartial> 0 across multiple sessions, flag - Check wave
qualityfields — repeated failures indicate recurring issues - Subject = issue pattern identifier (e.g., "test-failures-in-wave-execution", "lint-regressions")
4. scope-guidance (type: scope-guidance)
- Cross-reference
effectiveness.planned_issuesvseffectiveness.completion_rate - Skip sessions that lack the
effectivenessfield (early sessions may not have it) - If completion_rate is consistently 1.0 with N issues, note "N issues per session works well"
- If completion_rate < 0.7, note "scope was too large"
- Subject =
optimal-scope-per-session-type
5. deviation-pattern (type: deviation-pattern)
Ownership Reference: See
skills/_shared/state-ownership.md. evolve has read-only access to STATE.md.
- Read
<state-dir>/STATE.mdif it exists and check## Deviationssection - Cross-reference with session duration vs planned waves
- Subject = pattern name (e.g., "scope-creep-in-feature-sessions", "underestimated-complexity")
6. stagnation-class-frequency (type: stagnation-class-frequency)
- Read
stagnation_eventsfrom the most recent 5 sessions insessions.jsonl(skip sessions lacking the field — they predate #84). - For each
(file, error_class)pair appearing in ≥2 sessions, extract a candidate:- Subject =
<file>:<error_class>(e.g.,skills/wave-executor/wave-loop.md:edit-format-friction) - Insight = "File <X> has <error_class> stagnation in <N> recent sessions — candidate for pre-edit grounding (#85)."
- Evidence = "<N> sessions with stagnation_events for this file/class"
- Subject =
- These learnings feed #85 (pre-edit grounding injection) when it ships — high-frequency pairs trigger grounding.
7. hardware-pattern (type: hardware-pattern)
v3.1.0 / Sub-Epic #160 (C2, issue #171). Keyed on
host_classrather than project — surfaces hardware-bound problems that affect the user across every repo on the same machine. Complements the project-keyed types above.
- Read
.orchestrator/metrics/events.jsonl(session + wave events) and the registrysweep.logat~/.config/session-orchestrator/sessions/sweep.log. Both are optional — missing files produce no candidates. - Invoke
scripts/lib/hardware-pattern-detector.mjs→detectHardwarePatterns({events, sweepLogEntries, thresholds}). Thresholds come from Session Configresource-thresholdswhen present, falling back toDEFAULT_THRESHOLDS. - Five detection signals (aggregated per
(signal, host_class)pair, ≥2 occurrences required):- oom-kill —
orchestrator.session.stoppedwithexit_code: 137or OOM-marker inerror - heartbeat-gap — registry sweep-log entries with
gap_minutesaboveresource-thresholds.zombie-threshold-min - concurrent-session-pressure — session-start events with
peer_count ≥ concurrent-sessions-warn - disk-full — events whose
errormatchesENOSPC/ "no space left" - thermal-throttle — events whose
resource_snapshot.cpu_load_pctcrossescpu-load-max-pct
- oom-kill —
- Each candidate is piped through
candidateToLearning()→validateLearning(). Defaultscopeisprivate(in-repo only). To promote topublic, the user runsnpm run share:hw-learnings -- --promote(C3 export). This anonymizes eachprivatehardware-pattern entry, validates via the privacy contract, and appends apublictwin tolearnings.jsonl(original preserved). Use--dry-runto preview without writing. - Subject convention:
<signal>::<host_class>(e.g.,oom-kill::macos-arm64-m3pro). The::separator avoids colliding with project-keyed subjects. - Confidence starts at 0.5 like other learning types, but decay is slower in practice: hardware stays