session-orchestrator 3.23.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/architecture/SKILL.md +18 -0
- package/.agents/skills/autopilot/SKILL.md +17 -0
- package/.agents/skills/bootstrap/SKILL.md +20 -0
- package/.agents/skills/brainstorm/SKILL.md +22 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +15 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +22 -0
- package/.agents/skills/debug/SKILL.md +22 -0
- package/.agents/skills/discovery/SKILL.md +20 -0
- package/.agents/skills/dispatcher/SKILL.md +15 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +18 -0
- package/.agents/skills/ecosystem-health/SKILL.md +20 -0
- package/.agents/skills/eli5/SKILL.md +20 -0
- package/.agents/skills/eval/SKILL.md +21 -0
- package/.agents/skills/evolve/SKILL.md +21 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +15 -0
- package/.agents/skills/gitlab-ops/SKILL.md +20 -0
- package/.agents/skills/gitlab-portfolio/SKILL.md +15 -0
- package/.agents/skills/grill/SKILL.md +22 -0
- package/.agents/skills/hook-development/SKILL.md +15 -0
- package/.agents/skills/mcp-builder/SKILL.md +15 -0
- package/.agents/skills/memory-cleanup/SKILL.md +21 -0
- package/.agents/skills/mode-selector/SKILL.md +17 -0
- package/.agents/skills/npm-publish/SKILL.md +16 -0
- package/.agents/skills/peekaboo-driver/SKILL.md +18 -0
- package/.agents/skills/persona-panel/SKILL.md +17 -0
- package/.agents/skills/plan/SKILL.md +20 -0
- package/.agents/skills/playwright-driver/SKILL.md +20 -0
- package/.agents/skills/quality-gates/SKILL.md +20 -0
- package/.agents/skills/reconcile/SKILL.md +21 -0
- package/.agents/skills/remote-offload/SKILL.md +20 -0
- package/.agents/skills/repo-audit/SKILL.md +16 -0
- package/.agents/skills/session-end/SKILL.md +20 -0
- package/.agents/skills/session-plan/SKILL.md +20 -0
- package/.agents/skills/session-start/SKILL.md +20 -0
- package/.agents/skills/spinout/SKILL.md +16 -0
- package/.agents/skills/sunset-review/SKILL.md +16 -0
- package/.agents/skills/test-runner/SKILL.md +20 -0
- package/.agents/skills/tmux-layout/SKILL.md +21 -0
- package/.agents/skills/using-orchestrator/SKILL.md +17 -0
- package/.agents/skills/vault-mirror/SKILL.md +15 -0
- package/.agents/skills/vault-sync/SKILL.md +15 -0
- package/.agents/skills/wave-executor/SKILL.md +20 -0
- package/.agents/skills/write-executable-plan/SKILL.md +22 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot.md +2 -2
- package/.cursor/commands/bootstrap.md +1 -1
- package/.cursor/commands/brainstorm.md +1 -1
- package/.cursor/commands/debug.md +1 -1
- package/.cursor/commands/discovery.md +1 -1
- package/.cursor/commands/dispatcher.md +2 -2
- package/.cursor/commands/eli5.md +2 -2
- package/.cursor/commands/eval.md +2 -2
- package/.cursor/commands/evolve.md +1 -1
- package/.cursor/commands/go.md +1 -1
- package/.cursor/commands/grill.md +2 -2
- package/.cursor/commands/memory-cleanup.md +2 -2
- package/.cursor/commands/persona-panel.md +1 -1
- package/.cursor/commands/plan.md +1 -1
- package/.cursor/commands/portfolio.md +1 -1
- package/.cursor/commands/reconcile.md +2 -2
- package/.cursor/commands/release.md +2 -2
- package/.cursor/commands/session.md +2 -2
- package/.cursor/commands/spinout.md +2 -2
- package/.cursor/commands/sunset-review.md +2 -2
- package/.cursor/commands/templates-ack.md +2 -2
- package/.cursor/commands/test.md +2 -2
- package/.cursor/skills/brainstorm/SKILL.md +1 -1
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/quality-gates/SKILL.md +1 -1
- package/.cursor/skills/remote-offload/SKILL.md +13 -0
- package/.orchestrator/policy/blocked-commands.json +121 -0
- package/.orchestrator/policy/ecosystem.schema.json +66 -0
- package/.orchestrator/policy/quality-gates.example.json +16 -0
- package/.orchestrator/policy/quality-gates.schema.json +38 -0
- package/.orchestrator/policy/templates-policy.json +27 -0
- package/.orchestrator/policy/test-profiles.json +47 -0
- package/AGENTS.md +225 -0
- package/CHANGELOG.md +1401 -0
- package/NOTICE +11 -6
- package/README.md +127 -92
- package/agents/db-specialist.md +0 -1
- package/agents/eval-judge.md +1 -1
- package/agents/skill-applied-judge.md +1 -1
- package/assets/wave-lifecycle.svg +98 -0
- package/commands/release.md +6 -3
- package/commands/session.md +18 -3
- package/docs/README.md +4 -0
- package/{agents/AGENTS.md → docs/agent-authoring.md} +19 -26
- package/docs/baseline.md +67 -0
- package/docs/ci-setup.md +249 -48
- package/docs/codex-setup.md +66 -22
- package/docs/components.md +37 -16
- package/docs/cursor-setup.md +6 -2
- package/docs/events-schema.md +51 -10
- package/docs/instruction-delivery.md +62 -0
- package/{agents/memory-proposal-collector.md → docs/memory-proposal-flow.md} +1 -8
- package/docs/migration-v4.md +341 -0
- package/docs/pi-setup.md +6 -1
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/rule-authoring.md +85 -19
- package/docs/scope-collision-guard.md +8 -8
- package/docs/session-config-reference.md +120 -61
- package/docs/session-config-template.md +40 -33
- package/docs/telemetry/telemetry-claims.md +11 -10
- package/docs/telemetry.md +187 -4
- package/docs/vault-docs-architecture.md +50 -11
- package/hooks/_lib/atomic-json.mjs +111 -0
- package/hooks/_lib/hook-import-set.json +1487 -0
- package/hooks/_lib/subagent-paths.mjs +143 -0
- package/hooks/_lib/subagent-transcript.mjs +562 -0
- package/hooks/config-protection.mjs +2 -2
- package/hooks/cwd-change-restore.mjs +11 -31
- package/hooks/enforce-commands.mjs +69 -0
- package/hooks/enforce-scope.mjs +35 -6
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +10 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +3 -3
- package/hooks/on-session-end.mjs +280 -14
- package/hooks/on-session-start.mjs +153 -4
- package/hooks/on-stop.mjs +371 -17
- package/hooks/operator-steer.mjs +2 -2
- package/hooks/post-bash-write-verify.mjs +189 -4
- package/hooks/post-edit-import-probe.mjs +344 -0
- package/hooks/post-subagent-discovery-validator.mjs +278 -392
- package/hooks/post-tool-batch-wave-signal.mjs +272 -44
- package/hooks/post-tool-failure-corrective-context.mjs +11 -34
- package/hooks/post-tooluse-frontend-slop.mjs +3 -3
- package/hooks/pre-bash-destructive-guard.mjs +39 -13
- package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
- package/hooks/skill-invocation-telemetry.mjs +17 -5
- package/hooks/subagent-telemetry.mjs +24 -30
- package/monitors/monitors.json +3 -3
- package/package.json +9 -1
- package/pi/prompts/session.md +2 -2
- package/plugin.json +27 -0
- package/scripts/autopilot.mjs +26 -12
- package/scripts/backfill-abandoned-sessions.mjs +130 -15
- package/scripts/backfill-learnings-from-vault.mjs +9 -3
- package/scripts/dialectic-deriver.mjs +73 -8
- package/scripts/emit-event.mjs +10 -2
- package/scripts/export-hw-learnings.mjs +113 -1
- package/scripts/generate-agents-skills.mjs +378 -0
- package/scripts/generate-cursor-adapter.mjs +45 -8
- package/scripts/generate-hook-import-set.mjs +249 -0
- package/scripts/lib/agent-status.mjs +13 -2
- package/scripts/lib/auq/parse.mjs +5 -29
- package/scripts/lib/auto-dialectic.mjs +68 -0
- package/scripts/lib/auto-dream.mjs +38 -36
- package/scripts/lib/autonomy/suitability.mjs +6 -0
- package/scripts/lib/autopilot/loop.mjs +2 -2
- package/scripts/lib/autopilot/worktree-pipeline.mjs +82 -6
- package/scripts/lib/build-live-signals.mjs +25 -22
- package/scripts/lib/ci-status-banner.mjs +220 -75
- package/scripts/lib/codex/plugin-contract.mjs +82 -6
- package/scripts/lib/cold-start-detector.mjs +23 -14
- package/scripts/lib/config/auto-dream.mjs +2 -1
- package/scripts/lib/config/block-header.mjs +63 -0
- package/scripts/lib/config/block-preprocess.mjs +177 -0
- package/scripts/lib/config/broken-window.mjs +2 -1
- package/scripts/lib/config/cold-start.mjs +2 -1
- package/scripts/lib/config/config-protection.mjs +22 -2
- package/scripts/lib/config/context-coverage.mjs +2 -1
- package/scripts/lib/config/cross-repo.mjs +2 -1
- package/scripts/lib/config/custom-phases.mjs +2 -1
- package/scripts/lib/config/dialectic.mjs +2 -1
- package/scripts/lib/config/discovery-validator.mjs +9 -3
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +24 -1
- package/scripts/lib/config/dispatcher-autonomy.mjs +2 -1
- package/scripts/lib/config/docs-orchestrator.mjs +2 -1
- package/scripts/lib/config/docs-staleness.mjs +2 -1
- package/scripts/lib/config/drift-check.mjs +2 -1
- package/scripts/lib/config/eval.mjs +2 -1
- package/scripts/lib/config/events-rotation.mjs +2 -1
- package/scripts/lib/config/evolve.mjs +8 -2
- package/scripts/lib/config/frontend-slop-hook.mjs +7 -3
- package/scripts/lib/config/gitlab-portfolio.mjs +2 -1
- package/scripts/lib/config/handover-gate.mjs +2 -1
- package/scripts/lib/config/health-endpoints.mjs +388 -0
- package/scripts/lib/config/issue-budget.mjs +2 -1
- package/scripts/lib/config/loop-guard.mjs +2 -1
- package/scripts/lib/config/memory.mjs +2 -1
- package/scripts/lib/config/moc-staleness.mjs +2 -1
- package/scripts/lib/config/persona-gate-wave.mjs +2 -1
- package/scripts/lib/config/private-config-dir.mjs +67 -0
- package/scripts/lib/config/reconcile.mjs +2 -1
- package/scripts/lib/config/remote-hosts.mjs +234 -0
- package/scripts/lib/config/section-extractor.mjs +7 -1
- package/scripts/lib/config/skill-evolution.mjs +2 -1
- package/scripts/lib/config/slopcheck.mjs +2 -1
- package/scripts/lib/config/state-md-lock.mjs +2 -1
- package/scripts/lib/config/templates-first.mjs +2 -1
- package/scripts/lib/config/test.mjs +2 -1
- package/scripts/lib/config/vault-integration.mjs +7 -1
- package/scripts/lib/config/vault-mirror-quality.mjs +2 -1
- package/scripts/lib/config/vault-staleness.mjs +2 -1
- package/scripts/lib/config/vault-sync.mjs +2 -1
- package/scripts/lib/config/verification-auto-fix.mjs +2 -1
- package/scripts/lib/config/wave-reviewers.mjs +2 -1
- package/scripts/lib/config/worktree-orphans.mjs +2 -1
- package/scripts/lib/config.mjs +31 -3
- package/scripts/lib/convergence-monitor.mjs +82 -16
- package/scripts/lib/dispatcher/enumerate.mjs +2 -17
- package/scripts/lib/dispatcher/rank.mjs +124 -48
- package/scripts/lib/ecosystem-health.mjs +16 -2
- package/scripts/lib/eval/engine.mjs +9 -1
- package/scripts/lib/eval/session-resolve.mjs +23 -4
- package/scripts/lib/events-schema.mjs +48 -0
- package/scripts/lib/events.mjs +256 -7
- package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
- package/scripts/lib/frontmatter-guard.mjs +131 -13
- package/scripts/lib/gates/gate-full.mjs +26 -0
- package/scripts/lib/gates/gate-helpers.mjs +76 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
- package/scripts/lib/hardware-pattern-detector.mjs +18 -1
- package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
- package/scripts/lib/harness-audit/categories/category4.mjs +31 -11
- package/scripts/lib/host-identity.mjs +50 -11
- package/scripts/lib/instruction-budget-guard.mjs +171 -5
- package/scripts/lib/learnings/evolve-telemetry.mjs +178 -0
- package/scripts/lib/learnings/io.mjs +60 -6
- package/scripts/lib/memory-banner.mjs +20 -8
- package/scripts/lib/memory-proposals/store.mjs +30 -22
- package/scripts/lib/owner-config-banner.mjs +43 -6
- package/scripts/lib/owner-config-loader.mjs +21 -10
- package/scripts/lib/owner-interview.mjs +3 -3
- package/scripts/lib/owner-yaml.mjs +207 -14
- package/scripts/lib/peer-discovery.mjs +20 -2
- package/scripts/lib/platform.mjs +108 -15
- package/scripts/lib/plugin-update-banner.mjs +406 -0
- package/scripts/lib/project-hygiene.mjs +38 -2
- package/scripts/lib/qg-command-drift-banner.mjs +50 -12
- package/scripts/lib/quality-gate.mjs +133 -44
- package/scripts/lib/reconcile/emitter.mjs +68 -6
- package/scripts/lib/reconcile/engine.mjs +249 -9
- package/scripts/lib/reconcile/idempotency.mjs +37 -4
- package/scripts/lib/reconcile/writer.mjs +40 -18
- package/scripts/lib/scope-gate.mjs +36 -0
- package/scripts/lib/session-close-backfill.mjs +125 -18
- package/scripts/lib/session-discovery.mjs +57 -3
- package/scripts/lib/session-end/phase-skip.mjs +2 -2
- package/scripts/lib/session-id.mjs +12 -23
- package/scripts/lib/session-identity/own-session.mjs +187 -11
- package/scripts/lib/session-lock-shape.mjs +43 -0
- package/scripts/lib/session-lock.mjs +5 -10
- package/scripts/lib/session-registry.mjs +25 -9
- package/scripts/lib/session-schema/constants.mjs +36 -2
- package/scripts/lib/session-schema/validator.mjs +38 -4
- package/scripts/lib/session-start-probes.mjs +18 -1
- package/scripts/lib/session-transition.mjs +1 -1
- package/scripts/lib/sessions-canonical.mjs +446 -0
- package/scripts/lib/sessions-staleness-banner.mjs +18 -11
- package/scripts/lib/skill-health/join.mjs +17 -4
- package/scripts/lib/state-md.mjs +78 -0
- package/scripts/lib/sunset/walker.mjs +6 -0
- package/scripts/lib/telemetry/schema.mjs +255 -17
- package/scripts/lib/telemetry/sync.mjs +417 -24
- package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
- package/scripts/lib/validate/check-agents-skills.mjs +327 -0
- package/scripts/lib/validate/check-agents.mjs +3 -3
- package/scripts/lib/validate/check-cursor-adapter.mjs +234 -72
- package/scripts/lib/validate/check-doc-cli-commands.mjs +9 -33
- package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +45 -16
- package/scripts/lib/validate/check-owner-leakage.mjs +281 -20
- package/scripts/lib/validate/check-skill-links.mjs +163 -0
- package/scripts/lib/validate/check-skill-script-paths.mjs +455 -0
- package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
- package/scripts/lib/validate/check-unwired-features.mjs +0 -9
- package/scripts/lib/validate/check-validator-registration.mjs +254 -0
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
- package/scripts/lib/validate/enumerate-repo-files.mjs +317 -0
- package/scripts/lib/validate/markdown-fences.mjs +196 -0
- package/scripts/lib/vault-backfill/template.mjs +63 -6
- package/scripts/lib/vault-mirror/process.mjs +165 -42
- package/scripts/lib/vault-mirror/telemetry.mjs +2 -2
- package/scripts/lib/vault-status/board-lock.mjs +185 -0
- package/scripts/lib/vault-status/board-writer.mjs +174 -135
- package/scripts/lib/vault-status/narrative-mirror.mjs +129 -37
- package/scripts/lib/wave-executor/dispatch-common.mjs +164 -0
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +7 -142
- package/scripts/lib/wave-executor/remote-dispatch.mjs +502 -0
- package/scripts/lib/wave-resource-gate.mjs +133 -7
- package/scripts/lib/wave-sizing.mjs +4 -1
- package/scripts/lib/wave-transcript-tail.mjs +142 -8
- package/scripts/materialize-wave-scope.mjs +32 -9
- package/scripts/memory-propose.mjs +146 -8
- package/scripts/migrate-cold-start-seed.mjs +4 -1
- package/scripts/parse-config.mjs +60 -3
- package/scripts/promote-vault-strict.mjs +4 -15
- package/scripts/release.mjs +337 -29
- package/scripts/repair-invalid-sessions.mjs +3 -3
- package/scripts/run-quality-gate.mjs +128 -11
- package/scripts/site-numbers.mjs +36 -4
- package/scripts/sweep-expired-learnings.mjs +90 -0
- package/scripts/sync-vault-schema.mjs +3 -1
- package/scripts/telemetry.mjs +2 -2
- package/scripts/validate-plugin.mjs +187 -0
- package/scripts/validate-wave-scope.mjs +28 -8
- package/scripts/vault-consolidate.mjs +3 -11
- package/scripts/vault-integration-watcher.mjs +2 -4
- package/scripts/vault-mirror.mjs +111 -26
- package/scripts/wave-scope-binding.mjs +215 -0
- package/skills/_shared/instruction-file-resolution.md +10 -0
- package/skills/_shared/parallel-aware-auq.md +31 -2
- package/skills/_shared/parallel-aware-preamble.md +18 -4
- package/skills/_shared/platform-tools.md +1 -1
- package/skills/_shared/state-ownership.md +1 -1
- package/skills/architecture/SKILL.md +7 -5
- package/skills/{domain-model/SKILL.md → architecture/references/domain-model.md} +9 -9
- package/skills/autopilot/SKILL.md +4 -18
- package/skills/claude-md-drift-check/SKILL.md +5 -1
- package/skills/claude-md-drift-check/checker.mjs +62 -2
- package/skills/convergence-monitoring/SIGNALS.md +55 -0
- package/skills/discovery/probes/vault-staleness.mjs +37 -13
- package/skills/discovery/probes-arch.md +20 -18
- package/skills/dispatcher/SKILL.md +3 -2
- package/skills/ecosystem-health/SKILL.md +4 -1
- package/skills/ecosystem-health/wizard.md +5 -0
- package/skills/evolve/SKILL.md +87 -11
- package/skills/frontmatter-guard/SKILL.md +11 -5
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/reconcile/SKILL.md +38 -2
- package/skills/remote-offload/SKILL.md +89 -0
- package/skills/session-end/SKILL.md +18 -905
- package/skills/session-end/phase-3-6-tail.md +19 -9
- package/skills/session-end/plan-verification.md +221 -155
- package/skills/session-end/references/phase-2-quality-gate.md +93 -0
- package/skills/session-end/references/phase-3-documentation-updates.md +229 -0
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +120 -0
- package/skills/session-end/references/phase-4b-worktree-orphan-sweep.md +58 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +104 -0
- package/skills/session-end/references/session-summary-template.md +62 -0
- package/skills/session-plan/SKILL.md +49 -0
- package/skills/session-start/SKILL.md +41 -900
- package/skills/session-start/phase-8-5-express-path.md +1 -1
- package/skills/session-start/references/phase-1-1-dispatcher-autonomy-capture.md +55 -0
- package/skills/session-start/references/phase-1-2-session-lock.md +140 -0
- package/skills/session-start/references/phase-1-5-session-continuity.md +254 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +53 -0
- package/skills/session-start/references/phase-2-7-portfolio-snapshot.md +75 -0
- package/skills/session-start/references/phase-4-ssot-environment-check.md +155 -0
- package/skills/session-start/references/phase-6-5-forced-reads.md +75 -0
- package/skills/session-start/references/phase-6-6-project-intelligence.md +81 -0
- package/skills/session-start/references/phase-6-7-memory-banner-telemetry-consent.md +103 -0
- package/skills/vault-sync/validator.mjs +21 -27
- package/skills/wave-executor/SKILL.md +16 -2
- package/skills/wave-executor/references/wave-loop-dispatch.md +612 -0
- package/skills/wave-executor/references/wave-loop-review.md +570 -0
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +162 -0
- package/skills/wave-executor/wave-loop.md +14 -1271
- package/templates/_shared/journey-manifest.md +10 -6
- package/.cursor/commands/autopilot-multi.md +0 -14
- package/.cursor/commands/contract-version-bump.md +0 -14
- package/.cursor/commands/journey-audit.md +0 -14
- package/.cursor/skills/contract-version-bump/SKILL.md +0 -12
- package/.cursor/skills/daily/SKILL.md +0 -12
- package/.cursor/skills/domain-model/SKILL.md +0 -13
- package/.cursor/skills/journey-audit/SKILL.md +0 -13
- package/.cursor/skills/skill-creator/SKILL.md +0 -13
- package/.cursor/skills/ubiquitous-language/SKILL.md +0 -13
- package/commands/autopilot-multi.md +0 -74
- package/commands/contract-version-bump.md +0 -28
- package/commands/journey-audit.md +0 -43
- package/pi/prompts/autopilot-multi.md +0 -12
- package/pi/prompts/contract-version-bump.md +0 -12
- package/pi/prompts/journey-audit.md +0 -12
- package/scripts/autopilot-multi.mjs +0 -885
- package/scripts/backfill-learnings-expires.mjs +0 -196
- package/scripts/backfill-learnings.mjs +0 -203
- package/scripts/fleet-instruction-scan.mjs +0 -141
- package/scripts/lib/autopilot/dep-graph.mjs +0 -417
- package/scripts/lib/autopilot/multi-killswitch.mjs +0 -184
- package/scripts/lib/webhook-url.mjs +0 -105
- package/scripts/lifecycle-sim-v6.mjs +0 -347
- package/scripts/migrate-learnings-jsonl.mjs +0 -189
- package/scripts/migrate-subagents-jsonl.mjs +0 -196
- package/scripts/upload-social-preview.mjs +0 -316
- package/skills/_shared/model-selection.md +0 -64
- package/skills/contract-version-bump/SKILL.md +0 -219
- package/skills/daily/SKILL.md +0 -222
- package/skills/daily/generate.sh +0 -92
- package/skills/daily/templates/daily.md.tpl +0 -36
- package/skills/journey-audit/SKILL.md +0 -269
- package/skills/skill-creator/SKILL.md +0 -168
- package/skills/ubiquitous-language/SKILL.md +0 -97
- package/skills/vault-sync/package-lock.json +0 -40
- /package/skills/{domain-model → architecture/references}/ADR-FORMAT.md +0 -0
- /package/skills/{domain-model → architecture/references}/CONTEXT-FORMAT.md +0 -0
package/skills/evolve/SKILL.md
CHANGED
|
@@ -34,6 +34,8 @@ Do NOT proceed past Phase 0 if GATE_CLOSED. There is no bypass. Refer to `skills
|
|
|
34
34
|
|
|
35
35
|
## Phase 1: Config & Data Loading
|
|
36
36
|
|
|
37
|
+
**Telemetry start marker (#1200):** note the current wall-clock time before Step 1.1 runs (e.g. `date +%s%3N`, or the coordinator's own turn-start instant). Every `orchestrator.evolve.completed` emit in Phase 1 / Phase 3 below reports `duration_ms` (placeholder `DURATION_MS`) as the elapsed milliseconds since this marker — same in-memory-value convention as `CT`/`AC`/`ASK`/`DROP` in `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
|
|
38
|
+
|
|
37
39
|
### 1.1 Read Session Config
|
|
38
40
|
|
|
39
41
|
Read and parse Session Config per `skills/_shared/config-reading.md`. Store result as `$CONFIG`.
|
|
@@ -44,6 +46,13 @@ Extract `persistence` from `$CONFIG`. If `persistence` is `false`, abort with me
|
|
|
44
46
|
|
|
45
47
|
> "Learnings require persistence to be enabled in Session Config. Add `persistence: true` to your Session Config block (CLAUDE.md for Claude Code, AGENTS.md for Codex CLI)."
|
|
46
48
|
|
|
49
|
+
**Telemetry on abort (#1200, #1206):** before stopping, emit the abort form of the run-completion event. Kept as a minimal `emit-event.mjs` call, not routed through `scripts/sweep-expired-learnings.mjs` — no store-write CLI has run yet at this gate (it fires before Step 1.4 even reads `learnings.jsonl`), so there is no mechanical pipeline call site to fold this emit into, unlike the Step 3.5(5)/(6) success path below:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
|
|
53
|
+
"$(node -e "process.stdout.write(JSON.stringify({aborted: 'persistence-disabled', reason: 'Learnings require persistence to be enabled in Session Config.'.slice(0,300), duration_ms: DURATION_MS}))")"
|
|
54
|
+
```
|
|
55
|
+
|
|
47
56
|
### 1.3 Determine Mode
|
|
48
57
|
|
|
49
58
|
Read mode from `$ARGUMENTS`:
|
|
@@ -91,7 +100,12 @@ Extract learnings from session history.
|
|
|
91
100
|
- Read all entries from `.orchestrator/metrics/sessions.jsonl` (or `<state-dir>/metrics/sessions.jsonl` if the v2 path does not exist — see Phase 1.4 fallback)
|
|
92
101
|
- Parse each JSONL line as JSON
|
|
93
102
|
- Sort by `completed_at` descending (most recent first)
|
|
94
|
-
- If no sessions found, abort: "No session data available. Complete at least one session before running evolve."
|
|
103
|
+
- If no sessions found, abort: "No session data available. Complete at least one session before running evolve." **Telemetry on abort (#1200, #1206):** before stopping, emit — same minimal `emit-event.mjs` call as Phase 1.2's abort, and for the same reason: this gate fires before the Step 3.5(5) `sweep-expired-learnings.mjs --prune` call exists to fold the emit into:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
node scripts/emit-event.mjs --type orchestrator.evolve.completed --payload \
|
|
107
|
+
"$(node -e "process.stdout.write(JSON.stringify({aborted: 'no-session-data', reason: 'No session data available. Complete at least one session before running evolve.'.slice(0,300), duration_ms: DURATION_MS}))")"
|
|
108
|
+
```
|
|
95
109
|
|
|
96
110
|
### Step 3.1b: Read Extra Sources (#638)
|
|
97
111
|
|
|
@@ -167,7 +181,7 @@ For each of the 9 built-in analyzer learning types, apply these heuristics:
|
|
|
167
181
|
- Read `.orchestrator/metrics/events.jsonl` (session + wave events) and the registry `sweep.log` at `~/.config/session-orchestrator/sessions/sweep.log`. Both are optional — missing files produce no candidates.
|
|
168
182
|
- Invoke `scripts/lib/hardware-pattern-detector.mjs` → `detectHardwarePatterns({events, sweepLogEntries, thresholds})`. Thresholds come from Session Config `resource-thresholds` when present, falling back to `DEFAULT_THRESHOLDS`.
|
|
169
183
|
- Five detection signals (aggregated per `(signal, host_class)` pair, ≥2 occurrences required):
|
|
170
|
-
- **oom-kill** — `orchestrator.session.stopped` with `exit_code: 137` or OOM-marker in `error`
|
|
184
|
+
- **oom-kill** — `orchestrator.turn.stopped` (or its deprecated alias `orchestrator.session.stopped`, which `hooks/on-stop.mjs` still emits with `deprecated: true` until **2027-03-06**) with `exit_code: 137` or OOM-marker in `error`. Both names are accepted for the deprecation window because every OOM record already on disk carries only the legacy name; the detector's set lives in `OOM_TERMINAL_EVENTS` (`scripts/lib/hardware-pattern-detector.mjs`) and drops the alias on that date.
|
|
171
185
|
- **heartbeat-gap** — registry sweep-log entries with `gap_minutes` above `resource-thresholds.zombie-threshold-min`
|
|
172
186
|
- **concurrent-session-pressure** — session-start events with `peer_count ≥ concurrent-sessions-warn`
|
|
173
187
|
- **disk-full** — events whose `error` matches `ENOSPC` / "no space left"
|
|
@@ -302,22 +316,34 @@ For confirmed learnings, use atomic rewrite strategy:
|
|
|
302
316
|
Write the full next-generation entry set (existing entries **with** the step-2/3 confidence
|
|
303
317
|
updates, **plus** the step-4 new learnings) as JSONL to a temp sidecar **via the Write tool**
|
|
304
318
|
(not a shell `>` redirect — the destructive-command guard blocks it), then invoke the
|
|
305
|
-
`--prune` subcommand of the sweep CLI
|
|
319
|
+
`--prune` subcommand of the sweep CLI. **This call is also `/evolve`'s ONLY
|
|
320
|
+
`orchestrator.evolve.completed` success emit (#1206)** — export `N` (Step 3.5(4)'s
|
|
321
|
+
new-learnings count), `M` (Step 3.5(2)'s reinforced-existing count) and `DURATION_MS`
|
|
322
|
+
(elapsed ms since the Phase 1 marker) as real shell variables before running this line;
|
|
323
|
+
`${N:-0}`-style expansion means an un-exported variable degrades to a safe `0` rather than
|
|
324
|
+
an argument error:
|
|
306
325
|
|
|
307
326
|
```bash
|
|
308
327
|
NEXT=".orchestrator/metrics/.learnings-next.jsonl" # written by the step above
|
|
309
|
-
node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT"
|
|
328
|
+
node scripts/sweep-expired-learnings.mjs --prune --apply --json --entries "$NEXT" \
|
|
329
|
+
--appended "${N:-0}" --boosted "${M:-0}" --duration-ms "${DURATION_MS:-0}" \
|
|
330
|
+
--repo-root "$(pwd)" && rm -f "$NEXT"
|
|
310
331
|
```
|
|
311
332
|
|
|
312
333
|
`--file` / `--archive` default to the canonical store + archive paths — pass them only when
|
|
313
334
|
operating on a non-default pair. The command prints ONE JSON line; capture it as `$PRUNE` and
|
|
314
|
-
report its `{scanned, kept, archived, byReason}` in the final summary
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
>
|
|
335
|
+
report its `{scanned, kept, archived, byReason}` in the final summary — `$PRUNE.archived` is
|
|
336
|
+
also the `pruned` counter the emit above just wrote, so there is nothing left to compute for
|
|
337
|
+
the telemetry after this line. Preview first with `--prune --dry-run --json` (same counts,
|
|
338
|
+
zero writes, **no telemetry emit** — dry-run never claims a completed run) whenever the next
|
|
339
|
+
generation was hand-assembled.
|
|
340
|
+
|
|
341
|
+
> **This step is `/evolve`'s only store-write path, and (since #1206) its only
|
|
342
|
+
> `orchestrator.evolve.completed` success emit.** Until #1017 the store write lived here as
|
|
343
|
+
> an inline `node --input-type=module -e` block, and until #1206 the telemetry emit was a
|
|
344
|
+
> SEPARATE `emit-event.mjs` call further down this file — both were a mechanism hiding inside
|
|
345
|
+
> prose: no `--help`, no exit-code contract, no test, and (for the emit) forgettable
|
|
346
|
+
> independently of the write it reported on. Do not re-inline either, and do not hand-roll a
|
|
321
347
|
> `jq | ... > learnings.jsonl` pass — that bypasses every #721 safety net.
|
|
322
348
|
|
|
323
349
|
**Exit codes are the no-op rule.** `0` = applied (or a clean no-op). `1` = input error: the
|
|
@@ -380,6 +406,13 @@ For confirmed learnings, use atomic rewrite strategy:
|
|
|
380
406
|
|
|
381
407
|
Report: "Saved N new learnings, updated M existing. Total active: K."
|
|
382
408
|
|
|
409
|
+
**Telemetry (#1200, #1206):** already emitted by `scripts/sweep-expired-learnings.mjs --prune`
|
|
410
|
+
at Step 3.5(5) above — no separate action here. `appended`/`boosted`/`duration_ms` are whatever
|
|
411
|
+
`$N`/`$M`/`$DURATION_MS` carried into that call, and `pruned` is `$PRUNE.archived` (the sweep
|
|
412
|
+
CLI's own returned total). `promoted` is always `0` from THIS call site: promotion to `public`
|
|
413
|
+
scope is the separate `npm run share:hw-learnings -- --promote` CLI, never invoked by
|
|
414
|
+
`/evolve analyze` itself — see `docs/events-schema.md`.
|
|
415
|
+
|
|
383
416
|
### Step 3.6: C2 Auto-Repair Feeder (opt-in — #647)
|
|
384
417
|
|
|
385
418
|
> **Default OFF (advisory-only).** With no `skill-evolution:` block in Session Config, this step surfaces repair candidates as ADVICE only — it applies nothing and opens no MR. This mirrors the opt-in precedent of `slopcheck` (#520) and `verification-auto-fix` (#521): the engine is dark unless explicitly enabled.
|
|
@@ -542,6 +575,8 @@ N active learnings (M high confidence, K expiring soon)
|
|
|
542
575
|
|
|
543
576
|
Single-pass LLM derivation of USER.md + AGENT.md (peer cards from #503) updates from current learnings + sessions + steering files. Dry-run-default per #506 EARS contract.
|
|
544
577
|
|
|
578
|
+
**Telemetry start marker (#1200):** note the current wall-clock time at Phase 6 entry (`DURATION_MS` in the Step 6.4/6.5 emits below is the elapsed milliseconds since this marker) — same placeholder convention as `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
|
|
579
|
+
|
|
545
580
|
### Step 6.0: Argument Parsing
|
|
546
581
|
|
|
547
582
|
Parse `$ARGUMENTS` for trailing flags after the `dialectic` keyword:
|
|
@@ -603,6 +638,29 @@ const result = await runDialecticDeriver({
|
|
|
603
638
|
- If `--apply`: call `mergePeerCard(existingBody, managedUpdates)` from `scripts/lib/peer-cards/merger.mjs` for each card target, then `writePeerCard(repoRoot, 'user', mergedUserCard)` and `writePeerCard(repoRoot, 'agent', mergedAgentCard)` from `scripts/lib/peer-cards/writer.mjs`. Update the `updated:` frontmatter.
|
|
604
639
|
- Report: `Dialectic-derived: M deltas to USER.md, N deltas to AGENT.md. Dry-run | Applied. Tokens: in=<X> out=<Y>.`
|
|
605
640
|
|
|
641
|
+
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs`, not skill prose.**
|
|
642
|
+
The dry-run branch needs no action here: `runDialecticDeriver()` already emitted the success
|
|
643
|
+
form (`mode: 'dry-run'`) internally at Step 6.2, using `countManagedSections(diff)` on the SAME
|
|
644
|
+
diff this step presents — in dry-run the diff IS the final artefact, so the event and the
|
|
645
|
+
artefact are computed from the same value. The **apply** branch is the one case that pipeline
|
|
646
|
+
cannot record on its own: the merge above happens here, one layer up, so call
|
|
647
|
+
`recordDialecticRun()` (the sibling export beside `emitEvolveCompleted` in
|
|
648
|
+
`scripts/lib/learnings/evolve-telemetry.mjs`) immediately after the `writePeerCard()` calls,
|
|
649
|
+
using each target's `mergePeerCard()` `stats` for the deltas:
|
|
650
|
+
|
|
651
|
+
```javascript
|
|
652
|
+
await recordDialecticRun({
|
|
653
|
+
repoRoot,
|
|
654
|
+
status: 'ok',
|
|
655
|
+
mode: 'apply',
|
|
656
|
+
userDeltas: userMergeStats.replaced + userMergeStats.appended,
|
|
657
|
+
agentDeltas: agentMergeStats.replaced + agentMergeStats.appended,
|
|
658
|
+
tokensIn: result.usage?.input_tokens,
|
|
659
|
+
tokensOut: result.usage?.output_tokens,
|
|
660
|
+
durationMs: DURATION_MS,
|
|
661
|
+
});
|
|
662
|
+
```
|
|
663
|
+
|
|
606
664
|
### Step 6.5: Error Handling
|
|
607
665
|
- `status: 'unknown-model'` → fail with clear error (already thrown by validateModel)
|
|
608
666
|
- `status: 'budget-exceeded'` → emit `{status:'budget-exceeded', used:N, budget:M}`, do NOT truncate
|
|
@@ -610,6 +668,24 @@ const result = await runDialecticDeriver({
|
|
|
610
668
|
- `status: 'empty-input'` → exit clean with message "dialectic: skipped (no input)"
|
|
611
669
|
- subagent crash → log ⚠, exit cleanly (do NOT write to `.orchestrator/dialectic-pending.md`)
|
|
612
670
|
|
|
671
|
+
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs` for THREE of the five
|
|
672
|
+
outcomes.** `budget-exceeded`, `would-empty-card`, and `empty-input` are `runDialecticDeriver()`
|
|
673
|
+
RETURN values, so the module records them itself, mechanically, at the exact return point —
|
|
674
|
+
nothing to do here for those three. The remaining two are THROWN, not returned, and can only be
|
|
675
|
+
caught one layer up:
|
|
676
|
+
|
|
677
|
+
- `unknown-model` — `validateModel()` throws synchronously before `runDialecticDeriver()` can
|
|
678
|
+
record anything about the call.
|
|
679
|
+
- `subagent-crash` — a `dispatchAgent`/`Agent()` failure propagates out of
|
|
680
|
+
`runDialecticDeriver()` uncaught (it has no status of its own for this case).
|
|
681
|
+
|
|
682
|
+
Catch both here and call the SAME `recordDialecticRun()` used in Step 6.4's apply branch,
|
|
683
|
+
passing the literal slug as `status` (the abort form: `{aborted: status, duration_ms}`):
|
|
684
|
+
|
|
685
|
+
```javascript
|
|
686
|
+
await recordDialecticRun({ repoRoot, status: 'unknown-model' /* or 'subagent-crash' */, durationMs: DURATION_MS });
|
|
687
|
+
```
|
|
688
|
+
|
|
613
689
|
Cross-reference: PRD #506 AC1-AC4 + EARS gates. Vault Integration: dialectic does NOT mirror to vault (#506 scope — peer cards are repo-local by design; vault mirror is for cross-repo sessions/learnings).
|
|
614
690
|
|
|
615
691
|
---
|
|
@@ -94,13 +94,19 @@ The output is stable across calls for the same schema version. Regenerate only w
|
|
|
94
94
|
|
|
95
95
|
## Schema Source Path
|
|
96
96
|
|
|
97
|
-
The canonical schema source is:
|
|
97
|
+
The canonical schema source is `packages/zod-schemas/src/vault-frontmatter.ts` inside a **projects-baseline** checkout. That checkout is **optional and private** — see [`docs/baseline.md`](../../docs/baseline.md) — so the path is RESOLVED, never hardcoded. `resolveSchemaSourcePath()` resolves it in two tiers and returns `null` when nothing resolves. When the EXPLICIT tier is set it is used **alone** — probing past a wrong explicit value would silently read a different baseline than the one named:
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
| Tier | Candidate | Set by |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| **explicit** (exclusive) | `<baseline-path>/packages/zod-schemas/src/vault-frontmatter.ts` | `SO_BASELINE_PATH` env, else `owner.yaml` `paths.baseline-path` (host-local, never committed) — via `resolveHostPath('baseline-path', …)` |
|
|
102
|
+
| convention 1 | `<repoRoot>/../projects-baseline/packages/…` | sibling-checkout convention, the same one `scripts/sync-vault-schema.mjs` uses |
|
|
103
|
+
| convention 2 | `~/Projects/projects-baseline/packages/…` | legacy default this module shipped with |
|
|
104
|
+
|
|
105
|
+
Before this was resolved, convention 2 was the ONLY path and it was hardcoded: on a host whose checkout lives anywhere else, `readVaultSchema()` returned `null` and `generateFrontmatterSnippet()` then died with `Cannot destructure property 'typeEnum' of 'schema' as it is undefined`.
|
|
106
|
+
|
|
107
|
+
`readVaultSchema()` reads the resolved file on every call unless the in-memory mtime cache is current. It returns `null` (no throw) when no candidate resolves or the file is unreadable.
|
|
102
108
|
|
|
103
|
-
`
|
|
109
|
+
**Degraded mode.** With `null`, `generateFrontmatterSnippet()` does not throw: it falls back to an in-module enum/field set mirroring `skills/vault-sync/validator.mjs` (this repo's own in-tree copy of the schema, and what `vault-sync` actually validates against) and writes ONE stderr WARN per process. `computeSchemaHash()` returns `null` in that state — never the SHA-256 of the empty string, which would look like a real measurement and compare equal across every baseline-less host.
|
|
104
110
|
|
|
105
111
|
The parsed output includes:
|
|
106
112
|
|
|
@@ -39,7 +39,7 @@ The script gates mechanics. These three are yours, and it will not make them for
|
|
|
39
39
|
|
|
40
40
|
**2. What a leak means when one is found.** A hit from the leakage gate is not a pattern to silence. Decide which of two it is: a real leak (fix `package.json` `files`, re-pack, re-check) or genuine over-matching (fix `LEAKAGE_PATTERNS` in `scripts/release.mjs` **with a test**). There is no third option, and neither is "publish anyway and clean it up in the next version" — an npm publish is not revocable, and unpublishing burns the version number permanently. Operator handling detail: `docs/distribution/npm-publish-checklist.md` § 3.
|
|
41
41
|
|
|
42
|
-
**3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit, a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
|
|
42
|
+
**3. When to abort instead of repair.** Abort — do not patch forward — when the failure is upstream of the target-confirmed npm receipt: a red preflight row, a lagging `github` mirror, CI not green on the exact commit **on either platform** (`--check` carries both `ci-green-on-head` for GitLab and `ci-green-on-head-github` for the mirror, whose macOS matrix leg has no GitLab equivalent), a dead token, or a publish that did not issue the target receipt. These are cheap to fix and re-run from the top. Repair-in-place is only appropriate *after* that receipt, where the version is already immutable: registry propagation, a missing GitHub release, or a lagging site deploy can be reconciled because npm already has the correct artifact. When `--publish` reports **Post-publish reconciliation required**, **do not rerun `--publish`**; repair the listed state directly. `commands/release.md` § Abort criteria is the operative list.
|
|
43
43
|
|
|
44
44
|
## Failure-mode table
|
|
45
45
|
|
|
@@ -156,9 +156,9 @@ himself.
|
|
|
156
156
|
### 2.3 Invoke `runReconcile`
|
|
157
157
|
|
|
158
158
|
```javascript
|
|
159
|
-
import {
|
|
159
|
+
import { runReconcileFromSkill } from '$PLUGIN_ROOT/scripts/lib/reconcile/engine.mjs';
|
|
160
160
|
|
|
161
|
-
const { proposals, rejected, summary, error } = await
|
|
161
|
+
const { proposals, rejected, summary, error } = await runReconcileFromSkill({
|
|
162
162
|
repoRoot, // absolute path from git rev-parse --show-toplevel
|
|
163
163
|
ruleExpiryDays: RULE_EXPIRY_DAYS, // empty → undefined → engine per-type TTL
|
|
164
164
|
minRuleDays: MIN_RULE_DAYS, // default 7 — floors a near-dead expires-at
|
|
@@ -166,6 +166,9 @@ const { proposals, rejected, summary, error } = await runReconcile({
|
|
|
166
166
|
maxProposalsPerRun: MAX_PROPOSALS_PER_RUN, // default 10 — volume brake (issue #900 D)
|
|
167
167
|
now: new Date(),
|
|
168
168
|
dryRun: DRY_RUN, // true → engine touches no disk (no idempotency sidecar write)
|
|
169
|
+
// trigger is pinned to 'skill' IN CODE by runReconcileFromSkill (#1201 Part A) —
|
|
170
|
+
// this prose block no longer sets it.
|
|
171
|
+
targets, // from resolveEffectiveTargets above; recorded when non-empty, omitted otherwise
|
|
169
172
|
});
|
|
170
173
|
|
|
171
174
|
// The engine does NOT apply a confidence floor — it proposes every eligible
|
|
@@ -353,6 +356,39 @@ If `written === 0` and `approved.length === 0`:
|
|
|
353
356
|
|
|
354
357
|
---
|
|
355
358
|
|
|
359
|
+
## Consolidating and Dropping Generated Rules (merge contract)
|
|
360
|
+
|
|
361
|
+
`.claude/rules/` grows one file per approved learning, so it accumulates. This
|
|
362
|
+
repo consolidated 43 generated files (112,443 B, 46.2 % frontmatter+provenance
|
|
363
|
+
overhead) into 8 thematic files plus 10 drops on 2026-09-06. Both operations
|
|
364
|
+
are safe ONLY under the contract below — the full authoring spec is
|
|
365
|
+
[`docs/rule-authoring.md`](../../docs/rule-authoring.md) § "Consolidated rules:
|
|
366
|
+
N provenance pairs in ONE file". The three facts that decide whether a
|
|
367
|
+
consolidation survives the next `/reconcile`:
|
|
368
|
+
|
|
369
|
+
- **A target file may carry N provenance bullet PAIRS.** Frontmatter
|
|
370
|
+
`learning-key:` is a scalar, so at most one marker fits there; the other N−1
|
|
371
|
+
live in the body as `` - learning-key: `…` `` + `` - learning-id: `…` ``
|
|
372
|
+
bullets, which `engine.mjs` reads via `BODY_LEARNING_KEY_RE` /
|
|
373
|
+
`BODY_LEARNING_ID_RE`. One pair per absorbed learning — a missing pair
|
|
374
|
+
regenerates that learning as a standalone file on the next run.
|
|
375
|
+
- **A merged file's `expires-at` is the EARLIEST of its parts**, never the
|
|
376
|
+
latest: it must not outlive its shortest-lived content.
|
|
377
|
+
- **A dropped learning must be STAMPED before deletion, or it regenerates.**
|
|
378
|
+
`rm .claude/rules/<slug>.md` alone leaves `isProcessed()` false and no
|
|
379
|
+
on-disk marker, so the engine re-proposes it. Stamp it terminal first with
|
|
380
|
+
`markCandidateProcessed({ learningKey, outcome: 'rejected', fallbackSlug,
|
|
381
|
+
repoRoot })` from `scripts/lib/reconcile/idempotency.mjs` — the ONLY
|
|
382
|
+
sanctioned writer of `.orchestrator/runtime/reconcile-candidates.jsonl`
|
|
383
|
+
(never append to that file by hand; the read-side shape guard drops foreign
|
|
384
|
+
records and `mergeCandidates` rewrites the store in full).
|
|
385
|
+
|
|
386
|
+
**Verify a consolidation with a dry run**, not by eye: `alreadyMaterialized`
|
|
387
|
+
must equal absorbed + dropped. If it equals only the absorbed count, the drops
|
|
388
|
+
were not stamped and the next run will resurrect them. Do the whole operation
|
|
389
|
+
while `reconcile.enabled: false` in Session Config, so nothing regenerates
|
|
390
|
+
underneath you mid-edit.
|
|
391
|
+
|
|
356
392
|
## Critical Rules
|
|
357
393
|
|
|
358
394
|
- **NEVER** call `writeApprovedRules` before the operator has confirmed via AUQ — this is the
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remote-offload
|
|
3
|
+
user-invocable: false
|
|
4
|
+
tags: [reference, remote, offload, wave-executor, resource-gate]
|
|
5
|
+
model: haiku
|
|
6
|
+
model-preference: sonnet
|
|
7
|
+
model-preference-codex: gpt-5.4-mini
|
|
8
|
+
model-preference-cursor: claude-sonnet-4-6
|
|
9
|
+
description: Use when local resource pressure would shrink or coordinator-direct a wave, a wave plan carries heavy build/test/audit roles (test, ui, perf), or the operator says offload, remote host, or auslagern — reference for routing that wave role to a declared SSH-reachable host instead of reducing agent count
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Remote Offload — routing a wave role to a declared host instead of shrinking it
|
|
13
|
+
|
|
14
|
+
Repo-side half of #1160: `remote-hosts:` declares hosts, `wave-resource-gate.mjs` places work on them, `remote-dispatch.mjs` runs it. The host-side `offload` CLI (a separate baseline repo owns its SSOT) is invoked as a subprocess; this skill covers what the repo itself knows about it.
|
|
15
|
+
|
|
16
|
+
## Quick reference
|
|
17
|
+
|
|
18
|
+
| Task | Command |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Host readiness | `offload doctor -H <alias> --brief` |
|
|
21
|
+
| Gate (typecheck/lint/test) | `offload gate <repo> -H <alias>` |
|
|
22
|
+
| Run a command | `offload run <repo> -H <alias> -- <cmd...>` |
|
|
23
|
+
| Read-only analysis | `offload claude <repo> -H <alias> --model <name> < prompt.txt` |
|
|
24
|
+
| Implementation + patch | `offload claude <repo> -H <alias> --write --patch <path> < prompt.txt` |
|
|
25
|
+
| Remove finished jobs | `offload clean -H <alias> --older-than <hours>` |
|
|
26
|
+
|
|
27
|
+
Exit codes (`offload --help`, measured 2026-09-02): `0` ok · `1` usage/config · `2` host unreachable/not ready · `3` remote command failed · `4` sync failed · `5` timeout · `6` empty diff on a `--write` run · `7` account quota exhausted (429) · `8` write lock held. Same map as `OFFLOAD_EXIT_REASONS` in `scripts/lib/wave-executor/remote-dispatch.mjs`.
|
|
28
|
+
|
|
29
|
+
## 1. Decision rule — offload vs reduce
|
|
30
|
+
|
|
31
|
+
The gate decides, not the coordinator. `applyOffloadDecision()` in `scripts/lib/wave-resource-gate.mjs` only fires when the resource verdict is already `reduce` or `coordinator-direct`, and only AFTER the HR-004 heavy-repo cap — a capped wave that offloads still respects the cap. It never probes the network; the coordinator supplies a readiness WITNESS:
|
|
32
|
+
|
|
33
|
+
- `opts.remoteReady` — `{ [alias]: boolean }`, built from the SessionStart banner line `Offload <alias>: ready=yes …`, or
|
|
34
|
+
- `opts.probeFn` — an async `(alias) => boolean` fallback, consulted only for aliases `remoteReady` doesn't answer for (backed by `remoteDoctor()`, i.e. `offload doctor -H <alias> --brief` parsed by `parseDoctorLine()`).
|
|
35
|
+
|
|
36
|
+
With neither supplied, no host counts as ready and the wave stays local — the gate fails toward local, never toward an unverified host. A role in `NEVER_FOREIGN_ROLES` (`scripts/lib/wave-executor/dispatch-common.mjs`: `impl-core`, `security-review`, `migration`, `release`, `secrets`) is never offloaded regardless of readiness.
|
|
37
|
+
|
|
38
|
+
## 2. What is declared where
|
|
39
|
+
|
|
40
|
+
`remote-hosts:` in Session Config (`docs/session-config-reference.md` § Remote Hosts) declares the hosts, in preference order — the gate takes the FIRST host whose `roles-allowed` accepts the wave role and is witnessed ready:
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
remote-hosts:
|
|
44
|
+
- alias: <ssh-alias> # required, SAFE slug; reaches argv as `-H <alias>`
|
|
45
|
+
roles-allowed: [test, ui, perf] # subset of test|ui|perf (default: all three)
|
|
46
|
+
repo-path: ~/path/on/host # optional; SAFE path; default null
|
|
47
|
+
claude-path: ~/.local/bin/claude # optional; SAFE path; default null
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Two enums meet here and must not be conflated: `roles-allowed` holds `agent-mapping` roles (`test`/`ui`/`perf`), not wave roles (`Impl-Core`/`Quality`/…). The translation table is `OFFLOADABLE_WAVE_ROLES` in `wave-resource-gate.mjs` (`quality`→`test`, `test`→`test`, `ui`→`ui`, `perf`→`perf`; a wave role absent from that map stays local by default).
|
|
51
|
+
|
|
52
|
+
An `agent-mapping` entry of the form `<role>: ssh:<alias>` routes that wave role to Claude running ON the declared host instead of shrinking the wave; the alias must already exist under `remote-hosts`, or the config parse throws.
|
|
53
|
+
|
|
54
|
+
## 3. Three channels of work
|
|
55
|
+
|
|
56
|
+
| Channel | Command | Verdict rule |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| Gate / arbitrary command | `offload gate` / `offload run` | Exit code decides — use the table above, never the prose in the run's own output |
|
|
59
|
+
| Implementation, patch back | `offload claude --write --patch <file>` via `dispatchRemote()` | Empty patch (exit `6`) is a FAILURE regardless of what the run reports; the coordinator READS the patch, then applies it with its own `git apply` — the remote job never touches the repo the coordinator commits from |
|
|
60
|
+
| Read-only analysis | `offload claude` (no `--write`) | No patch is produced; treat the transcript as advisory input, same skepticism as any reviewer output (`receiving-review.md`) |
|
|
61
|
+
|
|
62
|
+
`dispatchRemote()` (`scripts/lib/wave-executor/remote-dispatch.mjs`) is the wave-executor caller for the second and third channels; it emits `orchestrator.remote_dispatch.completed` once per call (`docs/events-schema.md`) — the only ledger record a remote dispatch produces, since a Bash-spawned `offload` child fires no `SubagentStop` hook. Payload: `host`, `role`, `run_id`, `ok`, `exit_code`, `duration_ms`, `patch_files`, `patch_bytes`, `reason` (present on every refusal and every failure class — absence means success). Deliberately excluded from the payload: prompt text, patch body, `patch_path`.
|
|
63
|
+
|
|
64
|
+
## 4. Rules
|
|
65
|
+
|
|
66
|
+
- **Supervised, not blind.** Read the gate log or the patch before treating it as a result — completed and correct are not the same claim.
|
|
67
|
+
- **Prompt travels on stdin, never argv** (`offload --help`: "prompts travel by file (mode 600), never argv"; argv is visible to every process on the host).
|
|
68
|
+
- **The patch is READ, then applied by the coordinator** — never inside the offloaded job.
|
|
69
|
+
- **`never_foreign` roles are never offloaded** — checked first in `dispatchRemote()`, before any spawn or side effect.
|
|
70
|
+
- **One `--job` per concurrent run.** A job holds ONE set of run artefacts; two parallel runs sharing a job collided until per-run ids were introduced.
|
|
71
|
+
- **Rate-limit (exit `7`) carries the reset time in the message** — do not retry blind.
|
|
72
|
+
- **Secrets never in output** (SEC-008) — `offload` does not print credentials, and the module deliberately excludes prompt text and patch body from telemetry.
|
|
73
|
+
- **Never "clean up" another checkout on the host.** `offload clean` only removes the offload tool's OWN finished job worktrees, never a host's other active checkouts.
|
|
74
|
+
|
|
75
|
+
## 5. Host readiness checklist
|
|
76
|
+
|
|
77
|
+
- SSH alias configured with key auth (no password/interactive prompt on connect).
|
|
78
|
+
- `tmux` available on the host (for an interactive `offload session`).
|
|
79
|
+
- Claude authenticated ON the host — never copy OAuth credentials between machines (refresh-token rotation invalidates the source copy); log in fresh with `/login` there instead.
|
|
80
|
+
- Repo cloned on the host with headless git credentials configured (no interactive auth prompt on push/pull).
|
|
81
|
+
- Node version matching this repo's `.nvmrc`.
|
|
82
|
+
- Toolchain parity with the local checkout (same package manager, same lockfile).
|
|
83
|
+
|
|
84
|
+
## 6. Pitfalls measured in this repo
|
|
85
|
+
|
|
86
|
+
- **The pre-push quality gate used to fire on the sync push.** `.husky/pre-push` (#C10) detects a SCRATCH push — an unconfigured remote URL, e.g. the offload tool's own SSH sync target — and skips the gate for it; publish remotes (`origin`, `github`) stay gated regardless. The offload tool has since been fixed upstream to push with `--no-verify` itself, so this repo-side detection is defense-in-depth, not the primary fix.
|
|
87
|
+
- **The host installer must follow this repo's committed lockfile.** `package-lock.json` is tracked here (npm-canonical — `.claude/rules/development.md` § Package Management); install with `npm ci`, never a different package manager's install command, or the host checkout's `node_modules` layout diverges from CI's.
|
|
88
|
+
- **A linked worktree makes `.git` a file, not a directory.** 13 tracked files used to be flagged as "not in repository" in an unmodified worktree at the same layout, because the file form of `.git` was read as an untracked candidate rather than the repository marker — wave 3 fixed `scripts/lib/validate/check-untracked-test-deps.mjs` to treat a `.git` FILE as the repository marker in a linked worktree; the remote gate then ran 15,829/0.
|
|
89
|
+
- **Keychain-route auth shares the host account's usage window with that account's other interactive sessions**, not a dedicated quota — a token-slot profile (`--via slot`) avoids the sharing where a fixed quota matters.
|