session-orchestrator 5.2.0 → 5.4.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 +3 -1
- package/.agents/skills/autopilot/SKILL.md +5 -1
- package/.agents/skills/autopilot/agents/openai.yaml +5 -0
- package/.agents/skills/bootstrap/SKILL.md +5 -1
- package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
- package/.agents/skills/brainstorm/SKILL.md +5 -1
- package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +4 -2
- package/.agents/skills/close/SKILL.md +5 -1
- package/.agents/skills/close/agents/openai.yaml +5 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
- package/.agents/skills/debug/SKILL.md +5 -1
- package/.agents/skills/debug/agents/openai.yaml +5 -0
- package/.agents/skills/discovery/SKILL.md +5 -1
- package/.agents/skills/discovery/agents/openai.yaml +5 -0
- package/.agents/skills/dispatcher/SKILL.md +5 -1
- package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ecosystem-health/SKILL.md +3 -1
- package/.agents/skills/eli5/SKILL.md +5 -1
- package/.agents/skills/eli5/agents/openai.yaml +5 -0
- package/.agents/skills/eval/SKILL.md +6 -2
- package/.agents/skills/eval/agents/openai.yaml +5 -0
- package/.agents/skills/evolve/SKILL.md +6 -2
- package/.agents/skills/evolve/agents/openai.yaml +5 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
- package/.agents/skills/gitlab-ops/SKILL.md +3 -1
- package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
- package/.agents/skills/go/SKILL.md +5 -1
- package/.agents/skills/go/agents/openai.yaml +5 -0
- package/.agents/skills/grill/SKILL.md +5 -1
- package/.agents/skills/grill/agents/openai.yaml +5 -0
- package/.agents/skills/harness-audit/SKILL.md +5 -1
- package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
- package/.agents/skills/hook-development/SKILL.md +3 -1
- package/.agents/skills/mcp-builder/SKILL.md +3 -1
- package/.agents/skills/memory-cleanup/SKILL.md +5 -1
- package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/mode-selector/SKILL.md +3 -1
- package/.agents/skills/navigator/SKILL.md +22 -0
- package/.agents/skills/navigator/agents/openai.yaml +5 -0
- package/.agents/skills/npm-publish/SKILL.md +4 -2
- package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
- package/.agents/skills/persona-panel/SKILL.md +5 -1
- package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
- package/.agents/skills/plan/SKILL.md +5 -1
- package/.agents/skills/plan/agents/openai.yaml +5 -0
- package/.agents/skills/playwright-driver/SKILL.md +3 -1
- package/.agents/skills/portfolio/SKILL.md +5 -1
- package/.agents/skills/portfolio/agents/openai.yaml +5 -0
- package/.agents/skills/quality-gates/SKILL.md +3 -1
- package/.agents/skills/reconcile/SKILL.md +5 -1
- package/.agents/skills/reconcile/agents/openai.yaml +5 -0
- package/.agents/skills/release/SKILL.md +5 -1
- package/.agents/skills/release/agents/openai.yaml +5 -0
- package/.agents/skills/remote-offload/SKILL.md +3 -1
- package/.agents/skills/repo-audit/SKILL.md +5 -1
- package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
- package/.agents/skills/session/SKILL.md +21 -0
- package/.agents/skills/session/agents/openai.yaml +5 -0
- package/.agents/skills/session-end/SKILL.md +3 -1
- package/.agents/skills/session-plan/SKILL.md +3 -1
- package/.agents/skills/session-start/SKILL.md +3 -1
- package/.agents/skills/spinout/SKILL.md +5 -1
- package/.agents/skills/spinout/agents/openai.yaml +5 -0
- package/.agents/skills/sunset-review/SKILL.md +5 -1
- package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
- package/.agents/skills/templates-ack/SKILL.md +21 -0
- package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
- package/.agents/skills/test/SKILL.md +5 -1
- package/.agents/skills/test/agents/openai.yaml +5 -0
- package/.agents/skills/test-audit/SKILL.md +21 -0
- package/.agents/skills/test-audit/agents/openai.yaml +5 -0
- package/.agents/skills/test-runner/SKILL.md +3 -1
- package/.agents/skills/tmux-layout/SKILL.md +3 -1
- package/.agents/skills/using-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ux-grill/SKILL.md +5 -1
- package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +3 -1
- package/.agents/skills/vault-sync/SKILL.md +3 -1
- package/.agents/skills/wave-executor/SKILL.md +3 -1
- package/.agents/skills/write-executable-plan/SKILL.md +3 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +4 -4
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -3
- package/.codex-plugin/skills/eval/SKILL.md +1 -1
- package/.codex-plugin/skills/evolve/SKILL.md +1 -1
- package/.codex-plugin/skills/navigator/SKILL.md +22 -0
- package/.codex-plugin/skills/{convergence-monitoring → navigator}/agents/openai.yaml +2 -2
- package/.codex-plugin/skills/npm-publish/SKILL.md +1 -3
- package/.codex-plugin/skills/session/SKILL.md +1 -1
- package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
- package/.codex-plugin/skills/{npm-publish → test-audit}/agents/openai.yaml +1 -1
- package/.cursor/commands/eval.md +1 -1
- package/.cursor/commands/navigator.md +15 -0
- package/.cursor/commands/session.md +1 -1
- package/.cursor/commands/test-audit.md +14 -0
- package/.cursor/rules/000-session-orchestrator.mdc +0 -2
- package/.cursor/rules/050-plan.mdc +1 -1
- package/.cursor/rules/060-evolve.mdc +27 -12
- package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/navigator/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +1 -0
- package/.cursor/skills/test-audit/SKILL.md +12 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +12 -3
- package/AGENTS.md +9 -30
- package/CHANGELOG.md +206 -0
- package/README.md +13 -9
- package/SECURITY.md +12 -0
- package/agents/dialectic-deriver.md +13 -10
- package/agents/eval-judge.md +67 -45
- package/agents/skill-applied-judge.md +34 -19
- package/commands/session.md +7 -3
- package/docs/agent-authoring.md +2 -2
- package/docs/baseline.md +22 -7
- package/docs/ci-setup.md +57 -4
- package/docs/codex-setup.md +14 -2
- package/docs/components.md +12 -10
- package/docs/events-schema.md +65 -15
- package/docs/persona-panel.md +5 -4
- package/docs/rule-authoring.md +84 -17
- package/docs/scope-collision-guard.md +26 -4
- package/docs/session-config-reference.md +154 -12
- package/docs/session-config-template.md +41 -3
- package/docs/telemetry.md +2 -0
- package/hooks/_lib/hook-import-set.json +87 -6
- package/hooks/_lib/subagent-transcript.mjs +582 -31
- package/hooks/config-protection.mjs +11 -3
- package/hooks/cwd-change-restore.mjs +11 -3
- package/hooks/enforce-commands.mjs +70 -23
- package/hooks/enforce-scope.mjs +143 -33
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +5 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +11 -3
- package/hooks/on-session-end.mjs +58 -23
- package/hooks/on-session-start.mjs +101 -11
- package/hooks/on-stop.mjs +170 -22
- package/hooks/operator-steer.mjs +11 -3
- package/hooks/post-bash-issue-budget-refund.mjs +18 -8
- package/hooks/post-bash-write-verify.mjs +3 -2
- package/hooks/post-edit-import-probe.mjs +17 -9
- package/hooks/post-edit-validate.mjs +13 -5
- package/hooks/post-subagent-discovery-validator.mjs +98 -13
- package/hooks/post-tool-batch-wave-signal.mjs +202 -38
- package/hooks/post-tool-failure-corrective-context.mjs +11 -5
- package/hooks/post-tooluse-frontend-slop.mjs +10 -4
- package/hooks/pre-auq-clarity.mjs +15 -2
- package/hooks/pre-bash-destructive-guard.mjs +80 -9
- package/hooks/pre-bash-issue-budget.mjs +16 -11
- package/hooks/pre-bash-memory-propose-audit.mjs +137 -56
- package/hooks/pre-bash-sessions-ledger-guard.mjs +419 -22
- package/hooks/pre-bash-staging-fence.mjs +335 -31
- package/hooks/pre-bash-templates-first.mjs +19 -14
- package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
- package/hooks/pre-task-scope-disjoint.mjs +792 -74
- package/hooks/subagent-telemetry.mjs +111 -38
- package/hooks/wave-scope-commit-guard.mjs +197 -100
- package/monitors/monitors.json +1 -1
- package/output-styles/wave-summary.md +1 -1
- package/package.json +3 -3
- package/pi/prompts/eval.md +1 -1
- package/pi/prompts/navigator.md +12 -0
- package/pi/prompts/session.md +1 -1
- package/pi/prompts/test-audit.md +12 -0
- package/rules/README.md +7 -2
- package/rules/_index.md +3 -3
- package/rules/always-on/bash-harness-pitfalls.md +7 -1
- package/rules/opt-in-domain/prompt-caching.md +6 -2
- package/rules/opt-in-stack/backend-data.md +10 -2
- package/rules/opt-in-stack/backend.md +10 -4
- package/rules/opt-in-stack/frontend.md +7 -2
- package/rules/opt-in-stack/security-web.md +10 -4
- package/rules/opt-in-stack/swift.md +6 -2
- package/scripts/apply-session-learnings.mjs +492 -0
- package/scripts/archive-closed-prds.mjs +2 -1
- package/scripts/autopilot.mjs +70 -53
- package/scripts/backfill-abandoned-sessions.mjs +118 -16
- package/scripts/baseline-archetypes.mjs +1 -1
- package/scripts/check-package-manager.mjs +62 -5
- package/scripts/check-sessions-integrity.mjs +300 -0
- package/scripts/cursor-install.mjs +1 -4
- package/scripts/dialectic-deriver.mjs +50 -13
- package/scripts/emit-session.mjs +371 -31
- package/scripts/eval-session.mjs +65 -3
- package/scripts/export-hw-learnings.mjs +22 -3
- package/scripts/fleet-checkin.mjs +147 -0
- package/scripts/generate-agents-skills.mjs +102 -29
- package/scripts/generate-cursor-adapter.mjs +61 -16
- package/scripts/lib/agent-frontmatter.mjs +3 -3
- package/scripts/lib/agent-status.mjs +2 -31
- package/scripts/lib/auq/clarity.mjs +10 -2
- package/scripts/lib/auq/parse.mjs +12 -31
- package/scripts/lib/auq/schema.mjs +56 -41
- package/scripts/lib/auto-dialectic.mjs +304 -15
- package/scripts/lib/auto-dream.mjs +7 -6
- package/scripts/lib/autopilot/flags.mjs +18 -2
- package/scripts/lib/autopilot/kill-switches.mjs +6 -3
- package/scripts/lib/autopilot/loop.mjs +19 -2
- package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
- package/scripts/lib/baseline-archetypes.mjs +41 -22
- package/scripts/lib/ci-status-banner.mjs +376 -16
- package/scripts/lib/command-blocker.mjs +275 -28
- package/scripts/lib/config/dialectic.mjs +12 -3
- package/scripts/lib/config/gate.mjs +74 -0
- package/scripts/lib/config/host-paths.mjs +79 -0
- package/scripts/lib/config/persona-gate-wave.mjs +3 -3
- package/scripts/lib/config/reaper.mjs +163 -0
- package/scripts/lib/config-schema.mjs +13 -0
- package/scripts/lib/config.mjs +85 -10
- package/scripts/lib/convergence-monitor.mjs +74 -11
- package/scripts/lib/ecosystem-health.mjs +11 -0
- package/scripts/lib/eval/engine.mjs +421 -53
- package/scripts/lib/eval/judge.mjs +463 -40
- package/scripts/lib/eval/schema.mjs +10 -1
- package/scripts/lib/events-rotation.mjs +221 -25
- package/scripts/lib/events-schema.mjs +114 -0
- package/scripts/lib/events.mjs +545 -7
- package/scripts/lib/fleet-protocol.mjs +270 -0
- package/scripts/lib/frontmatter-guard.mjs +21 -10
- package/scripts/lib/gates/gate-baseline.mjs +40 -5
- package/scripts/lib/gates/gate-full.mjs +35 -5
- package/scripts/lib/gates/gate-helpers.mjs +336 -23
- package/scripts/lib/gates/gate-incremental.mjs +49 -23
- package/scripts/lib/gates/gate-per-file.mjs +42 -8
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
- package/scripts/lib/instruction-budget-guard.mjs +208 -8
- package/scripts/lib/io.mjs +42 -8
- package/scripts/lib/issue-close-strip-labels.mjs +207 -49
- package/scripts/lib/js-mask.mjs +197 -0
- package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
- package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
- package/scripts/lib/learnings/io.mjs +154 -26
- package/scripts/lib/learnings/schema.mjs +163 -15
- package/scripts/lib/learnings/sizing-subject.mjs +2 -2
- package/scripts/lib/maintenance-due-banner.mjs +53 -88
- package/scripts/lib/memory-proposals/schema.mjs +11 -5
- package/scripts/lib/named-baseline-resolver.mjs +53 -28
- package/scripts/lib/named-vault-resolver.mjs +104 -5
- package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
- package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
- package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
- package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
- package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
- package/scripts/lib/orphan-reaper/scan.mjs +506 -0
- package/scripts/lib/orphan-reaper.mjs +316 -0
- package/scripts/lib/owner-yaml.mjs +104 -6
- package/scripts/lib/peer-cards/merger.mjs +48 -10
- package/scripts/lib/peer-cards/reader.mjs +78 -2
- package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
- package/scripts/lib/process-group.mjs +950 -0
- package/scripts/lib/project-hygiene.mjs +21 -1
- package/scripts/lib/quality-gate.mjs +152 -33
- package/scripts/lib/reconcile/backlog.mjs +368 -0
- package/scripts/lib/reconcile/engine.mjs +55 -188
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +302 -60
- package/scripts/lib/reconcile/sanitize.mjs +69 -3
- package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
- package/scripts/lib/resource-probe/parsers.mjs +31 -0
- package/scripts/lib/resource-probe.mjs +1 -1
- package/scripts/lib/rule-loader.mjs +141 -74
- package/scripts/lib/rules-sync.mjs +27 -12
- package/scripts/lib/scope-baseline.mjs +3 -4
- package/scripts/lib/scope-echo.mjs +39 -2
- package/scripts/lib/scope-gate.mjs +605 -1
- package/scripts/lib/session-close-backfill.mjs +33 -6
- package/scripts/lib/session-id.mjs +9 -20
- package/scripts/lib/session-invocation.mjs +20 -0
- package/scripts/lib/session-record-repair.mjs +183 -26
- package/scripts/lib/session-registry.mjs +27 -2
- package/scripts/lib/session-schema/constants.mjs +56 -2
- package/scripts/lib/session-schema/normalizer.mjs +56 -4
- package/scripts/lib/session-schema/validator.mjs +28 -1
- package/scripts/lib/session-schema.mjs +8 -3
- package/scripts/lib/session-start-probes.mjs +95 -10
- package/scripts/lib/session-token-rollup.mjs +245 -52
- package/scripts/lib/sessions-canonical.mjs +118 -4
- package/scripts/lib/sessions-integrity-banner.mjs +7 -1
- package/scripts/lib/sessions-staleness-banner.mjs +193 -51
- package/scripts/lib/sh-quote.mjs +29 -0
- package/scripts/lib/skill-evidence-window.mjs +891 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
- package/scripts/lib/skill-evolution/engine.mjs +18 -9
- package/scripts/lib/skill-judge.mjs +45 -3
- package/scripts/lib/subagents-schema.mjs +30 -3
- package/scripts/lib/tail-window.mjs +56 -0
- package/scripts/lib/telemetry/pricing.mjs +118 -71
- package/scripts/lib/telemetry/schema.mjs +30 -0
- package/scripts/lib/telemetry/sync.mjs +61 -6
- package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
- package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
- package/scripts/lib/tests-src-ratio.mjs +140 -23
- package/scripts/lib/tmux-layout/layouts.mjs +1 -11
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +72 -13
- package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
- package/scripts/lib/user-invocable-skills.mjs +23 -3
- package/scripts/lib/ux-grill/reconcile.mjs +48 -22
- package/scripts/lib/validate/check-agents-skills.mjs +26 -15
- package/scripts/lib/validate/check-agents.mjs +1 -1
- package/scripts/lib/validate/check-cursor-adapter.mjs +1 -0
- package/scripts/lib/validate/check-entry-guard.mjs +13 -50
- package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
- package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
- package/scripts/lib/validate/check-rules.mjs +7 -5
- package/scripts/lib/validate/check-skill-links.mjs +9 -1
- package/scripts/lib/validate/check-skill-script-paths.mjs +239 -27
- package/scripts/lib/validate/check-test-git-config-target.mjs +24 -34
- package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate/check-untracked-test-deps.mjs +7 -102
- package/scripts/lib/validate/check-unwired-features.mjs +130 -27
- package/scripts/lib/validate/check-validator-registration.mjs +34 -10
- package/scripts/lib/validate/confidential-names.mjs +10 -0
- package/scripts/lib/validate-vendored-rules.mjs +210 -84
- package/scripts/lib/vault-mirror/namespace.mjs +46 -8
- package/scripts/lib/vault-mirror/process.mjs +10 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
- package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
- package/scripts/lib/vault-status/board-writer.mjs +48 -11
- package/scripts/lib/vault-status/narrative-mirror.mjs +71 -16
- package/scripts/lib/vault-yaml.mjs +118 -0
- package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
- package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
- package/scripts/lib/wave-resource-gate.mjs +34 -8
- package/scripts/lib/worktree/lifecycle.mjs +153 -1
- package/scripts/memory-propose.mjs +18 -5
- package/scripts/release-session-lock.mjs +306 -0
- package/scripts/release.mjs +40 -8
- package/scripts/repair-invalid-sessions.mjs +37 -4
- package/scripts/resolve-session-invocation.mjs +59 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
- package/scripts/run-quality-gate.mjs +357 -197
- package/scripts/site-numbers.mjs +163 -5
- package/scripts/sweep-expired-learnings.mjs +56 -5
- package/scripts/sweep-expired-rules.mjs +16 -4
- package/scripts/validate-plugin.mjs +19 -0
- package/scripts/validate-wave-scope.mjs +32 -105
- package/scripts/vault-integration-watcher.mjs +2 -1
- package/scripts/vault-mirror.mjs +81 -47
- package/scripts/wave-scope-binding.mjs +2 -1
- package/skills/_shared/config-reading.md +3 -3
- package/skills/_shared/fleet-protocol.md +131 -0
- package/skills/_shared/platform-tools.md +23 -11
- package/skills/_shared/state-ownership.md +5 -0
- package/skills/autopilot/SKILL.md +47 -18
- package/skills/bootstrap/SKILL.md +1 -1
- package/skills/bootstrap/_shared-template.md +1 -1
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/bootstrap/private-contract.md +2 -1
- package/skills/bootstrap/public-fallback.md +6 -3
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
- package/skills/claude-md-drift-check/SKILL.md +10 -10
- package/skills/claude-md-drift-check/checker.mjs +26 -18
- package/skills/convergence-monitoring/README.md +8 -1
- package/skills/convergence-monitoring/SIGNALS.md +50 -6
- package/skills/convergence-monitoring/SKILL.md +15 -6
- package/skills/eval/SKILL.md +39 -24
- package/skills/eval/rubric-v1.md +1 -0
- package/skills/eval/rubric-v2.md +457 -0
- package/skills/evolve/SKILL.md +3 -3
- package/skills/evolve/references/evolve-analyze-mode.md +10 -6
- package/skills/evolve/references/evolve-dialectic-mode.md +42 -25
- package/skills/gitlab-ops/SKILL.md +3 -2
- package/skills/memory-cleanup/SKILL.md +1 -1
- package/skills/navigator/SKILL.md +193 -0
- package/skills/navigator/references/account-check.sh +87 -0
- package/skills/navigator/references/fleet-decisions.mjs +231 -0
- package/skills/navigator/references/slot-check.sh +114 -0
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/persona-panel/SKILL.md +2 -2
- package/skills/persona-panel/persona-format.md +2 -2
- package/skills/persona-panel/presets/designer-lens.md +1 -1
- package/skills/persona-panel/presets/engineer-lens.md +1 -1
- package/skills/persona-panel/presets/pm-lens.md +1 -1
- package/skills/plan/mode-retro.md +19 -4
- package/skills/quality-gates/SKILL.md +6 -4
- package/skills/reconcile/SKILL.md +11 -0
- package/skills/remote-offload/SKILL.md +4 -2
- package/skills/session-end/SKILL.md +13 -16
- package/skills/session-end/discovery-scan.md +1 -1
- package/skills/session-end/learning-patterns.md +22 -12
- package/skills/session-end/metrics-collection.md +5 -6
- package/skills/session-end/phase-3-6-tail.md +55 -9
- package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
- package/skills/session-end/references/session-summary-template.md +1 -1
- package/skills/session-end/session-metrics-write.md +32 -60
- package/skills/session-plan/SKILL.md +17 -8
- package/skills/session-plan/references/session-plan-task-classification.md +2 -2
- package/skills/session-start/SKILL.md +6 -0
- package/skills/session-start/references/operations-contract.md +4 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
- package/skills/test-audit/SKILL.md +152 -0
- package/skills/test-audit/references/campaign.md +111 -0
- package/skills/test-audit/references/mutate.sh +50 -0
- package/skills/ux-grill/SKILL.md +1 -1
- package/skills/wave-executor/SKILL.md +9 -5
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +8 -3
- package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
- package/skills/wave-executor/references/wave-loop-review.md +3 -5
- package/templates/personas/README.md +5 -5
- package/templates/personas/accounting-compliance.v1.md +1 -1
- package/templates/personas/accounting-tax-advisor.v1.md +1 -1
- package/templates/personas/buyer-p1-cto.v1.md +1 -1
- package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
- package/templates/personas/buyer-p3-build.v1.md +1 -1
- package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
- package/templates/personas/buyer-p5-solo.v1.md +1 -1
- package/templates/personas/buyer-p6-ld.v1.md +1 -1
- package/templates/personas/klima-ai-expert.v1.md +1 -1
- package/templates/personas/klima-physicist.v1.md +1 -1
- package/.cursor/commands/convergence-monitoring.md +0 -13
- package/.cursor/commands/npm-publish.md +0 -13
- package/pi/prompts/convergence-monitoring.md +0 -11
- package/pi/prompts/npm-publish.md +0 -11
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
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.
|
|
10
10
|
|
|
11
|
-
**Telemetry start marker (#1200):** note the current wall-clock time at Phase 6 entry (`DURATION_MS` in the Step 6.4
|
|
11
|
+
**Telemetry start marker (#1200):** note the current wall-clock time at Phase 6 entry (`DURATION_MS` in the Step 6.4 apply emit below is the elapsed milliseconds since this marker) — same placeholder convention as `skills/session-end/SKILL.md`'s `orchestrator.handover.gated` emits.
|
|
12
12
|
|
|
13
13
|
### Step 6.0: Argument Parsing
|
|
14
14
|
|
|
@@ -19,14 +19,14 @@ Parse `$ARGUMENTS` for trailing flags after the `dialectic` keyword:
|
|
|
19
19
|
| `--apply` | `false` | Write diff to USER.md/AGENT.md via merger.mjs; without it = dry-run |
|
|
20
20
|
| `--dry-run` | `true` | Explicit dry-run (default); mutually exclusive with --apply |
|
|
21
21
|
| `--model <name>` | from Session Config `dialectic.model` (default `haiku`) | Override LLM |
|
|
22
|
-
| `--budget-tokens <N>` | from Session Config `dialectic.budget-tokens` (default
|
|
22
|
+
| `--budget-tokens <N>` | from Session Config `dialectic.budget-tokens` (default 32000) | Input-token ceiling (the pre-dispatch estimate aborts above it; not a spend) |
|
|
23
23
|
|
|
24
24
|
Mutex check: `--apply` + `--dry-run` together = error "flags mutually exclusive".
|
|
25
25
|
|
|
26
26
|
### Step 6.1: Pre-checks
|
|
27
27
|
- Bootstrap gate (Phase 0) — already executed
|
|
28
28
|
- Persistence check (Phase 1.2) — already executed
|
|
29
|
-
- Cadence check:
|
|
29
|
+
- Cadence check: none. `/evolve dialectic` is invoked MANUALLY (by the operator, or by the session-start maintenance loop acting on the `maintenance-due` probe's `dialectic` signal) and always runs. The session-end Phase 3.6.7 auto-trigger that used to pre-check cadence was removed in #1288; `shouldDispatchAutoDialectic` (`scripts/lib/auto-dialectic.mjs`) survives only as the side-effect-free signal that probe reads, and this phase never calls it.
|
|
30
30
|
|
|
31
31
|
### Step 6.2: Data Load
|
|
32
32
|
Read all 4 input sources via `runDialecticDeriver()` from `scripts/dialectic-deriver.mjs` (see W2 I1):
|
|
@@ -60,19 +60,39 @@ const result = await runDialecticDeriver({
|
|
|
60
60
|
dispatchAgent,
|
|
61
61
|
repoRoot: process.cwd(),
|
|
62
62
|
model: argv.model ?? config.dialectic?.model ?? 'haiku',
|
|
63
|
-
budget: { input: argv['budget-tokens'] ?? config.dialectic?.['budget-tokens'] ??
|
|
63
|
+
budget: { input: argv['budget-tokens'] ?? config.dialectic?.['budget-tokens'] ?? 32000, output: 4000 },
|
|
64
64
|
dryRun: !argv.apply,
|
|
65
65
|
allowEmptying: argv['allow-emptying'] ?? false,
|
|
66
66
|
});
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
### Step 6.4: Diff Output & Apply Gate
|
|
70
|
-
- If dry-run (default): present diff inline; write to `.orchestrator/dialectic-pending.md` via `writeDialecticPending({ repoRoot, diff })` from `scripts/lib/auto-dialectic.mjs` (path constant `DIALECTIC_PENDING_PATH`; atomic tmp+rename). `runDialecticDeriver()` does NOT write this file itself — the dry-run branch returns the diff and the caller persists it. The body parameter is named `diff`, not `body
|
|
70
|
+
- If dry-run (default): present diff inline; write to `.orchestrator/dialectic-pending.md` via `writeDialecticPending({ repoRoot, diff })` from `scripts/lib/auto-dialectic.mjs` (path constant `DIALECTIC_PENDING_PATH`; atomic tmp+rename). `runDialecticDeriver()` does NOT write this file itself — the dry-run branch returns the diff and the caller persists it. The body parameter is named `diff`, not `body`, and it is a Markdown **string**: `result.diff` is an OBJECT `{ user?, agent? }`, so serialize it first — passing the object throws `TypeError` (as does an empty string or a missing `repoRoot`). An empty `result.diff` (no target proposed) has nothing to review: write no sidecar. EXIT. Suggestion: "Re-run with `/evolve --dialectic --apply` to apply." <!-- path-check: example -->
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const pendingBody = renderPendingBody(result.diff); // scripts/lib/auto-dialectic.mjs
|
|
74
|
+
if (pendingBody) {
|
|
75
|
+
await writeDialecticPending({ repoRoot, diff: pendingBody, usage: result.usage, model });
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`renderPendingBody({ user?, agent? })` is the serializer that used to live here as a snippet (#1386). It is now code so the dry-run write and the apply-time drift check below build the body the SAME way — two hand-copied serializers would report drift that is only formatting. It returns `''` when neither target is a string: nothing to review, write no sidecar.
|
|
80
|
+
- **Before `--apply` writes anything: show the operator what changed since he approved (#1386).** `--apply` re-derives from the model (`dispatchAgent` runs unconditionally in `scripts/dialectic-deriver.mjs`), so under variant (b) the apply still costs a SECOND model call and what would be applied is not necessarily what was read in `.orchestrator/dialectic-pending.md`. This step makes that drift VISIBLE; it does **not** make apply deterministic. Run it after the fresh derivation and BEFORE any `writePeerCard()` call: <!-- path-check: example -->
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
const fresh = renderPendingBody(result.diff);
|
|
84
|
+
const cmp = await comparePendingBody({ repoRoot, body: fresh }); // never throws
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- `cmp.sidecarAbsent === true` (no sidecar — the operator may never have run the dry-run) or `cmp.drifted === false`: apply SILENTLY. An `AskUserQuestion` that blocks nothing is a rule break (`.claude/rules/ask-via-tool.md` AUQ-001/AUQ-005).
|
|
88
|
+
- `cmp.drifted === true`: present BOTH bodies (`cmp.sidecarBody` = approved, `cmp.freshBody` = fresh) and ask via `AskUserQuestion` — two options, each description carrying reason + cost + consequence, and the drifted text in the option `preview` so the operator decides from the payload rather than from a file:
|
|
89
|
+
- **"Frischen Vorschlag anwenden (Recommended)"** — recommended because the fresh derivation saw the newest learnings and sessions, while the sidecar is a snapshot of an earlier run; cost: the peer cards get text the operator has not reviewed line by line; consequence: cards are written, `writeDialecticLastRun` + `consumeDialecticPending` run, the sidecar is archived.
|
|
90
|
+
- **"Verwerfen, Sidecar für eine weitere Prüfung behalten"** — when the delta is large enough to want a second read; cost: the second model call just spent is wasted and `--apply` must run again later; consequence: **nothing is written to the peer cards and the sidecar is NOT consumed** — skip both bookkeeping calls below so the `pending-sidecar` signal keeps the review due. EXIT.
|
|
71
91
|
- If `--apply`: call **`mergeDerivedBody(existingBody, result.diff[target])`** 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.
|
|
72
92
|
|
|
73
93
|
**`writePeerCard` shape (#1303).** `writePeerCard(repoRoot, target, card)` takes `card = { frontmatter, body }`. `frontmatter.id` (kebab-case slug, 2..128 chars) is **required and never auto-filled**; `type: 'peer-card'`, `target`, `updated` (defaults to `new Date().toISOString()`) and `created` (defaults to `updated`) are filled by the writer. ISO timestamps may carry optional milliseconds (`scripts/lib/peer-cards/schema.mjs` `ISO_DATETIME_REGEX`). A missing `id` returns `{ ok: false, errors: [...] }` and leaves the target file untouched — it does **not** throw; branch on `result.ok`.
|
|
74
94
|
|
|
75
|
-
**Why `mergeDerivedBody` and not `mergePeerCard` directly (#1310):** the deriver emits
|
|
95
|
+
**Why `mergeDerivedBody` and not `mergePeerCard` directly (#1310):** the deriver emits, per target, the WHOLE `## ` SECTIONS it changes or adds — never the card's full body (`agents/dialectic-deriver.md` § Output format: "Omitted sections stay unchanged (nothing auto-deletes), so emit only the sections you change or newly ground"). `mergePeerCard` consumes a SECTION MAP keyed by sentinel name. `mergeDerivedBody` is the adapter between the two — it splits the proposed text at `## ` headings and maps each heading to a sentinel section, merging SECTION-WISE. Do not read this as a full-body replacement: a deriver that emitted the full body would overwrite every hand-written managed section with an LLM reproduction, and `detectEmptying` (`scripts/dialectic-deriver.mjs`) would not catch it — it refuses only a proposal with ZERO content lines. `mergePeerCard` stays available as the section-map primitive. Handling per heading class, all of it in `mergeDerivedBody`'s return value:
|
|
76
96
|
|
|
77
97
|
| Heading in the proposed body | Section name | Merge effect | Surfaced as |
|
|
78
98
|
|---|---|---|---|
|
|
@@ -81,10 +101,18 @@ const result = await runDialecticDeriver({
|
|
|
81
101
|
| Existing managed section the proposal omits | — | KEPT (no auto-delete, per `mergePeerCard` semantics) | — |
|
|
82
102
|
| Section name outside `[A-Za-z0-9_-]+` | — | `mergePeerCard` **throws** `invalid section name` | fix the name before merging |
|
|
83
103
|
| Text before the first `## ` heading | — | NOT applied | `preamble` + a `{ type: 'unmapped-preamble' }` entry in `conflicts[]` |
|
|
104
|
+
| Falls inside an existing managed region that wraps MORE than one `## ` heading | — | NOT applied — the region stays byte-unchanged (no replace, which would delete its sibling headings' hand-written text; no append, which would duplicate the heading) | `{ type: 'multi-heading-region', region, headings, skipped }` in `conflicts[]` — `region` is the region's section name, `headings` the `## ` headings it wraps, `skipped` the proposed headings dropped. Operator action: split the region by hand into one managed region per heading, then re-run — or discard the proposal for those headings |
|
|
84
105
|
|
|
85
106
|
Existing names are read back out of the card rather than re-derived because the live names are not a pure function of their headings — measured 2026-09-11 in `.orchestrator/peers/AGENT.md`: `## Guard and protocol-migration discipline` → `guard-and-protocol-migration`. Re-slugifying would APPEND a duplicate section instead of replacing one.
|
|
86
107
|
|
|
87
|
-
**Present `conflicts[]` before writing.** A non-empty `conflicts[]` (`duplicate-section`, `orphan-begin`, `unmapped-preamble`) is operator-visible content that the merge did not place — report it beside the delta line rather than writing silently.
|
|
108
|
+
**Present `conflicts[]` before writing.** A non-empty `conflicts[]` (`duplicate-section`, `orphan-begin`, `unmapped-preamble`, `multi-heading-region`) is operator-visible content that the merge did not place — report it beside the delta line rather than writing silently.
|
|
109
|
+
- **Close the loop — after a successful `--apply` AND after the operator explicitly discards a reviewed proposal** (never after a dry-run, a failure, a skip, or the drift-check's "keep the sidecar for another review" branch above): record the run and consume the sidecar, both from `scripts/lib/auto-dialectic.mjs`. Without these two calls the maintenance-due probe keeps `dialectic` (measured against `.orchestrator/dialectic-last-run`) and `pending-sidecar` (`.orchestrator/dialectic-pending.md` younger than 14 days) due forever — nothing else writes the one or moves the other (#1380). Both return `{ ok, error? }` and never throw; log a failure and continue. Since #1388 `consumeDialecticPending` MOVES the sidecar to `.orchestrator/consumed/<timestamp>-dialectic-pending.md` (newest 10 retained) instead of deleting it, so the reviewed text survives the apply; `archivedTo` on the result names the file. <!-- path-check: example -->
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const lastRun = await writeDialecticLastRun({ repoRoot, isoTimestamp: new Date().toISOString() });
|
|
113
|
+
const consumed = await consumeDialecticPending({ repoRoot }); // ENOENT → { ok: true, consumed: false }
|
|
114
|
+
if (!lastRun.ok || !consumed.ok) console.error(`⚠ dialectic bookkeeping: ${lastRun.error ?? consumed.error}`);
|
|
115
|
+
```
|
|
88
116
|
- Report: `Dialectic-derived: M deltas to USER.md, N deltas to AGENT.md. Dry-run | Applied. Tokens: in=<X> out=<Y>.`
|
|
89
117
|
|
|
90
118
|
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs`, not skill prose.**
|
|
@@ -117,27 +145,16 @@ await recordDialecticRun({
|
|
|
117
145
|
### Step 6.5: Error Handling
|
|
118
146
|
- `status: 'unknown-model'` → fail with clear error (already thrown by validateModel)
|
|
119
147
|
- `status: 'budget-exceeded'` → emit `{status:'budget-exceeded', used:N, budget:M}`, do NOT truncate.
|
|
120
|
-
|
|
148
|
+
The budget is an input CEILING, not a spend. The former 8000 default aborted real runs — a consumer repo estimated 11 158 input tokens (S119, 2026-09-10) and later 30 262, this repo ~12 268 for card bodies + steering alone — so the default is 32000 since #1380. If a repo still exceeds it, raise `--budget-tokens` or `dialectic.budget-tokens` in Session Config rather than trimming inputs.
|
|
121
149
|
- `status: 'would-empty-card'` → warn + require `--allow-emptying` flag
|
|
122
150
|
- `status: 'empty-input'` → exit clean with message "dialectic: skipped (no input)"
|
|
123
151
|
- subagent crash → log ⚠, exit cleanly (do NOT write to `.orchestrator/dialectic-pending.md`) <!-- path-check: example -->
|
|
124
152
|
|
|
125
|
-
**Telemetry (#1200, #1206) — emitted by `scripts/dialectic-deriver.mjs
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- `unknown-model` — `validateModel()` throws synchronously before `runDialecticDeriver()` can
|
|
132
|
-
record anything about the call.
|
|
133
|
-
- `subagent-crash` — a `dispatchAgent`/`Agent()` failure propagates out of
|
|
134
|
-
`runDialecticDeriver()` uncaught (it has no status of its own for this case).
|
|
135
|
-
|
|
136
|
-
Catch both here and call the SAME `recordDialecticRun()` used in Step 6.4's apply branch,
|
|
137
|
-
passing the literal slug as `status` (the abort form: `{aborted: status, duration_ms}`):
|
|
138
|
-
|
|
139
|
-
```javascript
|
|
140
|
-
await recordDialecticRun({ repoRoot, status: 'unknown-model' /* or 'subagent-crash' */, durationMs: DURATION_MS });
|
|
141
|
-
```
|
|
153
|
+
**Telemetry (#1200, #1206, #1221) — all five outcomes are emitted by `scripts/dialectic-deriver.mjs`;
|
|
154
|
+
do NOT call `recordDialecticRun()` for any of them here.** `budget-exceeded`, `would-empty-card` and
|
|
155
|
+
`empty-input` are recorded at their return point; `unknown-model` and `subagent-crash` are recorded
|
|
156
|
+
at the throw point, and the original error is then rethrown unchanged — so catch it for the ⚠ log
|
|
157
|
+
above, but a second record here would double-count the run. The only caller-side emit left is
|
|
158
|
+
apply-mode success (Step 6.4).
|
|
142
159
|
|
|
143
160
|
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).
|
|
@@ -178,7 +178,8 @@ glab issue list -R <OWNER>/<REPO> --closed --per-page 10 # Rec
|
|
|
178
178
|
glab issue view -R <OWNER>/<REPO> <IID> # View issue details
|
|
179
179
|
glab issue view -R <OWNER>/<REPO> <IID> --comments # With comments
|
|
180
180
|
glab issue create -R <OWNER>/<REPO> --title "title" --label "priority::high,status:ready"
|
|
181
|
-
glab issue update -R <OWNER>/<REPO> <IID> --label "status:in-progress" #
|
|
181
|
+
glab issue update -R <OWNER>/<REPO> <IID> --label "status:in-progress" # ADDS; existing labels stay — see caveat below
|
|
182
|
+
glab issue update -R <OWNER>/<REPO> <IID> --unlabel "status:in-progress" # removes only the named label(s)
|
|
182
183
|
glab issue close -R <OWNER>/<REPO> <IID> # then VERIFY: re-read the issue; it must show state=closed
|
|
183
184
|
glab issue note -R <OWNER>/<REPO> <IID> -m "Comment text" # Add comment
|
|
184
185
|
|
|
@@ -196,7 +197,7 @@ glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/issues?stat
|
|
|
196
197
|
glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/milestones?state=active"
|
|
197
198
|
```
|
|
198
199
|
|
|
199
|
-
**Label update caveat
|
|
200
|
+
**Label update caveat: the `glab` flags add or remove, the raw API `labels=` sets the whole list.** Measured 2026-09-19 with `glab 1.117.0 (44790937b)`: `glab issue update <IID> --label "status:in-progress"` on 7 issues (#1390 #1389 #1339 #1298 #1273 #1221 #1202) ADDED the label and left every existing label in place. Read-only re-check (canonical identity form above): `glab api --hostname "$GITLAB_HOST" "projects/${ENCODED_PROJECT_PATH}/issues/${ISSUE_IID}" | jq .labels` → for #1390 `["area:meta","follow-up","priority::low","status:in-progress","type:chore"]`. `glab issue update --help` agrees (`-l --label Add labels.`, `-u --unlabel Remove labels.`). To remove a label, use `--unlabel` (comma-separated for several); `stripStatusLabels` in `scripts/lib/issue-close-strip-labels.mjs` does exactly that. The raw REST API is different, and this part comes from the docs, not a measurement: the GitLab Issues API documents `labels` on `PUT /projects/:id/issues/:issue_iid` as "Comma-separated label names for an issue. Set to an empty string to unassign all labels.", with `add_labels` / `remove_labels` as the incremental parameters. So a `glab api --silent --hostname "$GITLAB_HOST" -X PUT "projects/${ENCODED_PROJECT_PATH}/issues/${ISSUE_IID}" -f labels=…` call must carry the FULL desired set; prefer `add_labels=` / `remove_labels=`. Other `glab` versions were not measured, so re-run the read-only check after an upgrade. `glab mr update` lists the same `--label` "Add labels." / `--unlabel` "Remove labels." help text in 1.117.0; its behaviour was not measured.
|
|
200
201
|
|
|
201
202
|
**Close verification:** after `glab issue close <IID>`, always verify the close actually landed — re-read the issue (`glab issue view <IID>`) and confirm `state: closed` in the output. A stale or wrong project path, or a silent 404, can report local success while closing nothing; use the canonical project identity above for API operations rather than resolving a numeric ID.
|
|
202
203
|
|
|
@@ -25,7 +25,7 @@ description: >
|
|
|
25
25
|
|
|
26
26
|
The user invoked `/memory-cleanup` with arguments: **$ARGUMENTS**. Parse them before anything else — two optional, mutually-exclusive flags are recognised (`--dry-run`, `--apply-pending`, see PRD #502); passing both is an error, and the absence of both selects the legacy interactive 4-phase mode. The per-flag behaviour, the exact status lines and the exit codes are in § Argument Handling (Phase 0) below; the interactive default runs Phases 1-4 (Orient → Gather Signal → Consolidate → Prune & Index) against `~/.claude/projects/<encoded-cwd>/memory/` and reports per § Output.
|
|
27
27
|
|
|
28
|
-
Sidecar producer/consumer contract: session-
|
|
28
|
+
Sidecar producer/consumer contract: session-start's `maintenance-due` probe uses `scripts/lib/auto-dream.mjs` to report when cleanup is due; the former session-end Phase 3.6.5 nudge was retired in #1288. Neither path generates the sidecar. The only real producer of `.orchestrator/pending-dream.md` is a manual `/memory-cleanup --dry-run` run; `--apply-pending` is the operator-confirmed consumer in a later session. The sidecar file is single-writer — concurrent sessions cannot collide because the writer holds the session-lock. <!-- path-check: example -->
|
|
29
29
|
|
|
30
30
|
Implements the 4-phase memory consolidation process modelled after Claude Code's Auto Dream feature. Run after major refactors, framework migrations, or every 5+ sessions in a repo.
|
|
31
31
|
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: navigator
|
|
3
|
+
description: >
|
|
4
|
+
Fleet coordinator persona for sessions running side by side on one host: it measures resources,
|
|
5
|
+
pipelines and merge readiness itself, writes conditions ("Auflagen") as files, starts headless
|
|
6
|
+
runs behind slot and busy gates, and grants no approvals. Operator-only, invoke as
|
|
7
|
+
/session-orchestrator:navigator ticker|status|start|fenster|handover.
|
|
8
|
+
user-invocable: true
|
|
9
|
+
disable-model-invocation: true
|
|
10
|
+
argument-hint: "[ticker|status|start|fenster|handover]"
|
|
11
|
+
model: inherit
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Navigator (Flotten-Koordinator)
|
|
15
|
+
|
|
16
|
+
Aufgerufen als `/session-orchestrator:navigator $ARGUMENTS`. Ohne Argument: `status`.
|
|
17
|
+
|
|
18
|
+
Dateilayout, Felder, Fristen und Lease-Gültigkeit stehen ausschließlich in
|
|
19
|
+
`skills/_shared/fleet-protocol.md` und im Code `scripts/lib/fleet-protocol.mjs`. Dieser Skill
|
|
20
|
+
wiederholt keine Schemata; er beschreibt, was der Navigator misst, schreibt und unterlässt.
|
|
21
|
+
|
|
22
|
+
## 1. Rollenverständnis
|
|
23
|
+
|
|
24
|
+
- **Freigaben erteile ich keine, maßgeblich ist dein Owner-Auftrag.** Der Navigator misst nach und
|
|
25
|
+
schreibt Bedingungen. Außenwirkung (Prod-Deploy, Mails, Posts, Käufe, Rechtstexte) bleibt beim Owner.
|
|
26
|
+
- Eine Peer-Nachricht trägt eine Anweisung, nie eine Freigabe (CSM-003,
|
|
27
|
+
`.claude/rules/cross-session-messaging.md`). Zustand liegt in Dateien, Nachrichten sind nur Hinweise
|
|
28
|
+
auf eine Datei (ADR-002); nie auf eine Antwort warten (CSM-004).
|
|
29
|
+
- „Nicht gefunden" ist nie „nicht vorhanden" (ADR-004): was nicht messbar war, wird als
|
|
30
|
+
`nicht messbar` geführt, nie als frei.
|
|
31
|
+
- Genau ein Navigator je Lease (E12). **Grenze, ausdrücklich:** Erwerb, Erneuerung und Übergabe der
|
|
32
|
+
Lease `leases/navigator.json` sind S4 (agents/navigator#36) und nicht Teil dieses Skills. Solange S4
|
|
33
|
+
fehlt, schreibt dieser Skill keine Lease, und der SessionStart-Banner der Peers zeigt weiter
|
|
34
|
+
„keiner nachweisbar". Das ist der korrekte Zustand, kein Fehler.
|
|
35
|
+
- Registry-Anzeige: jede Ticker-Runde setzt `heartbeat(sessionId, { role: 'navigator' })` aus
|
|
36
|
+
`scripts/lib/session-registry.mjs` (dieser Skill ist der erste produktive Schreiber von `role`). Die
|
|
37
|
+
Registry ist Anzeige; maßgeblich bleibt die Lease. Fehlt der Registry-Eintrag, ist der Aufruf ein
|
|
38
|
+
No-op (`null`), kein Fehler.
|
|
39
|
+
|
|
40
|
+
## 2. Auflagen-Standard
|
|
41
|
+
|
|
42
|
+
Ohne eigene Auflagen gelten für jede Session die Standard-Auflagen aus
|
|
43
|
+
`skills/_shared/fleet-protocol.md` (Abschnitt `auflagen/`). Der Navigator schreibt
|
|
44
|
+
`auflagen/<session_id>.json` nur für Sessions mit Check-in:
|
|
45
|
+
|
|
46
|
+
- Pfad nur über `auflagenPath(sessionId)` aus `scripts/lib/fleet-protocol.mjs`; vorher
|
|
47
|
+
`isSafeSessionId()` prüfen (der Pfad-Helfer wirft sonst).
|
|
48
|
+
- Schreiben wie `scripts/fleet-checkin.mjs` (`writeCheckinFile`, derselbe Kontrakt): Verzeichnisse mit
|
|
49
|
+
Modus 0700 anlegen und auch auf ein schon vorhandenes Verzeichnis `chmod 0700` anwenden; tmp-Datei
|
|
50
|
+
im Zielverzeichnis exklusiv anlegen (`wx`), explizit `chmod 0600` (die Umask filtert den
|
|
51
|
+
Anlege-Modus), dann `rename`. Nie `mkdir -p` + `cat > tmp && mv` ohne diese drei Schritte.
|
|
52
|
+
- `zeit` aus `date -u +%FT%TZ` (`utcSecondsTimestamp()`), nie geschätzt.
|
|
53
|
+
|
|
54
|
+
Schwellen (freier Speicher des lokalen Hosts laut `memory_pressure | tail -1`):
|
|
55
|
+
|
|
56
|
+
| Freier Speicher | Caps je Peer |
|
|
57
|
+
|---|---|
|
|
58
|
+
| ≥ 50 % | 2 prozessstartende + 2 lesende Agents |
|
|
59
|
+
| 35–50 % | 1 prozessstartender Agent |
|
|
60
|
+
| < 35 % | keine neuen Starts |
|
|
61
|
+
|
|
62
|
+
Offload auf `m5-remote` trägt keine eigene Lastzahl: maßgeblich ist allein `navigator m5-ersatz
|
|
63
|
+
--quiet` mit dem Exit-Vertrag aus `skills/_shared/fleet-protocol.md` (Standard-Auflagen). Jeder Exit
|
|
64
|
+
außer 0 heißt keine neuen Offload-Gates; den gemessenen Exit trägt `offload.m5_ersatz_exit`.
|
|
65
|
+
|
|
66
|
+
Minimalbeispiel (nur Platzhalter; Feldbedeutung laut Referenz):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"session": "session-A1",
|
|
71
|
+
"caps": { "prozessstartend": 2, "lesend": 2, "grundlage": "frei 54 %" },
|
|
72
|
+
"pipelines": { "repo-A": 2 },
|
|
73
|
+
"offload": { "host": "m5-remote", "m5_ersatz_exit": 0, "regel": "offload nur nach m5-ersatz Exit 0", "lokal": "vitest/eslint je Datei mit timeout" },
|
|
74
|
+
"merge_protokoll": "Ansage, eigene Messung, Befugnis nach PRD 3.5",
|
|
75
|
+
"zeitregel": "Zeiten nur aus date",
|
|
76
|
+
"flottenprioritaet": ["repo-A", "repo-B"],
|
|
77
|
+
"besitzkonflikte": [],
|
|
78
|
+
"pflichtsatz": "Freigaben erteile ich keine, maßgeblich ist dein Owner-Auftrag",
|
|
79
|
+
"zeit": "2026-01-01T00:00:00Z"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 3. Merge-Zeichen als Messung, nicht als Freigabe
|
|
84
|
+
|
|
85
|
+
Ein „Zeichen" heißt: die Belege stimmen und main ist frei, nie „du darfst". Davor misst der Navigator
|
|
86
|
+
selbst, nie aus dem Bericht einer Session:
|
|
87
|
+
|
|
88
|
+
1. MR `opened` und `mergeable`.
|
|
89
|
+
2. Head-SHA = Pipeline-SHA = Gate-SHA; Gate-Beleg ist die SHA-Zeile im Job-Log.
|
|
90
|
+
3. Pipeline `success`, Jobliste mit gelaufen / übersprungen / manuell, Pflichtjobs eingeschlossen.
|
|
91
|
+
4. main frei: keine laufende main-Pipeline, keine gültige fremde Ansage im Repo.
|
|
92
|
+
5. Dateiüberschneidung mit anderen offenen MRs.
|
|
93
|
+
|
|
94
|
+
Nach dem Merge: main-Pipeline bis zum Ende verfolgen, bei Deploy-Repos die Health-SHA messen. Die
|
|
95
|
+
Befugnis kommt aus PRD 3.5 (Owner-Auftrag oder `navigator authority query`), nie vom Navigator.
|
|
96
|
+
Merge-Leases sind S2 (#1463): siehe Abschnitt „Vorschau" in `skills/_shared/fleet-protocol.md`.
|
|
97
|
+
|
|
98
|
+
## 4. Kopflose Läufe starten (`start`)
|
|
99
|
+
|
|
100
|
+
- Vor jedem Start Platz-Tor und Belegt-Tor: `references/slot-check.sh` misst,
|
|
101
|
+
`references/fleet-decisions.mjs` entscheidet (`slot`, `busy`). Verweigert heißt: nicht starten.
|
|
102
|
+
Nie in einem Repo mit aktiver Claude- oder Codex-Session (Belegt-Tor: Codex-Rollout mit diesem
|
|
103
|
+
Checkout jünger als 30 min oder `session.lock` jünger als 6 h). Das Platz-Tor zählt kopflose Läufe
|
|
104
|
+
je Host (4 / 3 / 0 bei ≥ 50 % / ≥ 35 % / darunter freiem Speicher, Last1 > 40 schließt alles) und ist
|
|
105
|
+
eine andere Größe als die Agent-Caps je Peer aus Abschnitt 2.
|
|
106
|
+
- Brief als Datei; er verlangt, vor jeder Welle und jedem MR `auflagen/` und `merge/` zu lesen.
|
|
107
|
+
- Phase 1 mit fester Session-ID, spätere Phasen per `--resume`. Obergrenze je Lauf über
|
|
108
|
+
`timeout -k 60 <sekunden>` (ganze Sekunden; das Platz-Tor zählt Läufe an genau diesem Wrapper). Protokolldateien `phaseN.meta`, `phaseN.jsonl`, `phaseN.err`; je Lauf eine
|
|
109
|
+
Parkplatz-Datei (nur anhängen, nie überschreiben). Ablage je Lauf unter
|
|
110
|
+
`<NAVIGATOR_CONFIG_DIR>/fleet/<lauf>/` (Konvention, kein Skript liest sie).
|
|
111
|
+
- Hintergrund-Tasks und Monitor sterben mit dem Turn-Ende; ein alleinstehendes langes `sleep` blockt
|
|
112
|
+
der Harness; die `until`/`case`-Form kehrt sofort zurück, weil `case` ohne Treffer 0 liefert.
|
|
113
|
+
**Wartemuster**, wörtlich:
|
|
114
|
+
|
|
115
|
+
`timeout 540 bash -c 'while :; do s=$(<status-befehl>); case "$s" in success|failed|canceled|skipped|manual) echo "$s"; exit 0;; esac; sleep 20; done'; echo "rc=$?"`
|
|
116
|
+
|
|
117
|
+
Exit 124 heißt weiter warten: denselben Befehl wiederholen. Der Turn endet nie, solange etwas läuft.
|
|
118
|
+
|
|
119
|
+
## 5. Pfad-Regel für Offload
|
|
120
|
+
|
|
121
|
+
`offload gate|run` immer mit dem **Worktree-Pfad**, nie mit dem Repo-Namen (sonst wird der
|
|
122
|
+
Haupt-Checkout gespiegelt). Host nur über den Alias `m5-remote`. Im entfernten Befehl kein `timeout`
|
|
123
|
+
und keine Login-Shell. Details: `skills/remote-offload/SKILL.md`.
|
|
124
|
+
|
|
125
|
+
## 6. Codex-Läufe
|
|
126
|
+
|
|
127
|
+
- `codex exec` mit `--json` und `-o <datei>`; Fortsetzung per `codex exec resume <thread-id>`.
|
|
128
|
+
- Codex-Läufe mergen nie. Eine Claude-Session prüft ihr Ergebnis unabhängig, bevor irgendetwas
|
|
129
|
+
gemergt wird.
|
|
130
|
+
- Laufende Codex-Sessions sind nur lesend beobachtbar (Rollout-Dateien unter
|
|
131
|
+
`$NAVIGATOR_CODEX_HOME/sessions`, mtime < 3 min = aktiv in der Lage; das Belegt-Tor aus Abschnitt 4
|
|
132
|
+
zählt konservativer, 30 min) und per Nachricht nicht erreichbar.
|
|
133
|
+
|
|
134
|
+
## 7. Phase-2-Fortsetzung bei Abbruch
|
|
135
|
+
|
|
136
|
+
Endet ein Lauf früh (Exit ≠ 0, „killed"-Task im Log, Bericht fehlt): Parkplatz-Datei und die letzten
|
|
137
|
+
`result`-Zeilen lesen, Zustand selbst messen (Worktree, HEAD, Gate-Job), dann Phase 2 mit einem kurzen
|
|
138
|
+
Fortsetzungsbrief starten, wieder hinter beiden Toren.
|
|
139
|
+
|
|
140
|
+
## 8. Konto-Wache
|
|
141
|
+
|
|
142
|
+
- Nutzbar: 5h < 97 % und 7d < 97 %. Das nutzbare Konto mit dem frühesten 7d-Reset (≤ 3 Tage) zuerst
|
|
143
|
+
aufbrauchen; ferne Konten fair nach Verbrauch. Toleranz 1 800 s bei gleichem Reset gegen Flattern.
|
|
144
|
+
- Fehlende Daten = nicht messbar, nie „frei".
|
|
145
|
+
- Werkzeug: `references/account-check.sh` liest `NAVIGATOR_ACCOUNT_CMD` und gibt nur die Entscheidung
|
|
146
|
+
aus (Ziel als Slot-Nummer, nie als Alias); ungesetzt meldet es „nicht messbar". Nie Konto-Rohdaten
|
|
147
|
+
ausgeben.
|
|
148
|
+
- Ein Wechsel wirkt auf alle Sessions des Hosts und braucht eine dauerhafte Owner-Freigabe; ohne sie
|
|
149
|
+
nur eine Empfehlung.
|
|
150
|
+
|
|
151
|
+
## 9. KI-Budget-Regel
|
|
152
|
+
|
|
153
|
+
Bezahlter API-Key nur produktiv. Tests, Evals und CI-Proben laufen mit Mock, Kassette oder
|
|
154
|
+
Abo-/CLI-Modell. Tages- und Wochenverbrauch aus den Peer-Meldungen in die Lage-Datei; die Schwelle
|
|
155
|
+
für einen Owner-Punkt ist Konfiguration, nie eine erfundene Zahl.
|
|
156
|
+
|
|
157
|
+
## 10. Unterbefehle
|
|
158
|
+
|
|
159
|
+
| Befehl | Was er tut |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `ticker` | Eine Runde (unten). Wiederholung nur über `/loop`, nie selbst gebaut. |
|
|
162
|
+
| `status` | Liest Registry, Lease, `checkin/`, `auflagen/`; schreibt nichts. |
|
|
163
|
+
| `start` | Tore aus Abschnitt 4, dann Lauf. |
|
|
164
|
+
| `fenster` | Merge-Fenster je Repo als Messung nach Abschnitt 3. |
|
|
165
|
+
| `handover` | Übergabedatei an den Nachfolger. `uebergabe_an` in der Lease ist S4 und wird hier nur beschrieben. |
|
|
166
|
+
|
|
167
|
+
**Ticker-Runde:** (1) Zeit aus `date`; (2) Ressourcen (Speicher, Last lokal und `m5-remote`, Platte);
|
|
168
|
+
(3) Peers per `ListAgents`; (4) Codex nur lesend; (5) kopflose Läufe (`phaseN.meta`, Parkplatz);
|
|
169
|
+
(6) Pipelines per `glab api "projects/:id/pipelines?status=running"`; (7) Waisen: Prozesse mit PPID 1
|
|
170
|
+
aus Flotten-Repos, nur melden, beenden nur mit Register-Treffer (HR-107); (8) Owner-Punkte; (9) Konto;
|
|
171
|
+
(10) Budget. Danach `heartbeat(sessionId, { role: 'navigator' })`. Antwort eine Zeile, bei Befund
|
|
172
|
+
höchstens sechs.
|
|
173
|
+
|
|
174
|
+
**Kopflos:** unter `claude -p` sind nur `session` und `plan` als eingebaute Namen reserviert. Bis
|
|
175
|
+
`/navigator` ohne Namespace gemessen ist, gilt `/session-orchestrator:navigator`.
|
|
176
|
+
|
|
177
|
+
## Konfiguration
|
|
178
|
+
|
|
179
|
+
Nur über Umgebungsvariablen (getrimmt; leer zählt als nicht gesetzt):
|
|
180
|
+
|
|
181
|
+
| Variable | Default | Zweck |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `NAVIGATOR_CONFIG_DIR` | `~/.config/navigator` | Protokollwurzel (`navigatorDir()`, S1) |
|
|
184
|
+
| `NAVIGATOR_CODEX_HOME` | `~/.codex` | Codex-Rollouts, nur lesend |
|
|
185
|
+
| `NAVIGATOR_ACCOUNT_CMD` | ungesetzt | Konto-Messung (wird als Shell-Befehl ausgeführt, Owner-eigen); ungesetzt = nicht messbar |
|
|
186
|
+
| `NAVIGATOR_ACCOUNT_SWITCH_CMD` | ungesetzt | Wechselbefehl; `--apply` zeigt ihn nur an, führt ihn nie aus |
|
|
187
|
+
| `FLEET_SLOT_OVERRIDE`, `FLEET_BUSY_OVERRIDE` | ungesetzt | `1` = Owner-Override je Tor (Grund `override` in der Entscheidung) |
|
|
188
|
+
|
|
189
|
+
## See Also
|
|
190
|
+
|
|
191
|
+
`skills/_shared/fleet-protocol.md` · `skills/remote-offload/SKILL.md` ·
|
|
192
|
+
`.claude/rules/cross-session-messaging.md` · `.claude/rules/parallel-sessions.md` ·
|
|
193
|
+
`skills/_shared/state-ownership.md` · PRD `docs/prd/2026-09-27-navigator-peer-protokoll.md`
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# account-check.sh — account watch: recommend which account this host should run on.
|
|
3
|
+
#
|
|
4
|
+
# Usage: account-check.sh [--apply]
|
|
5
|
+
#
|
|
6
|
+
# Runs $NAVIGATOR_ACCOUNT_CMD (must print JSON rows: an array, or {"accounts": [...]}, each row
|
|
7
|
+
# {slot, alias?, active, p7, p5, resetAt}) and pipes it into `fleet-decisions.mjs account`.
|
|
8
|
+
# Prints ONLY the decision line — raw account rows never reach stdout or stderr (SEC-008).
|
|
9
|
+
#
|
|
10
|
+
# --apply does not switch. It prints the command that WOULD run via $NAVIGATOR_ACCOUNT_SWITCH_CMD
|
|
11
|
+
# and refuses if that variable is unset: a switch affects every session on the host and needs a
|
|
12
|
+
# durable owner approval, so this script only ever recommends.
|
|
13
|
+
#
|
|
14
|
+
# NAVIGATOR_ACCOUNT_CMD is executed as shell code by design: it is operator-owned configuration.
|
|
15
|
+
#
|
|
16
|
+
# Env (leading/trailing whitespace is trimmed; a whitespace-only value counts as unset):
|
|
17
|
+
# NAVIGATOR_ACCOUNT_CMD command printing the account rows as JSON (required)
|
|
18
|
+
# NAVIGATOR_ACCOUNT_SWITCH_CMD switch command, shown with the target appended under --apply
|
|
19
|
+
#
|
|
20
|
+
# Exit: 0 stay/switch recommended, 1 no usable account, 2 bad input/usage, 3 not measurable.
|
|
21
|
+
set -u
|
|
22
|
+
|
|
23
|
+
apply=0
|
|
24
|
+
case "${1:-}" in
|
|
25
|
+
'') ;;
|
|
26
|
+
--apply) apply=1 ;;
|
|
27
|
+
*) echo "usage: account-check.sh [--apply]" >&2; exit 2 ;;
|
|
28
|
+
esac
|
|
29
|
+
|
|
30
|
+
# Trim leading/trailing whitespace.
|
|
31
|
+
trim() {
|
|
32
|
+
local v=$1
|
|
33
|
+
v=${v#"${v%%[![:space:]]*}"}
|
|
34
|
+
v=${v%"${v##*[![:space:]]}"}
|
|
35
|
+
printf '%s' "$v"
|
|
36
|
+
}
|
|
37
|
+
account_cmd=$(trim "${NAVIGATOR_ACCOUNT_CMD:-}")
|
|
38
|
+
switch_cmd=$(trim "${NAVIGATOR_ACCOUNT_SWITCH_CMD:-}")
|
|
39
|
+
|
|
40
|
+
if [ -z "$account_cmd" ]; then
|
|
41
|
+
echo "account watch: not measurable (NAVIGATOR_ACCOUNT_CMD unset)"
|
|
42
|
+
exit 3
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
here=$(cd "$(dirname "$0")" && pwd)
|
|
46
|
+
# Cap the operator command at 40 s where a timeout binary exists (GNU coreutils `timeout`, Homebrew
|
|
47
|
+
# `gtimeout`); a stock macOS host has neither, and the command then runs uncapped rather than failing
|
|
48
|
+
# as "not measurable" (measured on the offload host: `command -v timeout` and `gtimeout` both empty).
|
|
49
|
+
# No bash array here: under `set -u` an empty array expansion fails on bash 3.2 (stock macOS).
|
|
50
|
+
run_capped() {
|
|
51
|
+
if command -v timeout >/dev/null 2>&1; then timeout 40 "$@"
|
|
52
|
+
elif command -v gtimeout >/dev/null 2>&1; then gtimeout 40 "$@"
|
|
53
|
+
else "$@"
|
|
54
|
+
fi
|
|
55
|
+
}
|
|
56
|
+
rows=$(run_capped bash -c "$account_cmd" 2>/dev/null)
|
|
57
|
+
cmd_rc=$?
|
|
58
|
+
if [ "$cmd_rc" -ne 0 ] || [ -z "$rows" ]; then
|
|
59
|
+
echo "account watch: not measurable (account command failed, rc=$cmd_rc)"
|
|
60
|
+
exit 3
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
decision=$(printf '%s' "$rows" | node "$here/fleet-decisions.mjs" account 2>/dev/null)
|
|
64
|
+
rc=$?
|
|
65
|
+
if [ "$rc" -eq 2 ]; then
|
|
66
|
+
echo "account watch: not measurable (account command output is not valid account JSON)"
|
|
67
|
+
exit 2
|
|
68
|
+
fi
|
|
69
|
+
if { [ "$rc" -ne 0 ] && [ "$rc" -ne 1 ]; } || [ -z "$decision" ]; then
|
|
70
|
+
echo "account watch: not measurable (decision unavailable, rc=$rc)"
|
|
71
|
+
exit 3
|
|
72
|
+
fi
|
|
73
|
+
echo "account: $decision"
|
|
74
|
+
|
|
75
|
+
if [ "$apply" -eq 1 ] && [ "$rc" -eq 0 ]; then
|
|
76
|
+
if [ -z "$switch_cmd" ]; then
|
|
77
|
+
echo "apply refused: NAVIGATOR_ACCOUNT_SWITCH_CMD unset" >&2
|
|
78
|
+
exit 2
|
|
79
|
+
fi
|
|
80
|
+
target=$(printf '%s' "$decision" | node -e 'let s="";process.stdin.on("data",c=>s+=c).on("end",()=>{const d=JSON.parse(s);process.stdout.write(d.action==="switch"?String(d.target):"")})')
|
|
81
|
+
if [ -n "$target" ]; then
|
|
82
|
+
echo "would run: $switch_cmd $target (not executed — switching needs a durable owner approval)"
|
|
83
|
+
else
|
|
84
|
+
echo "would run: nothing (stay)"
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
exit "$rc"
|