session-orchestrator 5.11.0 → 5.13.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/.claude-plugin/marketplace.json +12 -1
- package/.claude-plugin/plugin.json +4 -1
- package/.codex-plugin/agents/explorer.toml +1 -1
- package/.codex-plugin/agents/session-reviewer.toml +2 -2
- package/.codex-plugin/agents/wave-worker.toml +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +8 -0
- package/.orchestrator/policy/public-export.json +30 -0
- package/CHANGELOG.md +180 -3
- package/README.md +126 -117
- package/agents/analyst.md +7 -2
- package/agents/architect-reviewer.md +7 -2
- package/agents/code-implementer.md +4 -2
- package/agents/db-specialist.md +9 -2
- package/agents/dialectic-deriver.md +9 -3
- package/agents/docs-writer.md +7 -2
- package/agents/eval-judge.md +7 -1
- package/agents/qa-strategist.md +7 -2
- package/agents/security-reviewer.md +9 -2
- package/agents/session-reviewer.md +18 -2
- package/agents/skill-applied-judge.md +7 -1
- package/agents/test-writer.md +9 -2
- package/agents/ui-developer.md +9 -2
- package/agents/ux-evaluator.md +6 -1
- package/commands/session.md +4 -2
- package/commands/templates-ack.md +89 -18
- package/docs/agent-authoring.md +30 -11
- package/docs/ci-setup.md +38 -2
- package/docs/codex-setup.md +33 -9
- package/docs/components.md +13 -2
- package/docs/cursor-setup.md +3 -3
- package/docs/events-schema.md +5 -4
- package/docs/evidence-candidates.md +63 -0
- package/docs/fleet-checkin-audit.md +7 -4
- package/docs/github-mirror-protection.md +150 -3
- package/docs/install.md +102 -25
- package/docs/instruction-delivery.md +1 -1
- package/docs/migration-v4.md +2 -2
- package/docs/mods.md +118 -0
- package/docs/owner-config-schema.md +1 -0
- package/docs/plugin-architecture-v3.md +1 -1
- package/docs/pm-skills-marketplace.md +4 -3
- package/docs/rule-authoring.md +24 -13
- package/docs/scope-collision-guard.md +2 -1
- package/docs/session-config-reference.md +55 -21
- package/docs/session-config-template.md +32 -24
- package/docs/sessions-ledger-repair.md +137 -0
- package/docs/vault-docs-architecture.md +1 -1
- package/hooks/_lib/hook-import-set.json +406 -73
- package/hooks/_lib/hook-root.mjs +301 -0
- package/hooks/_lib/lock-bootstrap.mjs +434 -4
- package/hooks/_lib/orchestrator-ignore.mjs +3 -0
- package/hooks/_lib/subagent-transcript.mjs +2 -2
- package/hooks/_lib/vcs-create-matcher.mjs +13 -17
- package/hooks/cwd-change-restore.mjs +5 -1
- package/hooks/enforce-commands.mjs +4 -3
- package/hooks/enforce-scope.mjs +11 -1
- package/hooks/hooks-codex.json +48 -2
- package/hooks/hooks.json +31 -31
- package/hooks/on-session-end.mjs +38 -15
- package/hooks/on-session-start.mjs +158 -59
- package/hooks/on-stop.mjs +11 -6
- package/hooks/post-bash-issue-budget-refund.mjs +6 -1
- package/hooks/post-bash-write-verify.mjs +8 -4
- package/hooks/post-edit-validate.mjs +45 -52
- package/hooks/post-subagent-discovery-validator.mjs +2 -2
- package/hooks/post-tool-batch-wave-signal.mjs +8 -4
- package/hooks/post-tool-failure-corrective-context.mjs +5 -1
- package/hooks/pre-bash-destructive-guard.mjs +220 -8
- package/hooks/pre-bash-issue-budget.mjs +6 -1
- package/hooks/pre-bash-sessions-ledger-guard.mjs +691 -123
- package/hooks/pre-bash-staging-fence.mjs +258 -14
- package/hooks/pre-bash-templates-first.mjs +28 -27
- package/hooks/run-node.sh +1 -1
- package/hooks/skill-invocation-telemetry.mjs +15 -8
- package/hooks/subagent-telemetry.mjs +77 -14
- package/hooks/wave-scope-commit-guard.mjs +143 -14
- package/mods/so-hud/.claude-plugin/plugin.json +11 -0
- package/mods/so-hud/README.md +57 -0
- package/mods/so-hud/hooks/beacon-io.mjs +101 -0
- package/mods/so-hud/hooks/heredoc-scan.ts +394 -0
- package/mods/so-hud/hooks/hooks.json +1 -0
- package/mods/so-hud/hooks/logic.ts +182 -0
- package/mods/so-hud/hooks/register.tsx +670 -0
- package/mods/so-hud/hooks/rules.ts +2998 -0
- package/mods/so-hud/tsconfig.json +8 -0
- package/mods/so-hud/types/index.d.ts +36 -0
- package/package.json +4 -3
- package/rules/_index.md +1 -1
- package/rules/always-on/ask-via-tool.md +1 -1
- package/rules/always-on/loop-and-monitor.md +17 -194
- package/rules/always-on/parallel-sessions.md +3 -1
- package/rules/opt-in-stack/backend-data.md +1 -1
- package/rules/opt-in-stack/backend.md +1 -1
- package/rules/opt-in-stack/security-web.md +5 -1
- package/scripts/agent-usage-census.mjs +79 -0
- package/scripts/apply-session-learnings.mjs +34 -6
- package/scripts/archive-closed-prds.mjs +21 -5
- package/scripts/autopilot.mjs +11 -5
- package/scripts/backfill-abandoned-sessions.mjs +13 -3
- package/scripts/backfill-evidence-digest.mjs +2 -1
- package/scripts/backfill-learnings-from-vault.mjs +61 -6
- package/scripts/backfill-sessions.mjs +16 -2
- package/scripts/check-package-manager.mjs +26 -8
- package/scripts/check-sessions-integrity.mjs +4 -1
- package/scripts/ci/assert-vitest-green.mjs +3 -0
- package/scripts/ci/windows-smoke.mjs +201 -0
- package/scripts/close-precheck.mjs +55 -0
- package/scripts/dialectic-deriver.mjs +20 -12
- package/scripts/emit-event.mjs +2 -2
- package/scripts/emit-session.mjs +239 -20
- package/scripts/eval-session.mjs +17 -3
- package/scripts/export-hw-learnings.mjs +29 -2
- package/scripts/fleet-checkin-audit.mjs +8 -4
- package/scripts/fleet-checkin.mjs +73 -3
- package/scripts/gc-stale-worktrees.mjs +6 -1
- package/scripts/github-export.mjs +128 -0
- package/scripts/github-protection-audit.mjs +3 -1
- package/scripts/handover-queue-check.mjs +209 -0
- package/scripts/harness-audit.mjs +6 -4
- package/scripts/lib/agent-frontmatter.mjs +57 -10
- package/scripts/lib/agent-status.mjs +125 -7
- package/scripts/lib/agent-usage-census.mjs +394 -0
- package/scripts/lib/auto-dialectic.mjs +17 -10
- package/scripts/lib/auto-dream.mjs +22 -14
- package/scripts/lib/autopilot/loop.mjs +3 -1
- package/scripts/lib/autopilot/recent-runs.mjs +4 -2
- package/scripts/lib/autopilot/stall-sampler.mjs +2 -1
- package/scripts/lib/autopilot/telemetry.mjs +5 -1
- package/scripts/lib/autopilot/worktree-pipeline.mjs +5 -5
- package/scripts/lib/baseline-archetypes.mjs +10 -2
- package/scripts/lib/blocked-commands-policy.mjs +4 -3
- package/scripts/lib/build-live-signals.mjs +13 -9
- package/scripts/lib/ci-status-banner.mjs +329 -24
- package/scripts/lib/codex/plugin-contract.mjs +8 -0
- package/scripts/lib/cold-start-detector.mjs +5 -2
- package/scripts/lib/command-blocker.mjs +603 -43
- package/scripts/lib/common.mjs +3 -2
- package/scripts/lib/config/cross-repo.mjs +74 -7
- package/scripts/lib/config/host-paths.mjs +6 -2
- package/scripts/lib/config/remote-hosts.mjs +2 -2
- package/scripts/lib/config/section-extractor.mjs +65 -11
- package/scripts/lib/config/template-keys.mjs +153 -0
- package/scripts/lib/config/vault-integration.mjs +1 -0
- package/scripts/lib/config.mjs +3 -3
- package/scripts/lib/coordinator-snapshot.mjs +1 -1
- package/scripts/lib/discovery/triage-state.mjs +2 -1
- package/scripts/lib/dispatcher/rank.mjs +5 -7
- package/scripts/lib/ecosystem-health.mjs +2 -2
- package/scripts/lib/eval/engine.mjs +3 -2
- package/scripts/lib/eval/session-resolve.mjs +6 -2
- package/scripts/lib/eval/sink.mjs +4 -3
- package/scripts/lib/events-retention-banner.mjs +3 -2
- package/scripts/lib/events-schema.mjs +10 -0
- package/scripts/lib/events.mjs +23 -12
- package/scripts/lib/evolve/autonomy-verdict.mjs +4 -9
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +8 -18
- package/scripts/lib/fleet-protocol.mjs +21 -0
- package/scripts/lib/gates/gate-full.mjs +172 -11
- package/scripts/lib/gates/gate-helpers.mjs +236 -23
- package/scripts/lib/git-config-drift.mjs +141 -7
- package/scripts/lib/github-export.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +16 -5
- package/scripts/lib/handover-queue-marks.mjs +159 -0
- package/scripts/lib/hardware-pattern-detector.mjs +103 -13
- package/scripts/lib/harness-audit/categories/category1.mjs +16 -4
- package/scripts/lib/harness-audit/categories/category4.mjs +11 -8
- package/scripts/lib/harness-audit/categories/category6.mjs +25 -5
- package/scripts/lib/harness-audit/categories/category9.mjs +10 -4
- package/scripts/lib/host-identity.mjs +9 -5
- package/scripts/lib/http-request.mjs +64 -0
- package/scripts/lib/instruction-budget-guard.mjs +30 -22
- package/scripts/lib/io.mjs +6 -3
- package/scripts/lib/issue-budget-reconcile.mjs +3 -2
- package/scripts/lib/issue-budget.mjs +36 -7
- package/scripts/lib/learnings/evidence-candidates.mjs +154 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +99 -7
- package/scripts/lib/learnings/io.mjs +289 -15
- package/scripts/lib/learnings/select.mjs +53 -4
- package/scripts/lib/learnings/store-role.mjs +209 -0
- package/scripts/lib/learnings/surface.mjs +46 -7
- package/scripts/lib/ledger-path.mjs +113 -0
- package/scripts/lib/maintenance-due-banner.mjs +63 -12
- package/scripts/lib/memory-banner.mjs +5 -6
- package/scripts/lib/memory-proposals/collector.mjs +5 -2
- package/scripts/lib/memory-proposals/sink.mjs +7 -4
- package/scripts/lib/memory-proposals/store.mjs +22 -5
- package/scripts/lib/mode-selector-accuracy.mjs +2 -1
- package/scripts/lib/no-follow-open.mjs +57 -0
- package/scripts/lib/orphan-reaper/reaper-audit.mjs +4 -2
- package/scripts/lib/own-lock-root.mjs +95 -0
- package/scripts/lib/owner-interview.mjs +2 -1
- package/scripts/lib/owner-yaml.mjs +70 -7
- package/scripts/lib/platform.mjs +161 -9
- package/scripts/lib/plugin-update-banner.mjs +15 -11
- package/scripts/lib/pre-push-local-partial.mjs +117 -0
- package/scripts/lib/pre-push-remote-gate.mjs +151 -25
- package/scripts/lib/process-group.mjs +270 -34
- package/scripts/lib/project-hygiene.mjs +28 -0
- package/scripts/lib/quality-gate.mjs +33 -9
- package/scripts/lib/reconcile/backlog.mjs +29 -15
- package/scripts/lib/reconcile/engine.mjs +26 -2
- package/scripts/lib/reconcile/idempotency.mjs +65 -3
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +53 -12
- package/scripts/lib/reconcile/verdict-ledger.mjs +224 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +40 -6
- package/scripts/lib/resource-probe/evaluate.mjs +32 -9
- package/scripts/lib/resource-probe/probe-platform.mjs +3 -1
- package/scripts/lib/rule-loader.mjs +20 -10
- package/scripts/lib/scope-baseline.mjs +123 -8
- package/scripts/lib/scope-echo.mjs +5 -2
- package/scripts/lib/scope-gate.mjs +55 -20
- package/scripts/lib/session-close-backfill.mjs +75 -7
- package/scripts/lib/session-end/close-precheck.mjs +151 -0
- package/scripts/lib/session-end/phase-skip.mjs +8 -7
- package/scripts/lib/session-end/tail-runner.mjs +7 -2
- package/scripts/lib/session-end/vault-orphans.mjs +205 -0
- package/scripts/lib/session-id.mjs +9 -1
- package/scripts/lib/session-identity/own-session.mjs +63 -0
- package/scripts/lib/session-invocation.mjs +14 -3
- package/scripts/lib/session-lock.mjs +114 -0
- package/scripts/lib/session-record-repair.mjs +245 -35
- package/scripts/lib/session-registry.mjs +85 -12
- package/scripts/lib/session-schema/constants.mjs +9 -0
- package/scripts/lib/session-schema/filters.mjs +56 -1
- package/scripts/lib/session-schema/validator.mjs +15 -5
- package/scripts/lib/session-start-probes.mjs +149 -22
- package/scripts/lib/session-token-rollup.mjs +2 -1
- package/scripts/lib/session-work-trees.mjs +166 -0
- package/scripts/lib/sessions-canonical.mjs +61 -3
- package/scripts/lib/sessions-integrity-banner.mjs +17 -39
- package/scripts/lib/sessions-staleness-banner.mjs +8 -5
- package/scripts/lib/sh-quote.mjs +1 -0
- package/scripts/lib/skill-evidence-window.mjs +5 -1
- package/scripts/lib/skill-health/join.mjs +10 -9
- package/scripts/lib/skill-invocations-schema.mjs +13 -0
- package/scripts/lib/skill-judgments-schema.mjs +6 -2
- package/scripts/lib/snapshot-probe.mjs +414 -0
- package/scripts/lib/so-hud/collect.mjs +174 -0
- package/scripts/lib/so-hud/runtime.mjs +87 -0
- package/scripts/lib/spiral-carryover.mjs +8 -1
- package/scripts/lib/state-md/frontmatter-mutators.mjs +266 -8
- package/scripts/lib/state-md/idle-reset.mjs +248 -0
- package/scripts/lib/state-md/mission-status.mjs +5 -1
- package/scripts/lib/state-md/recommendations.mjs +26 -4
- package/scripts/lib/state-md-peer-guard.mjs +2 -0
- package/scripts/lib/state-md.mjs +31 -8
- package/scripts/lib/sunset/walker.mjs +4 -3
- package/scripts/lib/telemetry/consent.mjs +4 -2
- package/scripts/lib/telemetry/queue.mjs +3 -3
- package/scripts/lib/telemetry/sync.mjs +45 -9
- package/scripts/lib/test-runner/artifact-paths.mjs +10 -2
- package/scripts/lib/tmux-layout/layouts.mjs +20 -3
- package/scripts/lib/ux-grill/paths.mjs +5 -1
- package/scripts/lib/validate/check-agents.mjs +37 -6
- package/scripts/lib/validate/check-component-paths.mjs +25 -1
- package/scripts/lib/validate/check-guard-requires-parity.mjs +3 -3
- package/scripts/lib/validate/check-hooks-symmetry.mjs +53 -32
- package/scripts/lib/validate/check-json-files.mjs +3 -1
- package/scripts/lib/validate/check-learning-provenance.mjs +3 -2
- package/scripts/lib/validate/check-learnings-shell-writes.mjs +10 -4
- package/scripts/lib/validate/check-metrics-ledger-root.mjs +234 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +159 -11
- package/scripts/lib/validate/check-test-posix-shell.mjs +246 -0
- package/scripts/lib/validate/check-unwired-features.mjs +4 -2
- package/scripts/lib/validate/check-vcs-repo-flag-positional.mjs +58 -0
- package/scripts/lib/validate/check-vcs-repo-flag.mjs +259 -73
- package/scripts/lib/validate/check-workflow-continue-on-error.mjs +63 -0
- package/scripts/lib/validate/confidential-names.mjs +3 -1
- package/scripts/lib/vault-mirror/migrate-ids.mjs +321 -0
- package/scripts/lib/vault-mirror/namespace.mjs +22 -9
- package/scripts/lib/vault-mirror/process.mjs +197 -65
- package/scripts/lib/vault-mirror/prune.mjs +5 -2
- package/scripts/lib/vault-mirror/render-learnings.mjs +8 -7
- package/scripts/lib/vault-mirror/render-sessions.mjs +36 -53
- package/scripts/lib/vault-mirror/retention.mjs +2 -2
- package/scripts/lib/vault-mirror/utils.mjs +106 -13
- package/scripts/lib/vault-staleness-banner.mjs +4 -7
- package/scripts/lib/vault-status/board-writer.mjs +34 -5
- package/scripts/lib/vault-status/narrative-mirror.mjs +66 -7
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +20 -0
- package/scripts/lib/win-process-tree.mjs +137 -0
- package/scripts/lib/workspace.mjs +1 -1
- package/scripts/lib/worktree/constants.mjs +1 -1
- package/scripts/lib/worktree/lifecycle.mjs +1 -1
- package/scripts/lib/worktree/listing.mjs +1 -1
- package/scripts/lib/zx.mjs +50 -0
- package/scripts/mcp-server.mjs +16 -7
- package/scripts/mcp-server.sh +13 -83
- package/scripts/measure-policy-cache-effectiveness.mjs +7 -5
- package/scripts/memory-propose.mjs +10 -3
- package/scripts/migrate-cold-start-seed.mjs +7 -0
- package/scripts/migrate-legacy-learnings.sh +22 -0
- package/scripts/migrate-sessions-jsonl.mjs +16 -2
- package/scripts/migrate-vault-paths.mjs +29 -13
- package/scripts/parse-config.mjs +71 -14
- package/scripts/print-learnings-index.mjs +25 -2
- package/scripts/release-session-lock.mjs +94 -7
- package/scripts/release.mjs +451 -24
- package/scripts/relocate-vault-corpus.mjs +11 -7
- package/scripts/repair-invalid-sessions.mjs +68 -3
- package/scripts/resolve-session-invocation.mjs +57 -8
- package/scripts/run-migrate-v2-cross-repo.mjs +56 -1
- package/scripts/run-quality-gate.mjs +33 -7
- package/scripts/self-update.mjs +56 -7
- package/scripts/session-commit-files.mjs +133 -0
- package/scripts/site-numbers.mjs +52 -9
- package/scripts/snapshot-probe.mjs +156 -0
- package/scripts/so-hud.mjs +68 -0
- package/scripts/state-md-idle-reset.mjs +82 -0
- package/scripts/sweep-expired-learnings.mjs +54 -6
- package/scripts/sweep-expired-rules.mjs +4 -1
- package/scripts/validate-plugin.mjs +22 -0
- package/scripts/vault-integration-watcher.mjs +54 -6
- package/scripts/vault-mirror.mjs +9 -0
- package/scripts/vault-orphans.mjs +171 -0
- package/skills/_shared/fleet-protocol.md +166 -3
- package/skills/_shared/instruction-file-resolution.md +1 -1
- package/skills/_shared/monitor-patterns.md +44 -25
- package/skills/_shared/platform-tools.md +7 -0
- package/skills/_shared/state-ownership.md +5 -4
- package/skills/architecture/references/domain-model.md +1 -1
- package/skills/autopilot/SKILL.md +3 -2
- package/skills/bootstrap/SKILL.md +3 -1
- package/skills/bootstrap/_shared-template.md +4 -4
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/bootstrap/private-contract.md +1 -1
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +17 -9
- package/skills/bootstrap/templates/agents/project-code-review.md +5 -1
- package/skills/bootstrap/templates/agents/project-discovery.md +5 -1
- package/skills/bootstrap/templates/agents/project-quality-gate.md +5 -1
- package/skills/claude-md-drift-check/SKILL.md +3 -3
- package/skills/claude-md-drift-check/checker.mjs +61 -101
- package/skills/close/SKILL.md +20 -7
- package/skills/discovery/probes/docs-staleness.mjs +7 -5
- package/skills/discovery/probes/frontend-slop.mjs +7 -3
- package/skills/discovery/probes/ssot-code-diff.mjs +5 -3
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +10 -8
- package/skills/discovery/probes/vault-narrative-staleness.mjs +30 -10
- package/skills/discovery/probes/vault-staleness.mjs +5 -3
- package/skills/discovery/probes-session.md +3 -0
- package/skills/discovery/probes-vault.md +2 -0
- package/skills/dispatcher/SKILL.md +1 -1
- package/skills/eval/SKILL.md +3 -1
- package/skills/evolve/SKILL.md +2 -0
- package/skills/evolve/references/evolve-analyze-mode.md +3 -3
- package/skills/evolve/references/evolve-dialectic-mode.md +1 -1
- package/skills/gitlab-ops/SKILL.md +7 -6
- package/skills/gitlab-portfolio/SKILL.md +2 -2
- package/skills/go/SKILL.md +13 -1
- package/skills/npm-publish/SKILL.md +5 -2
- package/skills/plan/SKILL.md +23 -10
- package/skills/plan/mode-feature.md +13 -8
- package/skills/plan/mode-new.md +6 -14
- package/skills/plan/prd-feature-template.md +19 -0
- package/skills/plan/prd-full-template.md +12 -5
- package/skills/plan/prd-premortem-panel.md +48 -0
- package/skills/plan/prd-reviewer-prompt.md +11 -3
- package/skills/plan/soul.md +1 -1
- package/skills/portfolio/SKILL.md +5 -6
- package/skills/quality-gates/SKILL.md +2 -4
- package/skills/reconcile/SKILL.md +27 -4
- package/skills/release/SKILL.md +16 -8
- package/skills/session-end/SKILL.md +97 -13
- package/skills/session-end/phase-3-2-docs-verification.md +1 -0
- package/skills/session-end/phase-3-6-tail.md +11 -7
- package/skills/session-end/phase-3-7a-recommendations.md +9 -2
- package/skills/session-end/plan-verification.md +16 -1
- package/skills/session-end/references/phase-3-7e-vault-orphans.md +63 -0
- package/skills/session-end/references/phase-3-documentation-updates.md +25 -13
- package/skills/session-end/references/phase-5-issue-cleanup.md +1 -1
- package/skills/session-end/references/session-summary-template.md +8 -0
- package/skills/session-end/session-metrics-write.md +7 -4
- package/skills/session-plan/SKILL.md +5 -3
- package/skills/session-start/SKILL.md +10 -4
- package/skills/session-start/phase-4-5-resource-health.md +11 -5
- package/skills/session-start/phase-7-5-mode-selector.md +3 -1
- package/skills/session-start/phase-8-5-express-path.md +4 -3
- package/skills/session-start/references/phase-1-2-session-lock.md +7 -5
- package/skills/session-start/references/phase-1-5-session-continuity.md +13 -5
- 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 +3 -2
- package/skills/tmux-layout/SKILL.md +2 -2
- package/skills/vault-sync/validator.mjs +3 -2
- package/skills/wave-executor/SKILL.md +5 -4
- package/skills/wave-executor/references/wave-executor-state-init.md +3 -3
- package/skills/wave-executor/references/wave-loop-dispatch.md +11 -5
- package/skills/wave-executor/references/wave-loop-review.md +13 -5
- package/skills/wave-executor/references/wave-loop-scope-manifest.md +1 -1
- package/AGENTS.md +0 -207
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +0 -47
- package/assets/wave-lifecycle.svg +0 -98
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2023", "lib": ["es2023"], "types": [], "module": "esnext",
|
|
4
|
+
"moduleResolution": "bundler", "strict": true, "noUncheckedIndexedAccess": true,
|
|
5
|
+
"noEmit": true, "skipLibCheck": true, "jsx": "react", "jsxFactory": "h", "jsxFragmentFactory": "Fragment"
|
|
6
|
+
},
|
|
7
|
+
"include": [".claude-plugin/types", "hooks", "types", "tests"]
|
|
8
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Standalone public wire contract; null means unmeasured. Engine nouns are asynchronous. */
|
|
2
|
+
export type SoProfile = 'locker' | 'ausgewogen' | 'streng'
|
|
3
|
+
export type SoState = 'arbeitet' | 'wartet' | 'bereit' | 'blockiert' | 'unbekannt'
|
|
4
|
+
export interface SoBeacon {
|
|
5
|
+
schema_version: 1; session_id: string; name: string | null; repo_name: string | null
|
|
6
|
+
branch: string | null; pid: number | null; zustand: SoState; seit: string
|
|
7
|
+
warte_grund: 'dialog' | 'freigabe' | 'frage' | null; heuristisch: boolean
|
|
8
|
+
kontext_prozent: number | null; letzter_request_at: string | null; modell: string | null
|
|
9
|
+
welle: number | null; aktualisiert_at: string
|
|
10
|
+
}
|
|
11
|
+
export interface SoSnapshot {
|
|
12
|
+
schema_version: 1; measured_at: string; age_ms: number
|
|
13
|
+
repo: { root: string; name: string }
|
|
14
|
+
lock: { session_id: string | null; live: boolean; last_heartbeat: string | null } | null
|
|
15
|
+
session: { session_id: string; semantic_session_id: string | null } | null
|
|
16
|
+
wave: { running: boolean | null; number: number | null; role: string | null; agents_total: number | null; source: string | null }
|
|
17
|
+
agents: { entries: { id: string; typ: string | null; modellfamilie: string | null; status: string | null; tokens: null; letzter_request_at: null; quelle: string }[]; source: string | null; at: string | null; degraded: unknown
|
|
18
|
+
/** Running agents of this session; null when unknown (see stale_reason). Absent from collectors before #1580. */
|
|
19
|
+
running?: number | null
|
|
20
|
+
/** Why `running` is null: 'no-session', 'cache-unverifiable', 'no-session-start' or 'older-than-session'; null when measured. */
|
|
21
|
+
stale_reason?: string | null
|
|
22
|
+
/** Agents still running without a Stop past 24 h, counted apart from `running`; absent from older collectors. */
|
|
23
|
+
decayed?: number | null }
|
|
24
|
+
state: { status: string | null; session_type: string | null; current_wave: number | null; total_waves: number | null }
|
|
25
|
+
gate: { last: { variant: string | null; passed: boolean | null; check_failed: boolean | null; exit_code: number | null; at: string | null } | null; last_green_sha: string | null }
|
|
26
|
+
peers: { session_id: string; branch: string | null; status: string | null; current_wave: number | null; last_heartbeat: string | null; gleiches_working_copy: boolean; scope_paths: string[] | null }[]
|
|
27
|
+
vault: { enabled: boolean | null; mode: string | null; last_run: { at: string | null; created: number | null; updated: number | null; failed: number | null; aborted: string | null } | null; board: { action: string | null; at: string | null } | null }
|
|
28
|
+
degraded: string[]
|
|
29
|
+
}
|
|
30
|
+
export interface So {
|
|
31
|
+
version(): 1
|
|
32
|
+
snapshot(): Promise<SoSnapshot | null>
|
|
33
|
+
beacons(): Promise<SoBeacon[]>
|
|
34
|
+
profile(): SoProfile
|
|
35
|
+
}
|
|
36
|
+
declare module 'claude-code' { interface EngineInterface { so: So } }
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "session-orchestrator",
|
|
3
|
-
"version": "5.
|
|
4
|
-
"description": "Your coding agents get an agreed plan, a check after each round of changes and a handover to the next session.
|
|
3
|
+
"version": "5.13.0",
|
|
4
|
+
"description": "Your coding agents get an agreed plan, a check after each round of changes and a handover to the next session. For Claude Code, Codex CLI, Cursor and Pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://session-orchestrator.com",
|
|
7
7
|
"keywords": [
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
".mcp.json",
|
|
31
|
-
"AGENTS.md",
|
|
32
31
|
"CHANGELOG.md",
|
|
33
32
|
"pi/",
|
|
34
33
|
"skills/",
|
|
@@ -44,6 +43,8 @@
|
|
|
44
43
|
"evals/",
|
|
45
44
|
"!evals/results/**",
|
|
46
45
|
"!assets/marketing/**",
|
|
46
|
+
"mods/so-hud/",
|
|
47
|
+
"!mods/so-hud/tests/**",
|
|
47
48
|
".claude-plugin/",
|
|
48
49
|
".codex-plugin/",
|
|
49
50
|
".cursor-plugin/",
|
package/rules/_index.md
CHANGED
|
@@ -39,7 +39,7 @@ baseline project type (`nextjs-saas`, `express-service`, `docker-service`,
|
|
|
39
39
|
- `always-on/test-value.md` — TV-001..005: name the bug a test catches, or do not write it; deletion is a feature
|
|
40
40
|
- `always-on/build-value.md` — BV-001..004: the seven-rung build ladder, the four protections never simplified away
|
|
41
41
|
- `always-on/cross-session-messaging.md` — CSM-001..005: messaging is transport, not shared state; no permission laundering
|
|
42
|
-
- `always-on/loop-and-monitor.md` — LM-001..008: routing between `/goal`, Workflows, Channels, Monitor, `/loop`, and Routines
|
|
42
|
+
- `always-on/loop-and-monitor.md` — LM-001..008: routing between `/goal`, Workflows, Channels, Monitor, `/loop`, and Routines (short form ≤ 4 kB; long form with filter examples in `docs/reference/loop-and-monitor-routing.md`, not vendored — #1624)
|
|
43
43
|
- `always-on/bash-harness-pitfalls.md` — six false-green shell-harness failure classes (path-scoped via `globs:` + `paths:` frontmatter carrying identical lists — `paths:` is what Claude Code reads, `globs:` what `rule-loader.mjs` reads first; #1449)
|
|
44
44
|
|
|
45
45
|
## opt-in-stack (vendored on match)
|
|
@@ -30,7 +30,7 @@ AskUserQuestion({ questions: [{
|
|
|
30
30
|
], multiSelect: false }]})
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Weigh every realistic option, not just two: 2–4 options, 1–4 questions per call. Option 1 is the recommendation, labelled `(Recommended)`. Each description gives reason, cost and consequence; one that only restates its label is a rule break. One plain-words (eli5) sentence in the question or a description carries the core and drops no fact (AUQ-006).
|
|
34
34
|
|
|
35
35
|
- ✓ "Blocker for the next wave; ~20 min; freezes plan scope until it lands."
|
|
36
36
|
- ✗ "Fix the bug now."
|
|
@@ -1,220 +1,43 @@
|
|
|
1
1
|
<!-- source: session-orchestrator plugin (canonical: rules/always-on/loop-and-monitor.md) -->
|
|
2
2
|
# Loop & Monitor Routing (Always-on)
|
|
3
3
|
|
|
4
|
-
`/goal`,
|
|
5
|
-
scheduled desktop tasks share the "recurring, polling-style, or keep-going-
|
|
6
|
-
until-done work" slot but are **not interchangeable**. Picking the wrong
|
|
7
|
-
primitive wastes tokens, masks failures, or loses durability. This rule
|
|
8
|
-
encodes the routing decision once so future sessions do not re-derive it.
|
|
9
|
-
|
|
10
|
-
Version gates move; the routing does not. Check the primitive's availability in
|
|
11
|
-
your harness before wiring anything load-bearing onto it, and keep a fallback.
|
|
4
|
+
`/goal`, Workflow, Channels, Monitor, `/loop` and Routines share the "keep going / keep watching" slot but are not interchangeable. Check each primitive's availability in your harness before relying on it, and keep a fallback.
|
|
12
5
|
|
|
13
6
|
## LM-001: Decision Tree — Pick the Primitive First
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
├─ Yes → /goal.
|
|
22
|
-
│ Continuation across turns until the condition is model-evaluated.
|
|
23
|
-
│ (Completion-condition axis — see LM-008.)
|
|
24
|
-
│ Pair with deterministic gates — /goal judges; it never verifies.
|
|
25
|
-
│ NOT: "until CI goes green" — that is an EXTERNAL stream the
|
|
26
|
-
│ evaluator cannot see → Monitor (next branch).
|
|
27
|
-
│
|
|
28
|
-
└─ No → Is this a ONE-SHOT fan-out across many independent units (codebase-
|
|
29
|
-
wide audit, large migration, multi-angle cross-checked research)
|
|
30
|
-
needing dozens-to-hundreds of subagents one conversation cannot
|
|
31
|
-
coordinate?
|
|
32
|
-
│
|
|
33
|
-
├─ Yes → dynamic Workflow.
|
|
34
|
-
│ Codifies the plan as a rerunnable script; the main context
|
|
35
|
-
│ holds only the final result, not the per-agent chatter.
|
|
36
|
-
│ NOT a recurring primitive — for repeated polling stay on the
|
|
37
|
-
│ axes below. (Fan-out axis — see LM-002b.)
|
|
38
|
-
│
|
|
39
|
-
└─ No → Is the event PUSHABLE from an external system (CI webhook,
|
|
40
|
-
error tracker, chat)?
|
|
41
|
-
│
|
|
42
|
-
├─ Yes → Channels.
|
|
43
|
-
│ The source pushes the event into the open session via
|
|
44
|
-
│ a channel plugin — zero polling, reacts while you're
|
|
45
|
-
│ away. (Push-based sibling of Monitor — see LM-002a.)
|
|
46
|
-
│
|
|
47
|
-
└─ No → Is the watched thing a STREAM I can tail (logs, file
|
|
48
|
-
changes, CI status transitions, a JSONL telemetry
|
|
49
|
-
file)?
|
|
50
|
-
│
|
|
51
|
-
├─ Yes → Monitor.
|
|
52
|
-
│ Each stdout line = one notification. Zero
|
|
53
|
-
│ polling tokens.
|
|
54
|
-
│
|
|
55
|
-
└─ No → Is the watched thing PERIODIC and bounded by
|
|
56
|
-
THIS conversation (days, not weeks;
|
|
57
|
-
resume/continue restoration acceptable)?
|
|
58
|
-
│
|
|
59
|
-
├─ Yes → /loop.
|
|
60
|
-
│ Use dynamic mode unless the cadence
|
|
61
|
-
│ is genuinely fixed.
|
|
62
|
-
│
|
|
63
|
-
└─ No → Cloud Routines or desktop scheduled
|
|
64
|
-
tasks. Daily notes, weekly audits,
|
|
65
|
-
cross-repo sweeps. /loop CANNOT
|
|
66
|
-
cover these — it fires only while
|
|
67
|
-
the agent runtime is running.
|
|
68
|
-
```
|
|
7
|
+
In order, first match wins:
|
|
8
|
+
1. Finite objective whose done-condition the model's own surfaced output can demonstrate: `/goal` (LM-008). External CI-green is invisible to its evaluator: use Monitor.
|
|
9
|
+
2. One-shot fan-out over many independent units, too large for one conversation: Workflow (LM-002b).
|
|
10
|
+
3. Event the source can push (CI webhook, error tracker, chat): Channels (LM-002a).
|
|
11
|
+
4. Stream you can tail (logs, file changes, CI transitions, JSONL): Monitor (LM-002).
|
|
12
|
+
5. Periodic and bound to THIS conversation (days, resume acceptable): `/loop`, dynamic unless the cadence is truly fixed (LM-003).
|
|
13
|
+
6. Durable, offline, overnight or cross-repo: cloud Routines or desktop scheduled tasks (LM-004).
|
|
69
14
|
|
|
70
15
|
## LM-002: Use Monitor When …
|
|
71
|
-
|
|
72
|
-
Use Monitor when the watched thing is a STREAM you can tail — a long-running
|
|
73
|
-
build/test suite emitting progress to stdout, a CI pipeline you poll-then-stream
|
|
74
|
-
(`glab ci status`, `gh pr checks --watch`), an accumulating error log
|
|
75
|
-
(`tail -f` + `grep --line-buffered`), a JSONL telemetry stream, or a filesystem
|
|
76
|
-
event (`inotifywait -m`). Each stdout line is one notification; zero polling
|
|
77
|
-
tokens.
|
|
78
|
-
|
|
79
|
-
**Coverage rule (load-bearing).** A Monitor filter must match every terminal
|
|
80
|
-
state, not just the happy path. *Silence is not success.*
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
# WRONG — silent on crash, hang, or any non-success exit
|
|
84
|
-
tail -f run.log | grep --line-buffered "elapsed_steps="
|
|
85
|
-
|
|
86
|
-
# RIGHT — alternation covers progress + every failure signature
|
|
87
|
-
tail -f run.log | grep -E --line-buffered "elapsed_steps=|Traceback|Error|FAILED|assert|Killed|OOM"
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
If you cannot enumerate failure signatures, broaden the alternation rather than
|
|
91
|
-
narrow it. Some extra noise beats missing a crashloop.
|
|
16
|
+
Tailing builds, tests, CI, logs or file events. The filter MUST match progress AND every terminal failure state; silence is not success. If failure signatures cannot be enumerated, broaden the filter. A watch expires; expiry is an exit notice, never success, so re-arm if still needed. In unattended `-p` runs, wait in bounded foreground commands and read the real exit: background tasks and Monitor watches do not keep the run alive after the turn ends.
|
|
92
17
|
|
|
93
18
|
## LM-002a: Use Channels When …
|
|
94
|
-
|
|
95
|
-
Channels is the **push-based sibling of Monitor**: an external system pushes the
|
|
96
|
-
event into your open session via a channel plugin (CI webhook, error tracker,
|
|
97
|
-
chat) — zero polling, reacts while you are away. Choose Channels over Monitor
|
|
98
|
-
when the source can PUSH (you register a webhook endpoint) rather than be TAILED
|
|
99
|
-
(`tail -f` / `glab ci status`); when it can only be polled or tailed, stay on
|
|
100
|
-
Monitor. Treat it as preview-grade — do not wire a load-bearing automation onto
|
|
101
|
-
it without a Monitor or `/loop` fallback.
|
|
19
|
+
The source can push. Research preview: never load-bearing without a Monitor or `/loop` fallback. Session-to-session text is messaging, not Channels.
|
|
102
20
|
|
|
103
21
|
## LM-002b: Use Workflows When …
|
|
104
|
-
|
|
105
|
-
Dynamic **Workflows** is the **one-shot fan-out** primitive — distinct from every
|
|
106
|
-
recurring/polling axis. Reach for it when a single objective decomposes into many
|
|
107
|
-
independent units one conversation cannot coordinate: a codebase-wide audit, a
|
|
108
|
-
large migration, a multi-angle research sweep. The model plans once, codifies a
|
|
109
|
-
rerunnable script, fans out subagents, and returns only the final result.
|
|
110
|
-
|
|
111
|
-
**Never reimplement a one-shot fan-out as `/loop`.** A `/loop` body re-runs a
|
|
112
|
-
single coordinator prompt on an interval; it has no native fan-out, no
|
|
113
|
-
agent-count cap, and no rerunnable-script artifact.
|
|
114
|
-
|
|
115
|
-
**Distinct from in-run agent teams.** Workflows' one-shot fan-out is unrelated to
|
|
116
|
-
experimental in-run multi-agent coordination within a single live session — see
|
|
117
|
-
`parallel-sessions.md` § PSA Scope Axes for that boundary.
|
|
118
|
-
|
|
119
|
-
**Do not swap a purpose-built wave orchestrator for a bare Workflow.** A
|
|
120
|
-
Workflow's agent-count caps are bounds, not kill-switches, and it ships no
|
|
121
|
-
per-run telemetry artifact. If your orchestration has stop conditions and an
|
|
122
|
-
audit trail, a Workflow does not replace them.
|
|
22
|
+
One-shot independent fan-out. Never emulate fan-out with `/loop`; never replace an orchestrator that owns kill-switches and telemetry with a bare Workflow.
|
|
123
23
|
|
|
124
24
|
## LM-003: Use `/loop` When …
|
|
125
|
-
|
|
126
|
-
Use `/loop` when the check is genuinely periodic (no streamable trigger) and
|
|
127
|
-
bounded by THIS conversation — a staleness check during a multi-hour session, a
|
|
128
|
-
backlog snapshot during long-running work, branch-tending while waiting on
|
|
129
|
-
review. Wire a custom maintenance loop into `.claude/loop.md` (project) or
|
|
130
|
-
`~/.claude/loop.md` (user). Scheduled tasks fire only while the agent runtime is
|
|
131
|
-
running; unexpired tasks restore on `--resume`/`--continue`.
|
|
132
|
-
|
|
133
|
-
**Cadence — pick by observation-rate, not by the cache.** Choose the interval
|
|
134
|
-
from how fast the watched thing changes: about a minute to a few minutes when a
|
|
135
|
-
state transition is imminent, five to twenty minutes for steady-state polling,
|
|
136
|
-
twenty minutes to an hour for idle maintenance. The runtime clamps a self-paced
|
|
137
|
-
wakeup to roughly [60s, 3600s]. Under a short (5-minute) prompt-cache TTL, avoid
|
|
138
|
-
a cadence that lands exactly on the cache cliff — you pay the miss without
|
|
139
|
-
amortising it.
|
|
140
|
-
|
|
141
|
-
**Limits & kill-switches (load-bearing).** A single environment variable
|
|
142
|
-
(`CLAUDE_CODE_DISABLE_CRON=1`) disables the cron scheduler AND `/loop` entirely —
|
|
143
|
-
not just one task. Each session is capped at a few dozen scheduled tasks. Both
|
|
144
|
-
`.claude/loop.md` and `~/.claude/loop.md` are TRUNCATED past **25,000 bytes** —
|
|
145
|
-
keep the loop body lean; a bloated body silently loses its tail rather than
|
|
146
|
-
erroring.
|
|
25
|
+
Periodic, no stream, this conversation. Pace by observation rate: imminent change 60–270 s, steady polling 300–1200 s, idle 1200–3600 s. Loop body files truncate past 25,000 bytes; keep them lean. `CLAUDE_CODE_DISABLE_CRON=1` disables `/loop` and the scheduler entirely.
|
|
147
26
|
|
|
148
27
|
## LM-004: Use Routines / Scheduled Tasks When …
|
|
149
|
-
|
|
150
|
-
Use cloud Routines or desktop scheduled tasks when the work must run when no
|
|
151
|
-
session is open (overnight, weekly, monthly), spans repos no single session can
|
|
152
|
-
witness, or must persist across machine restarts. `/loop` is the wrong tool here
|
|
153
|
-
— it fires only while the agent runtime is running; `--resume`/`--continue`
|
|
154
|
-
restoration is not durable unattended scheduling.
|
|
28
|
+
Work must survive the session: nightly, weekly, cross-repo, restart-durable. Resume restoration is not unattended scheduling.
|
|
155
29
|
|
|
156
30
|
## LM-005: Never Reimplement These as `/loop`
|
|
157
|
-
|
|
158
|
-
- **A driver that already has its own kill-switches and telemetry.** Wrapping it
|
|
159
|
-
in `/loop` loses both. Pair them — never replace.
|
|
160
|
-
- **Synchronous inter-wave checkpoints.** They are synchronous by design.
|
|
161
|
-
- **Quality gates** (typecheck, test, lint). These block on purpose. Run them
|
|
162
|
-
once, sequentially.
|
|
163
|
-
- **Hook-served events.** `PostToolUse`, `Stop`, `SubagentStop` already fire at
|
|
164
|
-
the right moment. A `/loop` poll on top is redundant.
|
|
165
|
-
- **`/goal`.** Do not hand-roll a per-turn Stop-hook prompt evaluator to keep
|
|
166
|
-
working until a condition holds — `/goal` IS that mechanism, natively.
|
|
167
|
-
Re-implementing it as a custom Stop hook or a `/loop` body duplicates the
|
|
168
|
-
machinery and loses the built-in restore and clear lifecycle. See LM-008.
|
|
169
|
-
- **One-shot subagent fan-out.** A codebase-wide audit / large migration /
|
|
170
|
-
multi-angle research sweep is a dynamic Workflow, not a `/loop`. See LM-002b.
|
|
31
|
+
Autonomous drivers with their own kill-switches, synchronous inter-step quality gates, hook events you already receive, and `/goal` itself (never rebuild it as a custom Stop hook). Pair with them instead.
|
|
171
32
|
|
|
172
33
|
## LM-006: Destructive-Action Safeguards Apply
|
|
173
|
-
|
|
174
|
-
A `/loop` body is a coordinator prompt that runs every iteration. Treat it as you
|
|
175
|
-
would any coordinator action:
|
|
176
|
-
|
|
177
|
-
- **No destructive operations** (`git push`, `git reset`, `rm`, merging an MR,
|
|
178
|
-
closing an issue) without explicit transcript authorisation for the specific
|
|
179
|
-
action.
|
|
180
|
-
- **Track your footprint.** A loop that "tidies up" untracked files may delete
|
|
181
|
-
another session's work-in-progress. See `parallel-sessions.md`.
|
|
182
|
-
- **Read-only first.** When in doubt, observe and report.
|
|
34
|
+
Every loop iteration is an ordinary action: no push, reset, delete, merge or issue close without explicit authorization for that action. When unsure, observe and report read-only.
|
|
183
35
|
|
|
184
36
|
## LM-007: Anti-Patterns
|
|
185
|
-
|
|
186
|
-
- Fixed `/loop 5m …` to babysit a CI run — use Monitor on `glab ci status` or `gh pr checks --watch` instead (LM-002).
|
|
187
|
-
- `/loop 1d …` for a daily note — use Routines or desktop tasks; `/loop` does not fire while the agent runtime is stopped (LM-004).
|
|
188
|
-
- A Monitor filter matching only the success marker — silence from a crash is indistinguishable from success (LM-002 coverage rule).
|
|
189
|
-
- `/loop` wrapping an autonomous driver — duplicates loop semantics and hides its kill-switches (LM-005).
|
|
190
|
-
- A cadence sitting exactly on a short prompt-cache TTL boundary — you pay the cache miss without amortising it (LM-003).
|
|
191
|
-
- Using `/goal` as a quality gate — the evaluator reads the transcript only; pair `/goal` with a deterministic exit-code gate (LM-008).
|
|
192
|
-
- Unbounded `/goal` with no turn/time-bound clause — always embed "or stop after N turns / M minutes" (LM-008).
|
|
193
|
-
- Hand-rolling a one-shot fan-out as a `/loop` body — use a Workflow (LM-002b).
|
|
37
|
+
Wrong routing, success-only filters, unbounded goals, a goal used as a gate, and caps mistaken for kill-switches.
|
|
194
38
|
|
|
195
39
|
## LM-008: Use `/goal` When …
|
|
196
|
-
|
|
197
|
-
`/goal <condition>` keeps the model working across turns until a stated
|
|
198
|
-
completion condition is confirmed — a session-scoped, prompt-based Stop hook
|
|
199
|
-
where a small, fast evaluator reads the condition plus the conversation each turn
|
|
200
|
-
and returns yes/no with a reason. Cost is typically negligible. Use it for a
|
|
201
|
-
**finite objective** that needs multiple turns to converge and whose
|
|
202
|
-
done-condition is **demonstrable from the model's own surfaced output** — the
|
|
203
|
-
evaluator runs NO tools, so surface the evidence (paste the test summary, echo
|
|
204
|
-
the worklist, print the state). Write conditions the transcript can demonstrate
|
|
205
|
-
("all referenced tests show as passing in the output" works; "the production
|
|
206
|
-
database is consistent" does not). **Always embed a bound** ("or stop after 20
|
|
207
|
-
turns / 30 minutes") so a non-converging goal terminates.
|
|
208
|
-
|
|
209
|
-
**The load-bearing caveat — `/goal` provides CONTINUATION plus model-evaluated
|
|
210
|
-
JUDGMENT, never deterministic VERIFICATION.** The evaluator judges the condition
|
|
211
|
-
from the transcript; it does not run verification tools. Deterministic quality
|
|
212
|
-
gates remain the source of truth: the project's test, typecheck, and lint
|
|
213
|
-
commands and their **exit codes** decide whether work is correct. Never replace
|
|
214
|
-
an exit-code gate with a model vote. The correct pattern is a goal whose
|
|
215
|
-
condition references freshly-run gate output ("…until the test command prints 0
|
|
216
|
-
failures **in this turn's output**"), backed by an actual gate run each turn —
|
|
217
|
-
not a goal that asserts success on its own.
|
|
40
|
+
Finite multi-turn objective. The evaluator runs no tools: surface fresh evidence (test summary, worklist, state) in the transcript, and always embed a bound ("or stop after 20 turns / 30 minutes"). `/goal` gives continuation and model judgment, never verification: fresh test/typecheck/lint exit codes decide, run each turn.
|
|
218
41
|
|
|
219
42
|
## See Also
|
|
220
43
|
|
|
@@ -157,6 +157,8 @@ The git index and stash are **shared resources of the working copy**, not a priv
|
|
|
157
157
|
|
|
158
158
|
**The only write channel a subagent has is editing files inside its own declared file scope.** All VCS operations — staging, committing, pushing — belong to the coordinator. This makes the PSA-004 guarantee structural rather than behavioural at the subagent layer: an agent that never touches the index cannot violate PSA-004 by construction.
|
|
159
159
|
|
|
160
|
+
**Sole exception — worktree mode (`code-implementer` only).** It may stage its own files one by one (`git add <file>`) and `git commit` only when its prompt carries a line `WORKTREE-MODE: <absolute path> <branch>` AND `git rev-parse --show-toplevel` and `git branch --show-current` match that path and branch; otherwise the ban applies unchanged. A linked worktree has its own index, so the index race above does not exist there. The commit hook briefly adds an entry to the shared stash via lint-staged; the agent itself never runs `git stash`. Coordinator duty: never grant the coordinator's own worktree, never put two agents in one worktree. The wave-executor never sets the line. `git push`, merge, `git reset`, `git stash` and `git clean` stay banned in every mode, and the coordinator still publishes.
|
|
161
|
+
|
|
160
162
|
**Anti-patterns:**
|
|
161
163
|
- A subagent running `git add <its own files>` "to be helpful" before reporting done — even scoped to its own files, it races the coordinator's staging pass and any sibling's concurrent index write.
|
|
162
164
|
- A subagent running `git stash` to "save progress" before switching tasks — report `blocked` and let the coordinator decide, never stash.
|
|
@@ -170,4 +172,4 @@ The git index and stash are **shared resources of the working copy**, not a priv
|
|
|
170
172
|
- Using `git add .` in a shared workspace — you will commit another session's partial work.
|
|
171
173
|
- Reverting "broken" commits without asking — another session may have intentionally pushed incremental progress.
|
|
172
174
|
- Pausing at PSA-001 signals when your scope is unaffected — unnecessary interruptions slow the session.
|
|
173
|
-
- A subagent staging or committing
|
|
175
|
+
- A subagent staging or committing without a matching `WORKTREE-MODE` line, or as any agent other than `code-implementer` (PSA-007).
|
|
@@ -193,4 +193,4 @@ async function updateUser(id: string, data: Partial<User>): Promise<void> {
|
|
|
193
193
|
- Batch operations: use `.upsert()` or `.insert()` with arrays instead of individual inserts in loops.
|
|
194
194
|
|
|
195
195
|
## See Also
|
|
196
|
-
security-web.md · frontend.md · backend.md ·
|
|
196
|
+
security-web.md · frontend.md · backend.md · parallel-sessions.md
|
|
@@ -393,4 +393,4 @@ export async function askAI(prompt: string, options?: { model?: string; maxToken
|
|
|
393
393
|
- Checking budget after the LLM call (check before, enforce before spending)
|
|
394
394
|
|
|
395
395
|
## See Also
|
|
396
|
-
|
|
396
|
+
parallel-sessions.md · vendored only for some archetypes, so possibly absent in this repo: security-web.md [nextjs-saas, nextjs-minimal, express-service] · frontend.md [nextjs-saas, nextjs-minimal] · backend-data.md [nextjs-saas]
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
globs:
|
|
3
3
|
- src/middleware*.ts
|
|
4
|
+
- proxy.ts
|
|
5
|
+
- src/proxy.ts
|
|
4
6
|
- src/app/**
|
|
5
7
|
- next.config.*
|
|
6
8
|
- src/lib/csp*
|
|
7
9
|
- src/lib/cors*
|
|
8
10
|
paths:
|
|
9
11
|
- src/middleware*.ts
|
|
12
|
+
- proxy.ts
|
|
13
|
+
- src/proxy.ts
|
|
10
14
|
- src/app/**
|
|
11
15
|
- next.config.*
|
|
12
16
|
- src/lib/csp*
|
|
@@ -197,4 +201,4 @@ securityMiddleware(app);
|
|
|
197
201
|
- **Template Literals**: Never use tagged template literals with user input for SQL, HTML, or shell commands. Use parameterized queries, DOMPurify, or `child_process.execFile()` respectively.
|
|
198
202
|
|
|
199
203
|
## See Also
|
|
200
|
-
|
|
204
|
+
parallel-sessions.md · vendored only for some archetypes, so possibly absent in this repo: frontend.md [nextjs-saas, nextjs-minimal] · backend.md [nextjs-saas, express-service, docker-service] · backend-data.md [nextjs-saas]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* agent-usage-census.mjs — CLI shell over scripts/lib/agent-usage-census.mjs (#1617).
|
|
4
|
+
*
|
|
5
|
+
* Reads Claude Code subagent transcripts (read-only) and reports per agent type:
|
|
6
|
+
* dispatches, observed models, turns and output per run, cache rebuilds after
|
|
7
|
+
* idle gaps, and the median start context. Definitions: see the lib header.
|
|
8
|
+
*
|
|
9
|
+
* Usage: agent-usage-census.mjs [--days N] [--root DIR] [--json] [--top N]
|
|
10
|
+
* Exit: 0 measured · 1 bad argument · 2 root unreadable / measurement failed
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import os from 'node:os';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import fs from 'node:fs';
|
|
16
|
+
|
|
17
|
+
import { DEFAULT_DAYS, formatTable, runCensus } from './lib/agent-usage-census.mjs';
|
|
18
|
+
import { writeStdoutLineSync } from './lib/io.mjs';
|
|
19
|
+
import { isMainModule } from './lib/is-main-module.mjs';
|
|
20
|
+
|
|
21
|
+
const USAGE = 'Usage: agent-usage-census.mjs [--days N] [--root DIR] [--json] [--top N] [--help]';
|
|
22
|
+
|
|
23
|
+
export function parseArgs(argv) {
|
|
24
|
+
const out = { days: DEFAULT_DAYS, root: path.join(os.homedir(), '.claude', 'projects'), json: false, top: 25, help: false };
|
|
25
|
+
for (let i = 0; i < argv.length; i++) {
|
|
26
|
+
const a = argv[i];
|
|
27
|
+
if (a === '--json') out.json = true;
|
|
28
|
+
else if (a === '--help') out.help = true;
|
|
29
|
+
else if (a === '--days' || a === '--top') {
|
|
30
|
+
const v = Number(argv[++i]);
|
|
31
|
+
if (!Number.isFinite(v) || v <= 0) return { error: `${a} requires a positive number` };
|
|
32
|
+
out[a.slice(2)] = v;
|
|
33
|
+
} else if (a === '--root') {
|
|
34
|
+
const v = argv[++i];
|
|
35
|
+
if (!v) return { error: '--root requires a directory' };
|
|
36
|
+
out.root = path.resolve(v);
|
|
37
|
+
} else return { error: `Unknown argument: ${a}` };
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function main() {
|
|
43
|
+
const args = parseArgs(process.argv.slice(2));
|
|
44
|
+
if (args.error) {
|
|
45
|
+
console.error(`Error: ${args.error}`);
|
|
46
|
+
console.error(USAGE);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
if (args.help) {
|
|
50
|
+
console.log(USAGE);
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log('Per agent type over the subagent transcripts of the last N days (read-only):');
|
|
53
|
+
console.log(' dispatches, observed models (share of turns), turns/run and output tokens/run (median),');
|
|
54
|
+
console.log(' cache rebuilds after > 5 min gaps, median start context.');
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log(` --days N window in days (default ${DEFAULT_DAYS})`);
|
|
57
|
+
console.log(' --root D transcript root (default ~/.claude/projects)');
|
|
58
|
+
console.log(' --json machine-readable envelope on stdout');
|
|
59
|
+
console.log(' --top N rows in the table (default 25)');
|
|
60
|
+
console.log('');
|
|
61
|
+
console.log('Exit: 0 measured · 1 bad argument · 2 root unreadable / measurement failed');
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
if (!fs.existsSync(args.root)) {
|
|
65
|
+
console.error(`Error: transcript root does not exist: ${args.root}`);
|
|
66
|
+
process.exit(2);
|
|
67
|
+
}
|
|
68
|
+
let result;
|
|
69
|
+
try {
|
|
70
|
+
result = await runCensus({ root: args.root, days: args.days });
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error(`Error: census failed: ${err?.message ?? err}`);
|
|
73
|
+
process.exit(2);
|
|
74
|
+
}
|
|
75
|
+
writeStdoutLineSync(args.json ? JSON.stringify(result, null, 2) : formatTable(result, { top: args.top }));
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isMainModule(import.meta.url)) main();
|
|
@@ -73,12 +73,15 @@
|
|
|
73
73
|
* prune/rewrite, store lock not acquired). Unparseable store lines are
|
|
74
74
|
* NOT an error: they are kept verbatim, counted as `malformed` in the
|
|
75
75
|
* summary, and WARNed on stderr with their line numbers.
|
|
76
|
+
* 4 Refused: this host's learnings store role is invalid (owner.yaml
|
|
77
|
+
* `learnings` or SO_LEARNINGS_STORE_ROLE, #1516/#1686) — nothing written
|
|
76
78
|
*/
|
|
77
79
|
|
|
78
80
|
import { readFileSync, realpathSync } from 'node:fs';
|
|
79
81
|
import path from 'node:path';
|
|
80
82
|
import { validatePathInsideProject } from './lib/path-utils.mjs';
|
|
81
83
|
import { LearningsLockError, readLearnings, withLearningsLock } from './lib/learnings/io.mjs';
|
|
84
|
+
import { LearningsStoreRoleError } from './lib/learnings/store-role.mjs';
|
|
82
85
|
import { pruneLearnings } from './lib/learnings/expiry-sweep.mjs';
|
|
83
86
|
import {
|
|
84
87
|
CURRENT_SCHEMA_VERSION,
|
|
@@ -87,6 +90,8 @@ import {
|
|
|
87
90
|
} from './lib/learnings/schema.mjs';
|
|
88
91
|
import { parseSessionConfig, readConfigFile } from './lib/config.mjs';
|
|
89
92
|
import { isMainModule } from './lib/is-main-module.mjs';
|
|
93
|
+
import { resolveLedgerPath } from './lib/ledger-path.mjs';
|
|
94
|
+
import { resolveEventsLedgerRoot } from './lib/platform.mjs';
|
|
90
95
|
|
|
91
96
|
const DEFAULT_FILE = '.orchestrator/metrics/learnings.jsonl';
|
|
92
97
|
const ARCHIVE_BASENAME = 'learnings-archive.jsonl';
|
|
@@ -334,15 +339,22 @@ async function emitSessionWriteApplied({ repoRoot, filePath, payload }) {
|
|
|
334
339
|
// inside the repo but living outside it is refused, and a root spelled
|
|
335
340
|
// through a symlink (macOS /var → /private/var) still accepts the store
|
|
336
341
|
// inside it. Runs after the write, so the store exists and resolves.
|
|
342
|
+
//
|
|
343
|
+
// #1722: the default store of a linked worktree that gitignores it lives in
|
|
344
|
+
// the main checkout, so the ledger root (resolveEventsLedgerRoot) is accepted
|
|
345
|
+
// too; a store outside BOTH roots is still refused.
|
|
337
346
|
const file = canonicalPath(filePath);
|
|
338
|
-
const
|
|
339
|
-
|
|
347
|
+
const root = [repoRoot, resolveEventsLedgerRoot(repoRoot)].find(
|
|
348
|
+
(r) => validatePathInsideProject(file, r, { canonicalizeRoot: true }).ok,
|
|
349
|
+
);
|
|
350
|
+
if (root === undefined) {
|
|
340
351
|
process.stderr.write(
|
|
341
352
|
`apply-session-learnings: skipped ${SESSION_WRITE_EVENT} — ${filePath} lies outside ` +
|
|
342
353
|
`--repo-root ${repoRoot}\n`,
|
|
343
354
|
);
|
|
344
355
|
return;
|
|
345
356
|
}
|
|
357
|
+
const rel = path.relative(canonicalPath(root), file);
|
|
346
358
|
try {
|
|
347
359
|
const { emitEvent, sessionAttribution } = await import('./lib/events.mjs');
|
|
348
360
|
await emitEvent(
|
|
@@ -385,7 +397,9 @@ async function main(argv) {
|
|
|
385
397
|
}
|
|
386
398
|
|
|
387
399
|
const repoRoot = path.resolve(opts.repoRoot ?? process.cwd());
|
|
388
|
-
|
|
400
|
+
// #1722: only the DEFAULT store routes through the ledger resolver; an
|
|
401
|
+
// explicit --file stays exactly what the caller asked for.
|
|
402
|
+
const filePath = opts.file !== null ? path.resolve(repoRoot, opts.file) : resolveLedgerPath(DEFAULT_FILE, repoRoot);
|
|
389
403
|
const archivePath = path.join(path.dirname(filePath), ARCHIVE_BASENAME);
|
|
390
404
|
const decayRate = opts.decayRate ?? (await resolveDecayRate(repoRoot));
|
|
391
405
|
const now = new Date();
|
|
@@ -429,6 +443,10 @@ async function main(argv) {
|
|
|
429
443
|
// Joins the lock held below reentrantly; takes none on a dry run.
|
|
430
444
|
res = await pruneLearnings({ filePath, archivePath, entries: built.next, now, dryRun: !opts.apply });
|
|
431
445
|
} catch (err) {
|
|
446
|
+
if (err instanceof LearningsStoreRoleError) {
|
|
447
|
+
process.stderr.write(`apply-session-learnings: ${err.message}\n`);
|
|
448
|
+
return { code: 4 };
|
|
449
|
+
}
|
|
432
450
|
process.stderr.write(`apply-session-learnings: prune/rewrite failed: ${err.message}\n`);
|
|
433
451
|
return { code: 2 };
|
|
434
452
|
}
|
|
@@ -443,6 +461,10 @@ async function main(argv) {
|
|
|
443
461
|
process.stderr.write(`apply-session-learnings: ${err.message}\n`);
|
|
444
462
|
return 2;
|
|
445
463
|
}
|
|
464
|
+
if (err instanceof LearningsStoreRoleError) {
|
|
465
|
+
process.stderr.write(`apply-session-learnings: ${err.message}\n`);
|
|
466
|
+
return 4;
|
|
467
|
+
}
|
|
446
468
|
throw err;
|
|
447
469
|
}
|
|
448
470
|
if ('code' in outcome) return outcome.code;
|
|
@@ -466,14 +488,20 @@ async function main(argv) {
|
|
|
466
488
|
archived: res.archived,
|
|
467
489
|
kept: res.kept,
|
|
468
490
|
by_reason: byReason,
|
|
469
|
-
|
|
491
|
+
// On an inbox-role host (#1516) the live store is not rewritten: only
|
|
492
|
+
// records with new ids reach learnings-inbox.jsonl, so `kept` is no count
|
|
493
|
+
// of written records there (io.mjs prints the real numbers on stderr).
|
|
494
|
+
written: opts.apply && !res.skipped ? res.kept : 0,
|
|
495
|
+
...(res.skipped ? { skipped: res.skipped } : {}),
|
|
470
496
|
};
|
|
471
497
|
|
|
472
498
|
// The event's presence is documented as proof the write ran
|
|
473
499
|
// (docs/events-schema.md). pruneLearnings() returns early WITHOUT writing
|
|
474
500
|
// exactly when the store and the next generation are both empty — the only
|
|
475
501
|
// path that reports `scanned: 0` — so no store + empty input emits nothing.
|
|
476
|
-
|
|
502
|
+
// No event on an inbox-role host (#1516): the store write it attests to did
|
|
503
|
+
// not happen there.
|
|
504
|
+
if (opts.apply && res.scanned > 0 && !res.skipped) {
|
|
477
505
|
await emitSessionWriteApplied({
|
|
478
506
|
repoRoot,
|
|
479
507
|
filePath,
|
|
@@ -494,7 +522,7 @@ async function main(argv) {
|
|
|
494
522
|
`${summary.dry_run ? '[dry-run] ' : ''}learnings: read ${summary.read}, confirmed ${summary.confirmed}, ` +
|
|
495
523
|
`contradicted ${summary.contradicted}, appended ${summary.appended}, decayed ${summary.decayed} ` +
|
|
496
524
|
`(rate ${decayRate}), pruned ${pruned}, consolidated ${summary.consolidated}, kept ${summary.kept}` +
|
|
497
|
-
`${summary.dry_run ? ' — nothing written' : ` — wrote ${summary.written}`}\n`,
|
|
525
|
+
`${summary.dry_run ? ' — nothing written' : summary.skipped ? ` — ${summary.skipped}: live store not rewritten` : ` — wrote ${summary.written}`}\n`,
|
|
498
526
|
);
|
|
499
527
|
}
|
|
500
528
|
return 0;
|
|
@@ -50,7 +50,7 @@ import { glabRun as defaultGlabRun } from './lib/vault-backfill/glab.mjs';
|
|
|
50
50
|
import { archiveFileToVault, titleFromMarkdown } from './lib/vault-archive.mjs';
|
|
51
51
|
import { defaultGlabRepo } from './lib/vcs-repo-spec.mjs';
|
|
52
52
|
import { readLock } from './lib/session-lock.mjs';
|
|
53
|
-
import {
|
|
53
|
+
import { resolveStateMdWriteTarget, warnForeignStateMd } from './lib/state-md/frontmatter-mutators.mjs';
|
|
54
54
|
import { parseStateMd } from './lib/state-md/yaml-parser.mjs';
|
|
55
55
|
import { isMainModule } from './lib/is-main-module.mjs';
|
|
56
56
|
|
|
@@ -224,6 +224,24 @@ export function classifyOwnership({ repoRoot, rel, sessionStartedAt, gitRunFn })
|
|
|
224
224
|
return committedMs >= startedMs ? 'foreign' : 'mine';
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Read THIS session's STATE.md frontmatter, or null. #1636: the write side's
|
|
229
|
+
* ownership rule — another platform's STATE.md not proven to be this process's
|
|
230
|
+
* (#1618) counts as absent, so it never lends its `started_at` / `issues:` to
|
|
231
|
+
* this run's `--apply` (both callers fail closed on null).
|
|
232
|
+
*
|
|
233
|
+
* @param {string} repoRoot
|
|
234
|
+
* @returns {Record<string, unknown>|null}
|
|
235
|
+
*/
|
|
236
|
+
function readOwnStateFrontmatter(repoRoot) {
|
|
237
|
+
const { path: stateMdPath, rejected } = resolveStateMdWriteTarget(repoRoot);
|
|
238
|
+
if (rejected) {
|
|
239
|
+
warnForeignStateMd('archive-closed-prds', rejected, stateMdPath);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return parseStateMd(readFileSync(stateMdPath, 'utf8'))?.frontmatter ?? null;
|
|
243
|
+
}
|
|
244
|
+
|
|
227
245
|
/**
|
|
228
246
|
* Resolve THIS session's `started_at` (ISO-8601): the session lock first, the
|
|
229
247
|
* STATE.md frontmatter as fallback.
|
|
@@ -239,8 +257,7 @@ export function readSessionStartedAt(repoRoot) {
|
|
|
239
257
|
// fall through to STATE.md
|
|
240
258
|
}
|
|
241
259
|
try {
|
|
242
|
-
const
|
|
243
|
-
const startedAt = parsed?.frontmatter?.started_at;
|
|
260
|
+
const startedAt = readOwnStateFrontmatter(repoRoot)?.started_at;
|
|
244
261
|
if (typeof startedAt === 'string' && !Number.isNaN(Date.parse(startedAt))) return startedAt;
|
|
245
262
|
} catch {
|
|
246
263
|
// no STATE.md, or unreadable → null (fail-closed at the call site)
|
|
@@ -255,8 +272,7 @@ export function readSessionStartedAt(repoRoot) {
|
|
|
255
272
|
*/
|
|
256
273
|
function readSessionIssues(repoRoot) {
|
|
257
274
|
try {
|
|
258
|
-
const
|
|
259
|
-
const issues = parsed?.frontmatter?.issues;
|
|
275
|
+
const issues = readOwnStateFrontmatter(repoRoot)?.issues;
|
|
260
276
|
if (Array.isArray(issues)) return new Set(issues.map((n) => String(n)));
|
|
261
277
|
} catch {
|
|
262
278
|
// absent/unreadable → empty set
|