AGENTS.md · git:20260925.a7b11a3 · 2026-09-25 · sha256 2a9c58aa95c7881c

AGENTS.md git:20260925.a7b11a3A

Immutable. This exact content never changes and is served at /api/v1/blob/2a9c58aa95c7881c.

# Session Orchestrator Plugin

> Project-instruction file resolution: this is `CLAUDE.md` on Claude Code / Cursor IDE; the equivalent file on Codex CLI is `AGENTS.md`. See [skills/_shared/instruction-file-resolution.md](skills/_shared/instruction-file-resolution.md).

> Lean root by design (Anthropic large-codebase best-practice: root = pointers + critical gotchas). Delegated docs:
> - **Install, CLI usage, architecture, component inventory** → [`README.md`](./README.md) (full inventory: [`docs/components.md`](./docs/components.md))
> - **Plugin ↔ private baseline relationship** (what degrades without it, the public fallback) → [`docs/baseline.md`](./docs/baseline.md)
> - **Sub-agent authoring spec** (frontmatter, body, `sandbox-tier`, `output-schema`) → [`docs/agent-authoring.md`](./docs/agent-authoring.md) (moved out of `agents/` in 4.0.0 — the plugin loader registers every `agents/*.md` by directory convention, and the spec was dispatched as an agent 5× fleet-wide)
> - **Stable product/tech/structure context** → [`.orchestrator/steering/`](./.orchestrator/steering/) (injected at session-start Phase 2.6)
> - **Always-on + path-scoped rules** → [`.claude/rules/`](./.claude/rules/) (per-wave via `rule-loader.mjs`, #336/#694); authoring spec → [`docs/rule-authoring.md`](./docs/rule-authoring.md)
> - **Decisions log** (hand-authored) → [[01-projects/session-orchestrator/decisions]] in the Meta-Vault
> - **Session narrative** (machine-written by session-end Phase 3.7 via `scripts/lib/vault-status/narrative-mirror.mjs`) → `01-projects/session-orchestrator/_session-narrative.md`
> - **Operator tmux side-channel** → `/tmux-layout` (4-pane: STATE.md/CI-watch/events; [ADR-0007](docs/adr/0007-tmux-visualization-substrate.md))
>
> **Root `AGENTS.md` is GENERATED byte-identical from this file** (`node scripts/generate-agents-skills.mjs`) for harnesses that read only `AGENTS.md` (Codex CLI, OpenCode, Kiro, Cursor's AGENTS path). Never edit it; edit here and regenerate. `validate-plugin` fails on drift.

## Current State <!-- consistency:exempt:lean-root-pointer-section -->

State-free by design (see the **Live state is not in this file** gotcha below) — SSOTs:
- **Version + test/coverage** → README badges
- **Per-session metrics & history** → [`.orchestrator/metrics/sessions.jsonl`](./.orchestrator/metrics/sessions.jsonl)
- **Decisions** (hand-authored) → [[01-projects/session-orchestrator/decisions]] (Meta-Vault) · **Session narrative** (generated) → `_session-narrative.md` beside it

## Critical Gotchas <!-- consistency:exempt:lean-root-pointer-section -->

These are the non-obvious, mistake-causing facts that must load every session. Everything else is delegated above.

- **CI status is the source of truth at session-start** — never claim CI green from `npm test` alone (8-pipeline silent regression 2026-05-09 → 2026-05-10, fixed in deep-2); Phase 4 🚨 banner `checkCiStatus({ repoRoot })` in `scripts/lib/ci-status-banner.mjs`; see `skills/session-start/references/phase-4-ssot-environment-check.md` (incident: ADR-0006). <!-- consistency:exempt:runtime-only -->
- **Destructive-Command Guard** (`hooks/pre-bash-destructive-guard.mjs`, `.orchestrator/policy/blocked-commands.json`: 12 block / 4 warn of 16 rules) is live on Claude Code + Cursor/Pi bridges, instruction-only on Codex. PSA-003 (`parallel-sessions.md`); bypass `allow-destructive-ops: true`; long form incl. #1401: `docs/session-config-reference.md`. <!-- consistency:exempt:runtime-only -->
- **Session Config below is runtime-critical.** `scripts/parse-config.mjs` parses the `## Session Config` block; `claude-md-drift-check` Check 6 enforces top-level-key parity against `docs/session-config-template.md`. Edit it like code, not prose — a dropped key changes runtime behaviour.
- **Live state is not in this file.** Stack: Node 24+, vitest, ESLint 10 (`npm ci` after clone). Test counts, backlog, version, component inventory drift fast — the SSOT is README badges + `.orchestrator/metrics/sessions.jsonl`. Per-session detail lives in the Meta-Vault decisions log (linked above), not here.
- **`memory.propose` requires `SO_WAVE_AGENT=1`** — `scripts/memory-propose.mjs` exits 3 from the coordinator thread (use `/evolve`); wave-executor sets it per dispatched agent. Statuses: queued 0 · dry-run-ok 0 · quota-exceeded 1 · rejected-low-confidence 2 · rejected-wrong-context 3 · error 4 — `docs/session-config-reference.md` § Memory Proposals. <!-- consistency:exempt:runtime-only -->
- **Auto-promoted worktree cleanup keys on the `.orchestrator/promoted-from.json` marker, not on session-id coincidence (#1069)** — promotion is a process boundary (ADR-0013), so `detectAutoPromotedWorktree()` tries the marker first (`source: 'marker'`) and falls back to the `<repo>-<sessionId>` basename only for pre-marker worktrees.
  `/close` Phase 4a runs AFTER Phase 4 commit+push (#490): clean → auto-remove with WARN, dirty → AUQ `[Behalten/Löschen/Manuell]`; Hybrid Pattern (Anthropic-style, ADR-0008), PSA-003. Long form: `skills/session-end/references/phase-4a-worktree-cleanup.md`. <!-- consistency:exempt:runtime-only -->
- **`allowedPaths` is COMPUTED, and the scope declaration has TWO shapes — writing only one is the silent failure (#1020).** (a) per-agent `<state-dir>/filescopes/wave-<N>/<agent-id>.json` (path strings = `$AGENT_FILESCOPE_JSON`: FILE-SCOPE injection, Learnings-Index, `--assert-subset`); (b) per-wave `{id, files}` records, the only input of `--assert-disjoint`/`--union`.
  `node scripts/materialize-wave-scope.mjs --state-dir <state-dir> --wave <N>` writes both; fold `coordinator.json` into (b). Skipping (a) = signal-free ALLOW (2026-08-19: six waves, ~27 dispatches, zero injection). Long form: `docs/scope-collision-guard.md` § The two-shape trap; `skills/wave-executor/references/wave-loop-scope-manifest.md` § 3.1/3.2. <!-- consistency:exempt:runtime-only -->
- **`vault-dir` resolves HOST-LOCALLY** (`SO_VAULT_DIR` > `owner.yaml` > committed `vault-integration.vault-dir`, `scripts/lib/config/host-paths.mjs`) — a hand-run vault writer with a synthetic `repoRoot` still writes into the REAL vault; export `SO_VAULT_DIR=<tmpdir>` before any manual invocation. Detail: `docs/session-config-reference.md` (#1448). <!-- consistency:exempt:runtime-only -->

## Session Config

persistence: true
enforcement: warn
agents-per-wave: 6 (deep: 18)
waves: 5
recent-commits: 20
test-command: npm test
typecheck-command: npm run typecheck
lint-command: npm run lint
stale-branch-days: 7
plugin-freshness-days: 30
plan-baseline-path: OVERRIDE-IN-owner.yaml   # placeholder, NOT a real path — resolve host-locally
plan-prd-location: docs/prd
plan-retro-location: docs/retro
plan-default-visibility: internal
vcs: gitlab
auto-skill-dispatch: false
vault-integration:
  enabled: true
  vault-dir: ~/Projects/vault
  mode: warn
  vault-name:
docs-orchestrator:
  enabled: false
  audiences: [user, dev, vault]
  mode: warn
vault-staleness:
  enabled: false
  thresholds:
    top: 30
    active: 60
    archived: 180
  mode: warn
docs-staleness:
  enabled: false
  thresholds:
    living: 90
  mode: warn
moc-staleness:
  enabled: false
  thresholds:
    moc: 90
  mode: warn
context-coverage:
  enabled: false
  mode: warn
worktree-orphans:
  enabled: false
  base-branch: main
  mode: warn
drift-check:
  enabled: true
  mode: warn
  check-docs-parity: true
wave-reviewers:
  enabled: false
  reviewers: []
  mode: warn
memory-cleanup-soft-limit: 180
vault-mirror:
  quality:
    min-narrative-chars: 400
    min-confidence: 0.5
memory:
  banner:
    enabled: true
  proposals:
    enabled: true
    quota-per-wave: 5
    confidence-floor: 0.5
auto-dream:
  min-confidence: 0.5
cold-start:
  enabled: true
  nudge-after-hours: 1
  silence-after-sessions: 1
state-md-lock:
  enabled: true
  timeout-ms: 10000
handover-gate:
  enabled: true
  max-open-questions: 3
issue-budget:
  max-per-session: 12
  mode: strict
  overflow: collect-issue
broken-window-budget:
  enabled: false
  due-days: 7
slopcheck:
  enabled: false
  sources: [plan, discovery]
templates-first:
  enabled: true
  hosts: [github, gitlab]
verification-auto-fix:
  enabled: false
  max-retries: 2
discovery-validator:
  enabled: false
frontend-slop-hook:
  enabled: false
loop-guard:
  enabled: true
  threshold: 3
  window: 5
instruction-budget:
  enabled: true
  ceiling: 480
  mode: warn
config-protection:
  enabled: true
  mode: warn
allow-config-weakening: false
custom-phases:
  - name: archive-closed-prds
    when: both
    command: node scripts/archive-closed-prds.mjs --apply
    mode: warn
  - name: archive-closed-plans
    when: both
    command: node scripts/archive-closed-prds.mjs --apply --prd-dir docs/plans --vault-subdir 01-projects/session-orchestrator/plans
    mode: warn
remote-hosts:
  - alias: m5
    roles-allowed: [test, ui, perf]
evolve:
  extra-sources: []
dialectic:
  cadence: 5
  model: haiku
  budget-tokens: 32000
eval:
  enabled: true
  mode: warn
  judge: off
  report: html
  handle:
reconcile:
  enabled: false
  mode: warn
  targets: [repo-local]
  rule-expiry-days: null
  confidence-floor: 0.5
  min-rule-days: 7
  min-insight-chars: 24

## Skill Evolution <!-- consistency:exempt:parity-exempt-skill-evolution-block -->

> Opt-in self-evolution autonomy gate (Epic #643). A DISTINCT top-level block from the `evolve:` Session Config key above — `scripts/lib/config/skill-evolution.mjs` parses it independently of the `## Session Config` boundary, so `claude-md-drift-check` Check 6 (session-config-parity) never flags it.
> See `docs/session-config-reference.md` § Skill Evolution for the #652 activation history, the C2/H1-guard detail, and the quadruple-gate + MR-only rules.

skill-evolution:
  autonomy: autonomous-gated      # off | advisory | autonomous-gated — armed (#652)
  evidence-floor: 0.5             # float 0.0..1.0 — min evidence before an autonomous-gated repair acts
  judge: off                      # opt-in session-end LLM-judge (advisory only); default off

## Dispatcher Autonomy <!-- consistency:exempt:parity-exempt-dispatcher-autonomy-block -->

> **Parity-exempt section** (Epic #673, #679). Intentionally OUTSIDE `## Session Config` so `claude-md-drift-check` Check-6 (session-config-parity) does not flag repos that have not adopted this feature — `scripts/lib/config/dispatcher-autonomy.mjs` parses it independently.
> This block's committed presence is itself the never-re-ask marker (session-start Phase 1.1 migration trigger). Effective autonomy resolves host-locally: env > `owner.yaml` > committed > `off`.
> See `docs/session-config-reference.md` § Dispatcher Autonomy for the #681 capture history and the full precedence chain.

dispatcher-autonomy:
  autonomy: off            # off | advisory | autonomous-gated — default off (fail-closed)
  confidence-floor: 0.5    # float 0.0..1.0