@opengsd/gsd-core 1.11.0 → 1.12.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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -9
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +15 -55
- package/agents/gsd-planner.md +6 -4
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +609 -134
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/quick.md +8 -4
- package/gsd-core/bin/gsd-tools.cjs +567 -51
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +336 -95
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-validator.cjs +205 -18
- package/gsd-core/bin/lib/check-command-router.cjs +145 -5
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +543 -44
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +118 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +84 -7
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/frontmatter.cjs +840 -305
- package/gsd-core/bin/lib/gap-checker.cjs +27 -3
- package/gsd-core/bin/lib/git-base-branch.cjs +174 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +6 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +120 -41
- package/gsd-core/bin/lib/install-engine.cjs +68 -3
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -1
- package/gsd-core/bin/lib/install-profiles.cjs +78 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +160 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-table.cjs +52 -4
- package/gsd-core/bin/lib/milestone.cjs +90 -5
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +70 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +405 -84
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -14
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -0
- package/gsd-core/bin/lib/probe-core.cjs +4 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +9 -9
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +79 -16
- package/gsd-core/bin/lib/roadmap.cjs +74 -19
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +96 -8
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +287 -55
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +71 -8
- package/gsd-core/bin/lib/smart-entry.cjs +12 -22
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +186 -0
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +517 -101
- package/gsd-core/bin/lib/state.cjs +946 -163
- package/gsd-core/bin/lib/surface.cjs +10 -2
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +1376 -125
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification.cjs +14 -1
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +95 -40
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +177 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +3 -2
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +1 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +37 -8
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +2 -2
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/phase-prompt.md +3 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +4 -9
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +10 -26
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +121 -40
- package/gsd-core/workflows/complete-milestone.md +15 -10
- package/gsd-core/workflows/debug.md +5 -3
- package/gsd-core/workflows/diagnose-issues.md +12 -6
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +3 -7
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +2 -2
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +4 -9
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +113 -11
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +22 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +38 -54
- package/gsd-core/workflows/execute-plan.md +17 -12
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +2 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +3 -6
- package/gsd-core/workflows/import.md +14 -11
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +44 -11
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +2 -2
- package/gsd-core/workflows/new-milestone.md +9 -21
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +12 -26
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +121 -42
- package/gsd-core/workflows/plan-review-convergence.md +46 -9
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +27 -12
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -3
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +20 -29
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +193 -15
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +2 -2
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +3 -5
- package/gsd-core/workflows/ship.md +12 -6
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +23 -1
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +5 -5
- package/gsd-core/workflows/ui-phase.md +10 -16
- package/gsd-core/workflows/ui-review.md +6 -10
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +6 -10
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +57 -18
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +16 -7
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +17 -8
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +215 -26
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +34 -16
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +16 -7
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +17 -8
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +215 -26
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +34 -16
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +12 -7
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +5 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +45 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +134 -1
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +21 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +122 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/prompt-injection-scan.sh +75 -14
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -10,7 +10,7 @@ const capabilities = {
|
|
|
10
10
|
"ai-integration": {
|
|
11
11
|
"id": "ai-integration",
|
|
12
12
|
"role": "feature",
|
|
13
|
-
"version": "1.
|
|
13
|
+
"version": "1.12.0",
|
|
14
14
|
"title": "AI design contract",
|
|
15
15
|
"description": "AI-SPEC design contract workflow for phases that build AI systems; owns the AI integration command, agents, and workflow.ai_integration_phase activation key.",
|
|
16
16
|
"tier": "full",
|
|
@@ -68,7 +68,7 @@ const capabilities = {
|
|
|
68
68
|
"into": "planner",
|
|
69
69
|
"fragment": {
|
|
70
70
|
"path": "fragments/api-coverage-plan-pre.md",
|
|
71
|
-
"inline": "# API Coverage Decision Checkpoint\n\n> Full API Coverage by Default — Opt Out, Never Opt In. Fires when a phase\n> integrates an external API / SDK / service. Most non-API phases will not fire\n> it — that is the point.\n\n## Why this exists\n\n\"We integrated the API\" too often silently means \"we integrated whatever the\nfirst use case exercised.\" Every un-built capability is then an invisible hole,\ndiscovered later by a user who reasonably expected it to work. The phase sealed\ngreen because its tasks completed; nobody decided the gaps were acceptable,\nbecause nobody enumerated them. This checkpoint makes the surface **visible and\ndecided** before the phase can seal.\n\n## Detect whether this phase integrates an external API\n\nThe detector is a deterministic scan over the phase scope. It strips fenced\ncode blocks first, so a trigger term inside a code snippet does not fire. It\nreturns a typed result: `{ detected, signals[], terms }`. Run it on the phase\nscope (the concatenation of this phase's ROADMAP section + the PLAN body):\n\n```bash\nSCOPE=\"$(cat \"${PHASE_DIR}\"/*-PLAN.md 2>/dev/null) $(gsd_run query roadmap.get-phase \"${PHASE}\" 2>/dev/null || true)\"\nAPI_COVERAGE_JSON=$(printf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json 2>/dev/null ||
|
|
71
|
+
"inline": "# API Coverage Decision Checkpoint\n\n> Full API Coverage by Default — Opt Out, Never Opt In. Fires when a phase\n> integrates an external API / SDK / service. Most non-API phases will not fire\n> it — that is the point.\n\n## Why this exists\n\n\"We integrated the API\" too often silently means \"we integrated whatever the\nfirst use case exercised.\" Every un-built capability is then an invisible hole,\ndiscovered later by a user who reasonably expected it to work. The phase sealed\ngreen because its tasks completed; nobody decided the gaps were acceptable,\nbecause nobody enumerated them. This checkpoint makes the surface **visible and\ndecided** before the phase can seal.\n\n## Detect whether this phase integrates an external API\n\nThe detector is a deterministic scan over the phase scope. It strips fenced\ncode blocks first, so a trigger term inside a code snippet does not fire. It\nreturns a typed result: `{ detected, signals[], terms }`. Run it on the phase\nscope (the concatenation of this phase's ROADMAP section + the PLAN body):\n\n```bash\nSCOPE=\"$(cat \"${PHASE_DIR}\"/*-PLAN.md 2>/dev/null) $(gsd_run query roadmap.get-phase \"${PHASE}\" 2>/dev/null || true)\"\nAPI_COVERAGE_JSON=$(printf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json 2>/dev/null) || true\n[ -n \"$API_COVERAGE_JSON\" ] || API_COVERAGE_JSON='{\"skipped\":true,\"reason\":\"probe_unavailable\"}'\n```\n\nThe `|| true` neutralizes the assignment's status without discarding the\ndetector's own payload: the detector exits **1** for a real \"no integration\"\nverdict, so treating any non-zero exit as failure would throw away a correct\nanswer. Emptiness — not exit status — is what proves the probe never ran, and\nthe second line is the only place the fragment manufactures a payload of its\nown — one that records the *absence* of a verdict rather than asserting one.\n\nThe detector's exit code and `--json` payload now distinguish a real negative\nfrom an unexamined input (ADR-3889 Phase 3, #3907): empty/whitespace-only\n`$SCOPE` or a stdin read failure emit `{\"skipped\":true,\"reason\":\"no_input\"|\n\"stdin_error\"}` — no `detected` key at all. **Check for `skipped` before\nreading `detected`**: a `skipped` payload is not a confirmed \"no API\nintegration\" verdict, it means the detector never examined real input. Do not\ntreat it as `detected:false`. Read `API_COVERAGE_JSON.detected` only when\n`skipped` is absent — act on it only, do **not** pattern-match the prose\nyourself.\n\n**If `skipped` is `true`:** the detector could not establish a scope (empty\n`$SCOPE`) or failed to run (stdin read error). Skip the checkpoint for this\nrun rather than asserting a verdict about input that was never examined; do\nnot raise it with the user.\n\n**If `detected` is `false`:** this phase does not integrate an external API. Skip\nthe checkpoint entirely and continue planning. Do not raise it with the user.\n\n**If `detected` is `true`:** an external-API integration is in scope. You MUST\nproduce a **coverage matrix** before the plan is finalized.\n\n**If `detected` is `true` but the phase genuinely integrates no external API**\n(the detector is deterministic, not infallible — confirm by re-reading the phase\nscope, not by preference): do NOT fabricate a matrix row for a capability that\ndoes not exist. Write a reasoned declaration to `${PHASE_DIR}/COVERAGE.md`\ninstead:\n\n```markdown\nNo external API integration: <one-line reason — what the phase touches instead>.\n```\n\nThe reason is required, exactly like an `OPT-OUT` reason. The seal-time gate\naccepts this declaration in place of a matrix.\n\n## Produce the coverage matrix\n\nEnumerate the external API's full **capability surface** — the verb/endpoint/method\nlist (e.g. for a music service: `search`, `play`, `pause`, `skip`, `set_volume`,\n`get_playlist`, `create_playlist`, `add_to_playlist`, …). For each capability\nrecord a decision, starting from **full coverage** as the default:\n\n| capability | decision | reason |\n|---|---|---|\n| `<capability-id>` | `INTEGRATE` \\| `OPT-OUT` | `<one-line reason if OPT-OUT>` |\n\nRules:\n\n- **`INTEGRATE` is the default.** Every capability starts as INTEGRATE; the\n matrix is the *subtraction record*.\n- **Every `OPT-OUT` MUST carry a one-line reason** (`not needed`, `not needed\n yet`, `explicitly out of scope`, …). An opt-out without a reason is an\n un-decided hole — the exact failure mode this gate exists to close.\n- **A second integration against the same need** (e.g. a second platform for the\n same capability) starts from the **same full-coverage baseline** as the first.\n Do not carry over the first integration's opt-outs silently — re-decide each\n capability for the new surface, so a first-class/fallback asymmetry cannot\n accumulate.\n\nWrite the matrix to `${PHASE_DIR}/COVERAGE.md` (canonical markdown-table form):\n\n```markdown\n# API Coverage — <service>\n\n> Full coverage by default. Opt-outs are explicit, reasoned decisions.\n\n| capability | decision | reason |\n|---|---|---|\n| search | INTEGRATE | |\n| playlists | INTEGRATE | |\n| skip | OPT-OUT | not needed yet — tracked for follow-up phase |\n```\n\nA fenced ` ```coverage ` JSON block is also accepted for machine-generated\nmatrices; the markdown table is preferred (human-editable, diff-friendly).\n\n## The seal-time gate\n\nThis checkpoint is enforced. At `verify:pre` the `api-coverage.verify-pre` gate\nruns `check api-coverage.verify-pre <phase-dir>`:\n\n- If `COVERAGE.md` exists, it is validated — every row needs a valid decision and\n every `OPT-OUT` a reason. A malformed/partial matrix **blocks the seal**. A\n reasoned `No external API integration: …` declaration (and no rows) passes.\n- If `COVERAGE.md` is absent, the detector runs again over the phase scope. If a\n strong external-API-integration signal is found, the seal is **blocked** until a\n matrix is produced. If no signal is found, the phase is treated as a non-API\n phase and the seal proceeds.\n\nSo: an API-integrating phase cannot seal without a decided matrix. Produce it at\nplan time; do not leave it for seal time.\n\n## Tuning the vocabulary (optional)\n\nThe trigger vocabulary is a curated, additive-only set in\n`gsd-core/bin/lib/api-coverage.cjs` (`DEFAULT_API_COVERAGE_TERMS`). To widen it\nfor a project, override at the call site:\n\n```bash\nprintf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json \\\n --verbs integrate,wrap,connect,embed --nouns api,sdk,rest,grpc,webhook,plugin\n```\n\nThe whole checkpoint is toggleable via `workflow.api_coverage_gate` in\n`.planning/config.json`.\n"
|
|
72
72
|
},
|
|
73
73
|
"produces": [
|
|
74
74
|
"COVERAGE.md"
|
|
@@ -95,9 +95,9 @@ const capabilities = {
|
|
|
95
95
|
"antigravity": {
|
|
96
96
|
"id": "antigravity",
|
|
97
97
|
"role": "runtime",
|
|
98
|
-
"version": "1.
|
|
98
|
+
"version": "1.12.0",
|
|
99
99
|
"title": "Antigravity",
|
|
100
|
-
"description": "Google Antigravity IDE — nested under ~/.gemini/antigravity
|
|
100
|
+
"description": "Google Antigravity IDE — config/settings home nested under ~/.gemini/antigravity (probed across 1.x and 2.x layouts); global skills/agents install under ~/.gemini/config, the dir AGY scans for global discovery (#3738); Gemini hook event dialect; flat skill layout; tier-1 support.",
|
|
101
101
|
"tier": "core",
|
|
102
102
|
"requires": [],
|
|
103
103
|
"engines": {
|
|
@@ -128,7 +128,8 @@ const capabilities = {
|
|
|
128
128
|
"prefix": "gsd-",
|
|
129
129
|
"nesting": "flat",
|
|
130
130
|
"recursive": false,
|
|
131
|
-
"converter": "convertClaudeCommandToAntigravitySkill"
|
|
131
|
+
"converter": "convertClaudeCommandToAntigravitySkill",
|
|
132
|
+
"home": ".gemini/config"
|
|
132
133
|
},
|
|
133
134
|
{
|
|
134
135
|
"kind": "agents",
|
|
@@ -136,7 +137,8 @@ const capabilities = {
|
|
|
136
137
|
"prefix": "gsd-",
|
|
137
138
|
"nesting": "flat",
|
|
138
139
|
"recursive": false,
|
|
139
|
-
"converter": "convertClaudeAgentToAntigravityAgent"
|
|
140
|
+
"converter": "convertClaudeAgentToAntigravityAgent",
|
|
141
|
+
"home": ".gemini/config"
|
|
140
142
|
}
|
|
141
143
|
],
|
|
142
144
|
"local": [
|
|
@@ -227,7 +229,7 @@ const capabilities = {
|
|
|
227
229
|
"reviewsSection": "Antigravity",
|
|
228
230
|
"evidenceClass": "source-grounded",
|
|
229
231
|
"requiresBinaries": [],
|
|
230
|
-
"promptBudgetKey":
|
|
232
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.antigravity",
|
|
231
233
|
"modelConfigKey": "review.models.agy",
|
|
232
234
|
"handler": "antigravity"
|
|
233
235
|
},
|
|
@@ -236,13 +238,18 @@ const capabilities = {
|
|
|
236
238
|
"type": "string",
|
|
237
239
|
"default": "",
|
|
238
240
|
"description": "Model passed to the Antigravity reviewer lane. The key suffix is the lane binary/flag alias `agy`, not the slug `antigravity` — preserved verbatim so existing .planning/config.json files keep working."
|
|
241
|
+
},
|
|
242
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
243
|
+
"type": "number",
|
|
244
|
+
"default": -1,
|
|
245
|
+
"description": "Prompt-token budget for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\". Keyed on the reviewer slug `antigravity`, not the `agy` binary alias used by review.models.agy."
|
|
239
246
|
}
|
|
240
247
|
}
|
|
241
248
|
},
|
|
242
249
|
"assumption-delta": {
|
|
243
250
|
"id": "assumption-delta",
|
|
244
251
|
"role": "feature",
|
|
245
|
-
"version": "1.
|
|
252
|
+
"version": "1.12.0",
|
|
246
253
|
"title": "Assumption-delta architecture checkpoint",
|
|
247
254
|
"description": "Rarely-firing advisory checkpoint that triggers when a phase makes something plural, optional, or chosen that used to be singular, required, or derived. Surfaces one identity-model question (promote the new general representation to primary, or add it alongside?) so a silent primary-key drift does not accumulate into a later user-facing bug. Non-blocking; fires only on a detected signal.",
|
|
248
255
|
"tier": "full",
|
|
@@ -273,7 +280,7 @@ const capabilities = {
|
|
|
273
280
|
"into": "planner",
|
|
274
281
|
"fragment": {
|
|
275
282
|
"path": "fragments/plan-pre.md",
|
|
276
|
-
"inline": "# Assumption-Delta Architecture Checkpoint\n\n> Advisory, non-blocking. Fires **only** when the phase scope shows a singular→plural / required→optional / derived→chosen transition. When it fires, it surfaces ONE identity-model question before the plan is finalized. Most phases will not fire it — that is the point.\n\n## Why this exists\n\nMost quietly-imported architectural debt does not come from a missing upfront design phase. It comes at the *seam*: a later phase introduces a second case (a second platform, auth method, tenant, region, source of truth) and nobody re-asks whether the original abstraction still names the right thing. The phase that adds the second case is exactly the 20-minute conversation that prevents an afternoon of later cleanup.\n\n## Run the detector\n\nThe detector is a deterministic scan over the phase scope text. It strips fenced code blocks first, so a trigger word that appears only inside a code snippet does not fire. It returns a typed result: `{ detected, signals[], terms }`. Resolve it through the `assumption-delta scan` query (same phase-section resolver as `roadmap.get-phase`):\n\n```bash\nASSUMPTION_DELTA_JSON=$(gsd_run query assumption-delta scan \"${PHASE}\" --json 2>/dev/null ||
|
|
283
|
+
"inline": "# Assumption-Delta Architecture Checkpoint\n\n> Advisory, non-blocking. Fires **only** when the phase scope shows a singular→plural / required→optional / derived→chosen transition. When it fires, it surfaces ONE identity-model question before the plan is finalized. Most phases will not fire it — that is the point.\n\n## Why this exists\n\nMost quietly-imported architectural debt does not come from a missing upfront design phase. It comes at the *seam*: a later phase introduces a second case (a second platform, auth method, tenant, region, source of truth) and nobody re-asks whether the original abstraction still names the right thing. The phase that adds the second case is exactly the 20-minute conversation that prevents an afternoon of later cleanup.\n\n## Run the detector\n\nThe detector is a deterministic scan over the phase scope text. It strips fenced code blocks first, so a trigger word that appears only inside a code snippet does not fire. It returns a typed result: `{ detected, signals[], terms }`. Resolve it through the `assumption-delta scan` query (same phase-section resolver as `roadmap.get-phase`):\n\n```bash\nASSUMPTION_DELTA_JSON=$(gsd_run query assumption-delta scan \"${PHASE}\" --json 2>/dev/null) || true\n[ -n \"$ASSUMPTION_DELTA_JSON\" ] || ASSUMPTION_DELTA_JSON='{\"skipped\":true,\"reason\":\"probe_unavailable\"}'\n```\n\n> If the phase section cannot be resolved (no `ROADMAP.md` / unknown phase, or a section with no body), the query emits `{ \"skipped\": true, \"reason\": \"phase_unresolved\" }` — **not** `detected:false`. A probe that never had input does not get to assert that this phase changes no core assumption. The checkpoint does not fire either way; the difference is that a skip is now distinguishable from a real negative. Do not block on it.\n>\n> Optional tuning — pass `--terms <comma-list>` to replace the curated pluralization cues for this project (the `optional`/`chosen` cues keep their defaults): `gsd_run query assumption-delta scan \"${PHASE}\" --json --terms second,alternative,fallback`.\n\n## Decision branch\n\nRead `ASSUMPTION_DELTA_JSON`. Act on `detected` only — do **not** pattern-match the human prose.\n\n**If `skipped` is `true`:** the detector never examined a phase section — it could not resolve one (`phase_unresolved`) or could not run at all (`probe_unavailable`). Skip the checkpoint for this run rather than asserting a verdict about input that was never examined; do not raise it with the user. **Check for `skipped` before reading `detected`** — a skipped payload carries no `detected` key, and treating its absence as `false` re-creates the fabrication this branch exists to prevent.\n\n**If `detected` is `false`:** this phase does not change a core assumption. Skip the checkpoint entirely and continue planning. Do not raise it with the user.\n\n**If `detected` is `true`:** a core assumption may have lost its monopoly. The `signals[]` array tells you which family fired:\n\n| `kind` | What changed | The question to answer |\n|---|---|---|\n| `pluralization` | A second X was introduced where there was one (second platform / auth method / tenant / region / source of truth) | Does the current primary key / identity model still name the right noun? |\n| `optional` | A required / `only` field became optional | Is the field still the right anchor, or has the anchor moved? |\n| `chosen` | A derived value became chosen, or a constant became a parameter | Has a configuration decision become a modeling decision? |\n\nBefore finalizing the plan, answer this for the user and record the decision explicitly:\n\n> **Promote vs. add-alongside.** The usual correct move when a generalization occurs is to **promote** the new general representation to the primary and **demote** the old specific one to a detail of one variant — *not* to add the new one alongside the still-required old one. Adding alongside silently contradicts the generalized intent (a later variant that does not fit the old primary can be stored but never confirmed as a default).\n\nRecord the outcome in the PLAN.md front matter / a `<assumption_delta_decision>` block:\n\n- The **noun** that is now primary (the generalized identity).\n- The **decision**: `promote` | `add-alongside` | `no-change`, with a one-line rationale.\n- If `add-alongside`: call it out as accepted debt and note what would force a later promote.\n\n## Optional companion: an invariant test\n\nWhen `detected` is `true`, suggest (do not require) a contract/invariant test that encodes the now-generalized intent — e.g. *\"every confirmed default round-trips through the primary use-path, for every supported variant.\"* That test goes red the instant a future phase reintroduces the singular assumption, so the regression cannot land silently. If the user accepts, add the test as a task in the plan.\n\n## Tuning the vocabulary (optional)\n\nThe trigger vocabulary is a curated, additive-only set in `gsd-core/bin/lib/assumption-delta.cjs` (`DEFAULT_ASSUMPTION_DELTA_TERMS`). Bare \"or\" is intentionally excluded — it is too common in prose and would make the gate fire constantly. To widen or narrow the cues for a project, override at the call site with `--terms <comma-list>` (replaces the pluralization cues; `optional`/`chosen` keep defaults). The whole checkpoint is toggleable via `workflow.assumption_delta` in `.planning/config.json`.\n\nThis checkpoint is advisory: it informs and records; it never blocks the phase.\n"
|
|
277
284
|
},
|
|
278
285
|
"produces": [],
|
|
279
286
|
"consumes": [
|
|
@@ -288,7 +295,7 @@ const capabilities = {
|
|
|
288
295
|
"audit": {
|
|
289
296
|
"id": "audit",
|
|
290
297
|
"role": "feature",
|
|
291
|
-
"version": "1.
|
|
298
|
+
"version": "1.12.0",
|
|
292
299
|
"title": "Audit",
|
|
293
300
|
"description": "Open-artifact audit and UAT-gap audit for milestone close gates; exposes `gsd-tools audit-uat` (cross-phase UAT outstanding items) and `gsd-tools audit-open` (structured open-artifact scan across debug, tasks, threads, todos, seeds, UAT, verification, context-questions).",
|
|
294
301
|
"tier": "full",
|
|
@@ -325,7 +332,7 @@ const capabilities = {
|
|
|
325
332
|
"augment": {
|
|
326
333
|
"id": "augment",
|
|
327
334
|
"role": "runtime",
|
|
328
|
-
"version": "1.
|
|
335
|
+
"version": "1.12.0",
|
|
329
336
|
"title": "Augment Code",
|
|
330
337
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
331
338
|
"tier": "core",
|
|
@@ -438,7 +445,7 @@ const capabilities = {
|
|
|
438
445
|
"broken-windows": {
|
|
439
446
|
"id": "broken-windows",
|
|
440
447
|
"role": "feature",
|
|
441
|
-
"version": "1.
|
|
448
|
+
"version": "1.12.0",
|
|
442
449
|
"title": "Broken-windows ledger",
|
|
443
450
|
"description": "Cross-phase defect register accumulating stubs, TODOs, skipped tests, unrun verifies, and unmet truths into .planning/WINDOWS.md. When enforcement is enabled, it blocks /gsd-ship while any window is open unless explicitly waived with a recorded reason. Operationalizes GSD's no-defer discipline as a tracked artifact (issue #1950).",
|
|
444
451
|
"tier": "full",
|
|
@@ -484,7 +491,7 @@ const capabilities = {
|
|
|
484
491
|
"claude": {
|
|
485
492
|
"id": "claude",
|
|
486
493
|
"role": "runtime",
|
|
487
|
-
"version": "1.
|
|
494
|
+
"version": "1.12.0",
|
|
488
495
|
"title": "Claude Code",
|
|
489
496
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
490
497
|
"tier": "core",
|
|
@@ -631,7 +638,7 @@ const capabilities = {
|
|
|
631
638
|
"reviewsSection": "Claude",
|
|
632
639
|
"evidenceClass": "source-grounded",
|
|
633
640
|
"requiresBinaries": [],
|
|
634
|
-
"promptBudgetKey":
|
|
641
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.claude",
|
|
635
642
|
"modelConfigKey": "review.models.claude",
|
|
636
643
|
"handler": null
|
|
637
644
|
},
|
|
@@ -640,13 +647,18 @@ const capabilities = {
|
|
|
640
647
|
"type": "string",
|
|
641
648
|
"default": "",
|
|
642
649
|
"description": "Model passed to the Claude reviewer lane."
|
|
650
|
+
},
|
|
651
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
652
|
+
"type": "number",
|
|
653
|
+
"default": -1,
|
|
654
|
+
"description": "Prompt-token budget for the Claude reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
643
655
|
}
|
|
644
656
|
}
|
|
645
657
|
},
|
|
646
658
|
"claude-orchestration": {
|
|
647
659
|
"id": "claude-orchestration",
|
|
648
660
|
"role": "feature",
|
|
649
|
-
"version": "1.
|
|
661
|
+
"version": "1.12.0",
|
|
650
662
|
"title": "Claude orchestration (Workflow backend)",
|
|
651
663
|
"description": "Default-off, BETA, claude-only capability that adopts Claude Code's Workflow tool (the engine behind /effort ultracode) as an optional parallel-execution backend for the GSD loop. When the runtime exposes the Workflow tool and claude_orchestration.execution_backend resolves to 'workflow', execute-phase emits a generated Workflow script (waves -> parallel() barriers, plans -> agent({ agentType: 'gsd-executor', isolation: 'worktree' }), files_modified overlap -> separate sequential stages, resumeFromRunId wired to the phase run id, shared token budget) that composes the SAME gsd-executor agent and worktree isolation the inline path uses, restoring the wave parallelism the #853 backgrounded-agent nesting limitation forces inline on Claude Code. (The plan-checker and verifier remain inline until separately wired — this capability delivers the parallel-execution backend, not those gates.) Also folds the ultraplan plan-offload under one runtime gate (plan:* surface). On any runtime lacking the Workflow tool, or when the capability is disabled, behaviour is byte-identical to today (inline/manual dispatch). Detection + emission live in gsd-core/bin/lib/claude-orchestration.cjs (pure, fail-closed). Mirrors the existing gsd-ultraplan-phase BETA-isolation posture.",
|
|
652
664
|
"tier": "full",
|
|
@@ -705,7 +717,7 @@ const capabilities = {
|
|
|
705
717
|
"into": "executor",
|
|
706
718
|
"fragment": {
|
|
707
719
|
"path": "fragments/execute-wave-pre.md",
|
|
708
|
-
"inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version <ver>` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME <objective>...<success_criteria> prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the `<objective>`/`<execution_context>`/`<required_reading>`/\n `<success_criteria>` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version <ver>` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `<worktree_metadata>` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"<metadata.agent_id>\" --path \"<metadata.worktree_path>\" \\\n --branch \"<metadata.branch>\" --base \"<metadata.expected_base>\" \\\n --files \"<plan files_modified, space-separated>\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n"
|
|
720
|
+
"inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version <ver>` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME <objective>...<success_criteria> prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the `<objective>`/`<execution_context>`/`<required_reading>`/\n `<success_criteria>` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version <ver>` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `<worktree_metadata>` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"<metadata.agent_id>\" --path \"<metadata.worktree_path>\" \\\n --branch \"<metadata.branch>\" --base \"<metadata.expected_base>\" \\\n --files \"<plan files_modified, space-separated>\" \\\n --deletions \"<plan files_deleted, space-separated>\"\n ```\n\n `--deletions` (#3003) carries the plan's declared `files_deleted` so a plan that scoped a file\n removal merges through `cleanup-wave` instead of being blocked. Unlike `--files` it is not\n advisory: omitting it leaves the deletions guard blocking on any deletion at all, so this\n dispatch path must pass it or plans declaring a removal fail to merge here while succeeding on\n the inline path.\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n"
|
|
709
721
|
},
|
|
710
722
|
"produces": [],
|
|
711
723
|
"consumes": [
|
|
@@ -734,7 +746,7 @@ const capabilities = {
|
|
|
734
746
|
"cline": {
|
|
735
747
|
"id": "cline",
|
|
736
748
|
"role": "runtime",
|
|
737
|
-
"version": "1.
|
|
749
|
+
"version": "1.12.0",
|
|
738
750
|
"title": "Cline",
|
|
739
751
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
740
752
|
"tier": "core",
|
|
@@ -826,7 +838,7 @@ const capabilities = {
|
|
|
826
838
|
"code-review": {
|
|
827
839
|
"id": "code-review",
|
|
828
840
|
"role": "feature",
|
|
829
|
-
"version": "1.
|
|
841
|
+
"version": "1.12.0",
|
|
830
842
|
"title": "Code review",
|
|
831
843
|
"description": "Source-file code review and review-fix workflow support for completed execution work.",
|
|
832
844
|
"tier": "full",
|
|
@@ -887,7 +899,7 @@ const capabilities = {
|
|
|
887
899
|
"codebuddy": {
|
|
888
900
|
"id": "codebuddy",
|
|
889
901
|
"role": "runtime",
|
|
890
|
-
"version": "1.
|
|
902
|
+
"version": "1.12.0",
|
|
891
903
|
"title": "CodeBuddy",
|
|
892
904
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
893
905
|
"tier": "core",
|
|
@@ -1004,7 +1016,7 @@ const capabilities = {
|
|
|
1004
1016
|
"coderabbit": {
|
|
1005
1017
|
"id": "coderabbit",
|
|
1006
1018
|
"role": "reviewer",
|
|
1007
|
-
"version": "1.
|
|
1019
|
+
"version": "1.12.0",
|
|
1008
1020
|
"title": "CodeRabbit",
|
|
1009
1021
|
"description": "CodeRabbit CLI — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). Reviews the working-tree diff (`coderabbit review --prompt-only`), not the source tree, and accepts neither a prompt nor a model flag; findings are down-weighted in consensus (evidenceClass: diff-only).",
|
|
1010
1022
|
"tier": "full",
|
|
@@ -1038,15 +1050,22 @@ const capabilities = {
|
|
|
1038
1050
|
"reviewsSection": "CodeRabbit",
|
|
1039
1051
|
"evidenceClass": "diff-only",
|
|
1040
1052
|
"requiresBinaries": [],
|
|
1041
|
-
"promptBudgetKey":
|
|
1053
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.coderabbit",
|
|
1042
1054
|
"modelConfigKey": null,
|
|
1043
1055
|
"handler": null
|
|
1056
|
+
},
|
|
1057
|
+
"config": {
|
|
1058
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": {
|
|
1059
|
+
"type": "number",
|
|
1060
|
+
"default": -1,
|
|
1061
|
+
"description": "Prompt-token budget for the CodeRabbit reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
1062
|
+
}
|
|
1044
1063
|
}
|
|
1045
1064
|
},
|
|
1046
1065
|
"codex": {
|
|
1047
1066
|
"id": "codex",
|
|
1048
1067
|
"role": "runtime",
|
|
1049
|
-
"version": "1.
|
|
1068
|
+
"version": "1.12.0",
|
|
1050
1069
|
"title": "OpenAI Codex CLI",
|
|
1051
1070
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
1052
1071
|
"tier": "core",
|
|
@@ -1145,7 +1164,8 @@ const capabilities = {
|
|
|
1145
1164
|
"exec"
|
|
1146
1165
|
],
|
|
1147
1166
|
"cwdFlag": "--cd",
|
|
1148
|
-
"promptFlag": null
|
|
1167
|
+
"promptFlag": null,
|
|
1168
|
+
"modelFlag": "--model"
|
|
1149
1169
|
},
|
|
1150
1170
|
"hostBehaviors": {
|
|
1151
1171
|
"reapplyCommand": "$gsd-update --reapply",
|
|
@@ -1187,7 +1207,7 @@ const capabilities = {
|
|
|
1187
1207
|
"reviewsSection": "Codex",
|
|
1188
1208
|
"evidenceClass": "source-grounded",
|
|
1189
1209
|
"requiresBinaries": [],
|
|
1190
|
-
"promptBudgetKey":
|
|
1210
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.codex",
|
|
1191
1211
|
"modelConfigKey": "review.models.codex",
|
|
1192
1212
|
"handler": null
|
|
1193
1213
|
},
|
|
@@ -1196,13 +1216,18 @@ const capabilities = {
|
|
|
1196
1216
|
"type": "string",
|
|
1197
1217
|
"default": "",
|
|
1198
1218
|
"description": "Model passed to the Codex reviewer lane."
|
|
1219
|
+
},
|
|
1220
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
1221
|
+
"type": "number",
|
|
1222
|
+
"default": -1,
|
|
1223
|
+
"description": "Prompt-token budget for the Codex reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
1199
1224
|
}
|
|
1200
1225
|
}
|
|
1201
1226
|
},
|
|
1202
1227
|
"copilot": {
|
|
1203
1228
|
"id": "copilot",
|
|
1204
1229
|
"role": "runtime",
|
|
1205
|
-
"version": "1.
|
|
1230
|
+
"version": "1.12.0",
|
|
1206
1231
|
"title": "GitHub Copilot",
|
|
1207
1232
|
"description": "GitHub Copilot (VS Code) — markdown config format; copilot-inline hook surface; no hook events emitted; flat skill nesting (unconfirmed recursive loader); tier-2 support.",
|
|
1208
1233
|
"tier": "core",
|
|
@@ -1301,7 +1326,7 @@ const capabilities = {
|
|
|
1301
1326
|
"cursor": {
|
|
1302
1327
|
"id": "cursor",
|
|
1303
1328
|
"role": "runtime",
|
|
1304
|
-
"version": "1.
|
|
1329
|
+
"version": "1.12.0",
|
|
1305
1330
|
"title": "Cursor",
|
|
1306
1331
|
"description": "Cursor IDE — skills-only workflow surface; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
1307
1332
|
"tier": "core",
|
|
@@ -1445,15 +1470,22 @@ const capabilities = {
|
|
|
1445
1470
|
"reviewsSection": "Cursor",
|
|
1446
1471
|
"evidenceClass": "source-grounded",
|
|
1447
1472
|
"requiresBinaries": [],
|
|
1448
|
-
"promptBudgetKey":
|
|
1473
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
|
1449
1474
|
"modelConfigKey": null,
|
|
1450
1475
|
"handler": null
|
|
1476
|
+
},
|
|
1477
|
+
"config": {
|
|
1478
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
1479
|
+
"type": "number",
|
|
1480
|
+
"default": -1,
|
|
1481
|
+
"description": "Prompt-token budget for the Cursor reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
1482
|
+
}
|
|
1451
1483
|
}
|
|
1452
1484
|
},
|
|
1453
1485
|
"drift": {
|
|
1454
1486
|
"id": "drift",
|
|
1455
1487
|
"role": "feature",
|
|
1456
|
-
"version": "1.
|
|
1488
|
+
"version": "1.12.0",
|
|
1457
1489
|
"title": "Drift detection gates",
|
|
1458
1490
|
"description": "Drift detection gates for the planning loop. At execute:wave:post: a blocking schema drift gate (detects schema files changed without a database push) and a non-blocking codebase drift gate (detects structural additions not reflected in STRUCTURE.md). At plan:pre: a non-blocking, warn-only codebase drift gate (gated on workflow.plan_drift_precheck) that flags a stale codebase map before planning, so plans are authored against a fresh STRUCTURE.md instead of discovering drift mid-execution.",
|
|
1459
1491
|
"tier": "full",
|
|
@@ -1531,7 +1563,7 @@ const capabilities = {
|
|
|
1531
1563
|
"external-job": {
|
|
1532
1564
|
"id": "external-job",
|
|
1533
1565
|
"role": "feature",
|
|
1534
|
-
"version": "1.
|
|
1566
|
+
"version": "1.12.0",
|
|
1535
1567
|
"title": "Async external-job scheduler adapter",
|
|
1536
1568
|
"description": "Default-off producer of the async external-job manifest (#1164). At execute:wave:post an executor can externalize long-running compute (SLURM first, scheduler-pluggable), commit a .planning/async-jobs/<job>.json manifest, defer SUMMARY.md, and return external_job_waiting. The core loop (#1165) consumes the manifest; this capability is the only thing that writes it. NOTE on contribution point: #1164 specifies execute:wave:pre, but execute-phase.md only dispatches execute:wave:post today (wave:pre is declared in the loop host contract but not rendered); wiring wave:pre dispatch is a core-loop change #1164 explicitly puts out of scope, so this capability registers at wave:post and the executor honors the runtime_budget classification guidance before running any tagged task. The adapter (scripts/slurm-adapter.cjs) reads external_job.submit_timeout_ms / poll_timeout_ms / artifact_dir through the canonical capability-config seam (env override > config > registry default).",
|
|
1537
1569
|
"tier": "full",
|
|
@@ -1614,7 +1646,7 @@ const capabilities = {
|
|
|
1614
1646
|
"gap-analysis": {
|
|
1615
1647
|
"id": "gap-analysis",
|
|
1616
1648
|
"role": "feature",
|
|
1617
|
-
"version": "1.
|
|
1649
|
+
"version": "1.12.0",
|
|
1618
1650
|
"title": "Post-planning gap analysis",
|
|
1619
1651
|
"description": "Proactive, non-blocking post-planning coverage report. After all PLAN.md files are generated, cross-references every REQ-ID and D-ID from REQUIREMENTS.md and CONTEXT.md against plan bodies. Emits a Source | Item | Status table. Does not block phase advancement.",
|
|
1620
1652
|
"tier": "standard",
|
|
@@ -1655,7 +1687,7 @@ const capabilities = {
|
|
|
1655
1687
|
"gemini": {
|
|
1656
1688
|
"id": "gemini",
|
|
1657
1689
|
"role": "reviewer",
|
|
1658
|
-
"version": "1.
|
|
1690
|
+
"version": "1.12.0",
|
|
1659
1691
|
"title": "Gemini CLI",
|
|
1660
1692
|
"description": "Google Gemini CLI — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). Spawned as `gemini -p - -m <model>` with the plan piped on stdin.",
|
|
1661
1693
|
"tier": "full",
|
|
@@ -1690,7 +1722,7 @@ const capabilities = {
|
|
|
1690
1722
|
"reviewsSection": "Gemini",
|
|
1691
1723
|
"evidenceClass": "source-grounded",
|
|
1692
1724
|
"requiresBinaries": [],
|
|
1693
|
-
"promptBudgetKey":
|
|
1725
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.gemini",
|
|
1694
1726
|
"modelConfigKey": "review.models.gemini",
|
|
1695
1727
|
"handler": null
|
|
1696
1728
|
},
|
|
@@ -1699,13 +1731,18 @@ const capabilities = {
|
|
|
1699
1731
|
"type": "string",
|
|
1700
1732
|
"default": "",
|
|
1701
1733
|
"description": "Model passed to the Gemini reviewer lane."
|
|
1734
|
+
},
|
|
1735
|
+
"review.max_prompt_tokens_per_reviewer.gemini": {
|
|
1736
|
+
"type": "number",
|
|
1737
|
+
"default": -1,
|
|
1738
|
+
"description": "Prompt-token budget for the Gemini reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
1702
1739
|
}
|
|
1703
1740
|
}
|
|
1704
1741
|
},
|
|
1705
1742
|
"graphify": {
|
|
1706
1743
|
"id": "graphify",
|
|
1707
1744
|
"role": "feature",
|
|
1708
|
-
"version": "1.
|
|
1745
|
+
"version": "1.12.0",
|
|
1709
1746
|
"title": "Knowledge graph",
|
|
1710
1747
|
"description": "Build, query, and inspect the project knowledge graph in `.planning/graphs/`; exposes graphify CLI subcommands (build, query, status, diff) and the /gsd-graphify skill.",
|
|
1711
1748
|
"tier": "full",
|
|
@@ -1746,7 +1783,7 @@ const capabilities = {
|
|
|
1746
1783
|
"hermes": {
|
|
1747
1784
|
"id": "hermes",
|
|
1748
1785
|
"role": "runtime",
|
|
1749
|
-
"version": "1.
|
|
1786
|
+
"version": "1.12.0",
|
|
1750
1787
|
"title": "Hermes Agent",
|
|
1751
1788
|
"description": "Hermes Agent (NousResearch) — skills nest under skills/gsd/ category bucket; nested skill layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
1752
1789
|
"tier": "core",
|
|
@@ -1857,7 +1894,7 @@ const capabilities = {
|
|
|
1857
1894
|
"intel": {
|
|
1858
1895
|
"id": "intel",
|
|
1859
1896
|
"role": "feature",
|
|
1860
|
-
"version": "1.
|
|
1897
|
+
"version": "1.12.0",
|
|
1861
1898
|
"title": "Codebase intelligence",
|
|
1862
1899
|
"description": "Code-intelligence store for codebase querying, diff, snapshot, and API-surface extraction; exposes `gsd-tools intel` subcommands (query, status, update, diff, snapshot, patch-meta, validate, extract-exports, api-surface) and backs `/gsd-map-codebase` and `gsd-intel-updater`.",
|
|
1863
1900
|
"tier": "full",
|
|
@@ -1909,7 +1946,7 @@ const capabilities = {
|
|
|
1909
1946
|
"kilo": {
|
|
1910
1947
|
"id": "kilo",
|
|
1911
1948
|
"role": "runtime",
|
|
1912
|
-
"version": "1.
|
|
1949
|
+
"version": "1.12.0",
|
|
1913
1950
|
"title": "Kilo Code",
|
|
1914
1951
|
"description": "Kilo Code — XDG-based config dir; global skills at ~/.kilo/skills (separate from XDG config); flat command/ + skills artifact layout; no lifecycle hook registration; tier-2 support.",
|
|
1915
1952
|
"tier": "core",
|
|
@@ -2038,7 +2075,7 @@ const capabilities = {
|
|
|
2038
2075
|
"kimi": {
|
|
2039
2076
|
"id": "kimi",
|
|
2040
2077
|
"role": "runtime",
|
|
2041
|
-
"version": "1.
|
|
2078
|
+
"version": "1.12.0",
|
|
2042
2079
|
"title": "Kimi CLI",
|
|
2043
2080
|
"description": "Kimi CLI (Moonshot AI) — generic agents root at ~/.config/agents; skills + kimi-agents artifact layout; native config.toml [[hooks]] bus at ~/.kimi/config.toml; background dispatch; tier-2 support.",
|
|
2044
2081
|
"tier": "core",
|
|
@@ -2140,7 +2177,7 @@ const capabilities = {
|
|
|
2140
2177
|
"kimi-code": {
|
|
2141
2178
|
"id": "kimi-code",
|
|
2142
2179
|
"role": "runtime",
|
|
2143
|
-
"version": "1.
|
|
2180
|
+
"version": "1.12.0",
|
|
2144
2181
|
"title": "Kimi Code CLI",
|
|
2145
2182
|
"description": "Kimi Code CLI (Moonshot AI, Node) — Agent Skills auto-discovered at ~/.kimi-code/skills; global AGENTS.md at ~/.kimi-code/AGENTS.md; native config.toml + [[hooks]] bus; three built-in subagents (coder/explore/plan), NO custom named subagents; background dispatch; tier-2 support. Distinct from Python kimi-cli (the 'kimi' capability) per ADR-1239 EoS — Kimi Code cannot dispatch named subagents so the kimi-agents YAML layout does NOT apply; persona injection rides the existing ${AGENT_SKILLS_*} workflow fallback. Install-layout, agent-install-check, and install-time decision (kimi vs kimi-code) land in follow-up PRs; this descriptor is the EoS foundation.",
|
|
2146
2183
|
"tier": "core",
|
|
@@ -2278,7 +2315,7 @@ const capabilities = {
|
|
|
2278
2315
|
"reviewsSection": "Kimi Code",
|
|
2279
2316
|
"evidenceClass": "source-grounded",
|
|
2280
2317
|
"requiresBinaries": [],
|
|
2281
|
-
"promptBudgetKey":
|
|
2318
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.kimi-code",
|
|
2282
2319
|
"modelConfigKey": "review.models.kimi-code",
|
|
2283
2320
|
"handler": null
|
|
2284
2321
|
},
|
|
@@ -2287,13 +2324,71 @@ const capabilities = {
|
|
|
2287
2324
|
"type": "string",
|
|
2288
2325
|
"default": "",
|
|
2289
2326
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
2327
|
+
},
|
|
2328
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
2329
|
+
"type": "number",
|
|
2330
|
+
"default": -1,
|
|
2331
|
+
"description": "Prompt-token budget for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
2290
2332
|
}
|
|
2291
2333
|
}
|
|
2292
2334
|
},
|
|
2335
|
+
"live-dom-uat": {
|
|
2336
|
+
"id": "live-dom-uat",
|
|
2337
|
+
"role": "feature",
|
|
2338
|
+
"version": "1.12.0",
|
|
2339
|
+
"title": "Live-DOM UAT",
|
|
2340
|
+
"description": "Default-off live-DOM verification (#2856). Confines browser MCP reach to one purpose-built agent (gsd-dom-verifier) that carries the browser globs in its own tools: line, registered as an additive step hook at execute:wave:post. agents/gsd-executor.md is deliberately NOT widened: for a first-party agent the static tool list is the only control that exists, no capability can grant tools to one (ADR-1244 D2), no hook kind grants tool permissions (ADR-857 D4), and there is no per-dispatch tool override. Gated by activationKey workflow.live_dom_uat (default false), so with the key off the capability resolves inactive and the hook does not render at all. NOTE on the browser profile lock: chrome-devtools-mcp holds an exclusive lock on $HOME/.cache/chrome-devtools-mcp/chrome-profile, and --isolated is a flag on the user's own MCP-server registration that GSD cannot pass. Concurrent execution waves sharing one profile will therefore collide; the step tolerates and reports that (onError: skip, never blocking) rather than pretending to coordinate a resource it does not own.",
|
|
2341
|
+
"tier": "full",
|
|
2342
|
+
"requires": [],
|
|
2343
|
+
"engines": {
|
|
2344
|
+
"gsd": ">=1.11.0"
|
|
2345
|
+
},
|
|
2346
|
+
"runtimeCompat": {
|
|
2347
|
+
"supported": [
|
|
2348
|
+
"*"
|
|
2349
|
+
],
|
|
2350
|
+
"unsupported": []
|
|
2351
|
+
},
|
|
2352
|
+
"skills": [],
|
|
2353
|
+
"agents": [
|
|
2354
|
+
"gsd-dom-verifier"
|
|
2355
|
+
],
|
|
2356
|
+
"activationKey": "workflow.live_dom_uat",
|
|
2357
|
+
"config": {
|
|
2358
|
+
"workflow.live_dom_uat": {
|
|
2359
|
+
"type": "boolean",
|
|
2360
|
+
"default": false,
|
|
2361
|
+
"description": "Enable live-DOM verification. Default-off: browser MCP reach is opt-in per project. When on, the orchestrator's automated UI verification may additionally use mcp__chrome-devtools__* / mcp__claude-in-chrome__* when present, and a gsd-dom-verifier step runs after each execution wave. When off, neither surface reaches a browser and the pre-existing mcp__playwright__* path is unchanged."
|
|
2362
|
+
}
|
|
2363
|
+
},
|
|
2364
|
+
"hooks": [],
|
|
2365
|
+
"steps": [
|
|
2366
|
+
{
|
|
2367
|
+
"point": "execute:wave:post",
|
|
2368
|
+
"ref": {
|
|
2369
|
+
"agent": "gsd-dom-verifier"
|
|
2370
|
+
},
|
|
2371
|
+
"fragment": {
|
|
2372
|
+
"path": "fragments/execute-wave-post.md",
|
|
2373
|
+
"inline": "<objective>\nVerify the live-DOM acceptance criteria for the execution wave that just completed.\nAnswer: \"of this wave's stated UI acceptance criteria, which can I observe in a live DOM\nright now, and which could I not look at?\"\n\nThis step is ADDITIVE. It never halts the wave, never fails the phase, and never rewrites\nSUMMARY.md. If you cannot look, say so and finish.\n</objective>\n\n<required_reading>\n- {phase_dir}/{phase_num}-PLAN.md (the wave's tasks and their acceptance criteria)\n- {phase_dir}/{phase_num}-UI-SPEC.md if it exists (the design contract, when the phase has one)\n</required_reading>\n\n<browser_surface>\nYou carry exactly two browser MCP families: `mcp__chrome-devtools__*` and\n`mcp__claude-in-chrome__*`. Use whichever responds. Do not assume they expose the same\ntool names — probe, then use what is there. Do not paper over differences between them.\n\nYou do NOT carry the Playwright MCP family. That path belongs to the orchestrator's\nown verification step and is not yours.\n</browser_surface>\n\n<profile_lock>\n`chrome-devtools-mcp` holds an exclusive lock on its browser profile\n(`$HOME/.cache/chrome-devtools-mcp/chrome-profile`). A second concurrent instance fails with:\n\n```\nThe browser is already running for <dir>. Use --isolated to run multiple browser instances.\n```\n\nIf you see that, or any equivalent lock error:\n\n1. Record `outcome: could_not_look` and `reason: profile_locked`.\n2. Name `--isolated` in the notes, so the operator knows the remedy is a flag on THEIR MCP\n server registration.\n3. **Stop.** Do not retry, do not loop, do not wait for the lock. GSD cannot pass\n `--isolated` — it is not GSD's flag — and a retry loop here just holds up the wave.\n\nParallel execution waves sharing one profile WILL hit this. It is an expected condition,\nnot a defect, and it is not a reason to fail anything.\n</profile_lock>\n\n<method>\nFor each UI acceptance criterion you can identify in the wave's plan:\n\n1. Resolve its target URL. If no dev server or target is reachable, that criterion is\n `could_not_look` / `target_unreachable` — not a failure.\n2. Open it with the browser family that responded.\n3. Observe the DOM for the specific, stated condition. Assert on structure and content —\n an element's presence, its text, its attributes, its computed state.\n4. Record `passed` when the stated condition is observably true, `needs_review` when it is\n ambiguous or requires human judgement (subjective aesthetics, content accuracy).\n\nScope limit for this version: DOM observation against stated criteria only. No screenshot\ndiffing, no accessibility audit, no performance tracing. If a criterion needs one of those,\nmark it `needs_review` and say which.\n\nNever invent a criterion. If the plan states no UI acceptance criteria, that is\n`outcome: nothing_to_report` / `reason: no_criteria`, and it is a perfectly good result.\n</method>\n\n<output>\nWrite to: {phase_dir}/{phase_num}-DOM-VERIFY.md\n\nFrontmatter carries scalars only, so a reader can get the verdict without parsing prose:\n\n```\n---\nschema_version: 1\nwave: {wave_number}\noutcome: verified | nothing_to_report | could_not_look\nreason: ok | no_criteria | no_browser_mcp | profile_locked | target_unreachable\nchecked: <integer>\npassed: <integer>\nneeds_review: <integer>\n---\n```\n\nThen a short body: one line per criterion with its verdict, and — when `outcome` is\n`could_not_look` — exactly what stopped you and what the operator would change.\n\n**`nothing_to_report` and `could_not_look` are different outcomes and must never be\nconflated.** \"There were no UI criteria in this wave\" and \"there were criteria but I had no\nbrowser\" look identical in a summary that collapses them, and that ambiguity is the reported\nproblem this capability exists to remove.\n</output>\n"
|
|
2374
|
+
},
|
|
2375
|
+
"produces": [
|
|
2376
|
+
"DOM-VERIFY.md"
|
|
2377
|
+
],
|
|
2378
|
+
"consumes": [
|
|
2379
|
+
"PLAN.md"
|
|
2380
|
+
],
|
|
2381
|
+
"when": "workflow.live_dom_uat",
|
|
2382
|
+
"onError": "skip"
|
|
2383
|
+
}
|
|
2384
|
+
],
|
|
2385
|
+
"contributions": [],
|
|
2386
|
+
"gates": []
|
|
2387
|
+
},
|
|
2293
2388
|
"llama-cpp": {
|
|
2294
2389
|
"id": "llama-cpp",
|
|
2295
2390
|
"role": "reviewer",
|
|
2296
|
-
"version": "1.
|
|
2391
|
+
"version": "1.12.0",
|
|
2297
2392
|
"title": "llama.cpp",
|
|
2298
2393
|
"description": "llama.cpp server — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). OpenAI-compatible HTTP transport against a user-configured `review.llama_cpp_host` (POST /v1/chat/completions); model discovered via GET /v1/models piped through jq. Capability id/folder are kebab (`llama-cpp`, required by KEBAB_RE); `reviewer.slug` stays snake (`llama_cpp`) to match the shipped roster and the `review.llama_cpp_host` config key (ADR-2782's three-namespace trap).",
|
|
2299
2394
|
"tier": "full",
|
|
@@ -2351,7 +2446,7 @@ const capabilities = {
|
|
|
2351
2446
|
"lm-studio": {
|
|
2352
2447
|
"id": "lm-studio",
|
|
2353
2448
|
"role": "reviewer",
|
|
2354
|
-
"version": "1.
|
|
2449
|
+
"version": "1.12.0",
|
|
2355
2450
|
"title": "LM Studio",
|
|
2356
2451
|
"description": "LM Studio local model server — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). OpenAI-compatible HTTP transport against a user-configured `review.lm_studio_host` (POST /v1/chat/completions); model discovered via GET /v1/models piped through jq. Capability id/folder are kebab (`lm-studio`, required by KEBAB_RE); `reviewer.slug` stays snake (`lm_studio`) to match the shipped roster and the `review.lm_studio_host` config key (ADR-2782's three-namespace trap).",
|
|
2357
2452
|
"tier": "full",
|
|
@@ -2409,7 +2504,7 @@ const capabilities = {
|
|
|
2409
2504
|
"mempalace": {
|
|
2410
2505
|
"id": "mempalace",
|
|
2411
2506
|
"role": "feature",
|
|
2412
|
-
"version": "1.
|
|
2507
|
+
"version": "1.12.0",
|
|
2413
2508
|
"title": "MemPalace memory",
|
|
2414
2509
|
"description": "Cross-session, cross-project memory: deliberate recall before discuss/plan and verbatim capture + temporal-KG sync at phase boundaries, via the MemPalace MCP server and CLI.",
|
|
2415
2510
|
"tier": "full",
|
|
@@ -2583,7 +2678,7 @@ const capabilities = {
|
|
|
2583
2678
|
"nyquist": {
|
|
2584
2679
|
"id": "nyquist",
|
|
2585
2680
|
"role": "feature",
|
|
2586
|
-
"version": "1.
|
|
2681
|
+
"version": "1.12.0",
|
|
2587
2682
|
"title": "Nyquist validation",
|
|
2588
2683
|
"description": "Validation coverage audit that maps executed work back to tests and manual-only evidence.",
|
|
2589
2684
|
"tier": "full",
|
|
@@ -2633,7 +2728,7 @@ const capabilities = {
|
|
|
2633
2728
|
"ollama": {
|
|
2634
2729
|
"id": "ollama",
|
|
2635
2730
|
"role": "reviewer",
|
|
2636
|
-
"version": "1.
|
|
2731
|
+
"version": "1.12.0",
|
|
2637
2732
|
"title": "Ollama",
|
|
2638
2733
|
"description": "Ollama local model server — cross-AI /gsd:review reviewer lane only; not a GSD install target (no runtime body, no artifacts). OpenAI-compatible HTTP transport against a user-configured `review.ollama_host` (POST /v1/chat/completions); model discovered via GET /v1/models piped through jq.",
|
|
2639
2734
|
"tier": "full",
|
|
@@ -2691,7 +2786,7 @@ const capabilities = {
|
|
|
2691
2786
|
"opencode": {
|
|
2692
2787
|
"id": "opencode",
|
|
2693
2788
|
"role": "runtime",
|
|
2694
|
-
"version": "1.
|
|
2789
|
+
"version": "1.12.0",
|
|
2695
2790
|
"title": "OpenCode",
|
|
2696
2791
|
"description": "OpenCode — XDG-based config dir; flat commands/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
2697
2792
|
"tier": "core",
|
|
@@ -2852,7 +2947,7 @@ const capabilities = {
|
|
|
2852
2947
|
"reviewsSection": "OpenCode",
|
|
2853
2948
|
"evidenceClass": "source-grounded",
|
|
2854
2949
|
"requiresBinaries": [],
|
|
2855
|
-
"promptBudgetKey":
|
|
2950
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.opencode",
|
|
2856
2951
|
"modelConfigKey": "review.models.opencode",
|
|
2857
2952
|
"handler": "opencode"
|
|
2858
2953
|
},
|
|
@@ -2861,13 +2956,18 @@ const capabilities = {
|
|
|
2861
2956
|
"type": "string",
|
|
2862
2957
|
"default": "",
|
|
2863
2958
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
2959
|
+
},
|
|
2960
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
2961
|
+
"type": "number",
|
|
2962
|
+
"default": -1,
|
|
2963
|
+
"description": "Prompt-token budget for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
2864
2964
|
}
|
|
2865
2965
|
}
|
|
2866
2966
|
},
|
|
2867
2967
|
"pattern-mapper": {
|
|
2868
2968
|
"id": "pattern-mapper",
|
|
2869
2969
|
"role": "feature",
|
|
2870
|
-
"version": "1.
|
|
2970
|
+
"version": "1.12.0",
|
|
2871
2971
|
"title": "Pattern mapping",
|
|
2872
2972
|
"description": "Optional codebase-pattern mapping before planning; owns the pattern mapper agent and workflow.pattern_mapper activation key.",
|
|
2873
2973
|
"tier": "full",
|
|
@@ -2921,7 +3021,7 @@ const capabilities = {
|
|
|
2921
3021
|
"pi": {
|
|
2922
3022
|
"id": "pi",
|
|
2923
3023
|
"role": "runtime",
|
|
2924
|
-
"version": "1.
|
|
3024
|
+
"version": "1.12.0",
|
|
2925
3025
|
"title": "pi",
|
|
2926
3026
|
"description": "pi (pi.dev) — bun-runtime programmatic-CLI; TS ExtensionAPI (registerCommand/registerTool/registerProvider/pi.on); single native-extension file at ~/.pi/agent/extensions/gsd.js (.js, not .cjs — pi's extension auto-discovery accepts only .ts/.js, #2470); no shared-settings hook surface; tier-2 support.",
|
|
2927
3027
|
"tier": "core",
|
|
@@ -2990,7 +3090,7 @@ const capabilities = {
|
|
|
2990
3090
|
"profile-pipeline": {
|
|
2991
3091
|
"id": "profile-pipeline",
|
|
2992
3092
|
"role": "feature",
|
|
2993
|
-
"version": "1.
|
|
3093
|
+
"version": "1.12.0",
|
|
2994
3094
|
"title": "Developer profiling pipeline",
|
|
2995
3095
|
"description": "Developer behavioral profiling from Claude Code session history; scans session JSONL files, extracts and samples user messages, and generates profile artifacts (USER-PROFILE.md, dev-preferences.md, CLAUDE.md sections). Exposes eight `gsd-tools` commands: scan-sessions, extract-messages, profile-sample (pipeline phase) and write-profile, profile-questionnaire, generate-dev-preferences, generate-claude-profile, generate-claude-md (output phase). Backs the /gsd-profile-user skill and gsd-user-profiler agent.",
|
|
2996
3096
|
"tier": "full",
|
|
@@ -3067,7 +3167,7 @@ const capabilities = {
|
|
|
3067
3167
|
"qwen": {
|
|
3068
3168
|
"id": "qwen",
|
|
3069
3169
|
"role": "runtime",
|
|
3070
|
-
"version": "1.
|
|
3170
|
+
"version": "1.12.0",
|
|
3071
3171
|
"title": "Qwen Code",
|
|
3072
3172
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
3073
3173
|
"tier": "core",
|
|
@@ -3198,15 +3298,22 @@ const capabilities = {
|
|
|
3198
3298
|
"reviewsSection": "Qwen",
|
|
3199
3299
|
"evidenceClass": "source-grounded",
|
|
3200
3300
|
"requiresBinaries": [],
|
|
3201
|
-
"promptBudgetKey":
|
|
3301
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.qwen",
|
|
3202
3302
|
"modelConfigKey": null,
|
|
3203
3303
|
"handler": null
|
|
3304
|
+
},
|
|
3305
|
+
"config": {
|
|
3306
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
3307
|
+
"type": "number",
|
|
3308
|
+
"default": -1,
|
|
3309
|
+
"description": "Prompt-token budget for the Qwen Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
3310
|
+
}
|
|
3204
3311
|
}
|
|
3205
3312
|
},
|
|
3206
3313
|
"refactor-trigger": {
|
|
3207
3314
|
"id": "refactor-trigger",
|
|
3208
3315
|
"role": "feature",
|
|
3209
|
-
"version": "1.
|
|
3316
|
+
"version": "1.12.0",
|
|
3210
3317
|
"title": "Complexity-triggered refactor",
|
|
3211
3318
|
"description": "Measures the complexity of the code a phase touched and, when a function crosses a configured threshold or jumps past its recorded anchor, surfaces a scoped refactor proposal at .planning/phases/<N>/<NN>-REFACTOR.md. Advisory by default — it never edits code and never blocks. Opt-in strict mode blocks /gsd-ship while a proposal is untriaged; a declined proposal is recorded in the broken-windows ledger when that capability is present. Operationalizes 'refactor early, refactor often' as continuous pressure instead of a thing you have to remember (issue #1953).",
|
|
3212
3319
|
"tier": "full",
|
|
@@ -3273,7 +3380,7 @@ const capabilities = {
|
|
|
3273
3380
|
"research": {
|
|
3274
3381
|
"id": "research",
|
|
3275
3382
|
"role": "feature",
|
|
3276
|
-
"version": "1.
|
|
3383
|
+
"version": "1.12.0",
|
|
3277
3384
|
"title": "Phase research",
|
|
3278
3385
|
"description": "Optional phase research before planning; owns the phase researcher agent and workflow.research activation key.",
|
|
3279
3386
|
"tier": "standard",
|
|
@@ -3325,7 +3432,7 @@ const capabilities = {
|
|
|
3325
3432
|
"schema-gate": {
|
|
3326
3433
|
"id": "schema-gate",
|
|
3327
3434
|
"role": "feature",
|
|
3328
|
-
"version": "1.
|
|
3435
|
+
"version": "1.12.0",
|
|
3329
3436
|
"title": "Schema push detection gate",
|
|
3330
3437
|
"description": "Detects ORM schema-relevant files in the phase scope during planning and injects a mandatory [BLOCKING] schema push task into the plan. Prevents false-positive verification where build/types pass because TypeScript types come from config, not the live database.",
|
|
3331
3438
|
"tier": "full",
|
|
@@ -3371,7 +3478,7 @@ const capabilities = {
|
|
|
3371
3478
|
"security": {
|
|
3372
3479
|
"id": "security",
|
|
3373
3480
|
"role": "feature",
|
|
3374
|
-
"version": "1.
|
|
3481
|
+
"version": "1.12.0",
|
|
3375
3482
|
"title": "Security enforcement",
|
|
3376
3483
|
"description": "Threat mitigation verification and ship-time security blocking for phases with security enforcement enabled.",
|
|
3377
3484
|
"tier": "full",
|
|
@@ -3470,7 +3577,7 @@ const capabilities = {
|
|
|
3470
3577
|
"tdd": {
|
|
3471
3578
|
"id": "tdd",
|
|
3472
3579
|
"role": "feature",
|
|
3473
|
-
"version": "1.
|
|
3580
|
+
"version": "1.12.0",
|
|
3474
3581
|
"title": "Test-driven development",
|
|
3475
3582
|
"description": "Injects TDD heuristics into the planner and enforces RED/GREEN gate compliance on type:tdd plans after execution. Owns workflow.tdd_mode; the --tdd CLI flag is the ephemeral override.",
|
|
3476
3583
|
"tier": "full",
|
|
@@ -3523,7 +3630,7 @@ const capabilities = {
|
|
|
3523
3630
|
"trae": {
|
|
3524
3631
|
"id": "trae",
|
|
3525
3632
|
"role": "runtime",
|
|
3526
|
-
"version": "1.
|
|
3633
|
+
"version": "1.12.0",
|
|
3527
3634
|
"title": "Trae IDE",
|
|
3528
3635
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
3529
3636
|
"tier": "core",
|
|
@@ -3620,7 +3727,7 @@ const capabilities = {
|
|
|
3620
3727
|
"ui": {
|
|
3621
3728
|
"id": "ui",
|
|
3622
3729
|
"role": "feature",
|
|
3623
|
-
"version": "1.
|
|
3730
|
+
"version": "1.12.0",
|
|
3624
3731
|
"title": "UI design contracts",
|
|
3625
3732
|
"description": "UI-SPEC design contract + retrospective UI audit for frontend phases.",
|
|
3626
3733
|
"tier": "full",
|
|
@@ -3715,7 +3822,7 @@ const capabilities = {
|
|
|
3715
3822
|
"vscode": {
|
|
3716
3823
|
"id": "vscode",
|
|
3717
3824
|
"role": "runtime",
|
|
3718
|
-
"version": "1.
|
|
3825
|
+
"version": "1.12.0",
|
|
3719
3826
|
"title": "VS Code",
|
|
3720
3827
|
"description": "VS Code — Marketplace/VSIX extension; no file-projected config directory; IDE-profile reference host (active vscode.lm model, engine-owned hook bus, sandboxed globalState/workspaceState stateIO).",
|
|
3721
3828
|
"tier": "core",
|
|
@@ -3772,7 +3879,7 @@ const capabilities = {
|
|
|
3772
3879
|
"windsurf": {
|
|
3773
3880
|
"id": "windsurf",
|
|
3774
3881
|
"role": "runtime",
|
|
3775
|
-
"version": "1.
|
|
3882
|
+
"version": "1.12.0",
|
|
3776
3883
|
"title": "Windsurf",
|
|
3777
3884
|
"description": "Windsurf (Codeium) — workspace workflow artifact layout for slash commands; Cascade native hooks.json blocking hook bus (pre_write_code, pre_run_command); tier-2 support.",
|
|
3778
3885
|
"tier": "core",
|
|
@@ -3863,7 +3970,7 @@ const capabilities = {
|
|
|
3863
3970
|
"zcode": {
|
|
3864
3971
|
"id": "zcode",
|
|
3865
3972
|
"role": "runtime",
|
|
3866
|
-
"version": "1.
|
|
3973
|
+
"version": "1.12.0",
|
|
3867
3974
|
"title": "ZCode",
|
|
3868
3975
|
"description": "ZCode (Z.ai) — desktop Agentic Development Environment for GLM-5.2; Claude-shaped nested skills at ~/.zcode/skills/<name>/SKILL.md, slash commands, named subagents, native MCP; declarative plugin surface; profile-marker install; tier-2 community support.",
|
|
3869
3976
|
"tier": "core",
|
|
@@ -3993,6 +4100,7 @@ const byAgent = {
|
|
|
3993
4100
|
"gsd-eval-planner": "ai-integration",
|
|
3994
4101
|
"gsd-code-reviewer": "code-review",
|
|
3995
4102
|
"gsd-code-fixer": "code-review",
|
|
4103
|
+
"gsd-dom-verifier": "live-dom-uat",
|
|
3996
4104
|
"gsd-mempalace-curator": "mempalace",
|
|
3997
4105
|
"gsd-nyquist-auditor": "nyquist",
|
|
3998
4106
|
"gsd-pattern-mapper": "pattern-mapper",
|
|
@@ -4148,7 +4256,7 @@ const byLoopPoint = {
|
|
|
4148
4256
|
"into": "planner",
|
|
4149
4257
|
"fragment": {
|
|
4150
4258
|
"path": "fragments/api-coverage-plan-pre.md",
|
|
4151
|
-
"inline": "# API Coverage Decision Checkpoint\n\n> Full API Coverage by Default — Opt Out, Never Opt In. Fires when a phase\n> integrates an external API / SDK / service. Most non-API phases will not fire\n> it — that is the point.\n\n## Why this exists\n\n\"We integrated the API\" too often silently means \"we integrated whatever the\nfirst use case exercised.\" Every un-built capability is then an invisible hole,\ndiscovered later by a user who reasonably expected it to work. The phase sealed\ngreen because its tasks completed; nobody decided the gaps were acceptable,\nbecause nobody enumerated them. This checkpoint makes the surface **visible and\ndecided** before the phase can seal.\n\n## Detect whether this phase integrates an external API\n\nThe detector is a deterministic scan over the phase scope. It strips fenced\ncode blocks first, so a trigger term inside a code snippet does not fire. It\nreturns a typed result: `{ detected, signals[], terms }`. Run it on the phase\nscope (the concatenation of this phase's ROADMAP section + the PLAN body):\n\n```bash\nSCOPE=\"$(cat \"${PHASE_DIR}\"/*-PLAN.md 2>/dev/null) $(gsd_run query roadmap.get-phase \"${PHASE}\" 2>/dev/null || true)\"\nAPI_COVERAGE_JSON=$(printf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json 2>/dev/null ||
|
|
4259
|
+
"inline": "# API Coverage Decision Checkpoint\n\n> Full API Coverage by Default — Opt Out, Never Opt In. Fires when a phase\n> integrates an external API / SDK / service. Most non-API phases will not fire\n> it — that is the point.\n\n## Why this exists\n\n\"We integrated the API\" too often silently means \"we integrated whatever the\nfirst use case exercised.\" Every un-built capability is then an invisible hole,\ndiscovered later by a user who reasonably expected it to work. The phase sealed\ngreen because its tasks completed; nobody decided the gaps were acceptable,\nbecause nobody enumerated them. This checkpoint makes the surface **visible and\ndecided** before the phase can seal.\n\n## Detect whether this phase integrates an external API\n\nThe detector is a deterministic scan over the phase scope. It strips fenced\ncode blocks first, so a trigger term inside a code snippet does not fire. It\nreturns a typed result: `{ detected, signals[], terms }`. Run it on the phase\nscope (the concatenation of this phase's ROADMAP section + the PLAN body):\n\n```bash\nSCOPE=\"$(cat \"${PHASE_DIR}\"/*-PLAN.md 2>/dev/null) $(gsd_run query roadmap.get-phase \"${PHASE}\" 2>/dev/null || true)\"\nAPI_COVERAGE_JSON=$(printf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json 2>/dev/null) || true\n[ -n \"$API_COVERAGE_JSON\" ] || API_COVERAGE_JSON='{\"skipped\":true,\"reason\":\"probe_unavailable\"}'\n```\n\nThe `|| true` neutralizes the assignment's status without discarding the\ndetector's own payload: the detector exits **1** for a real \"no integration\"\nverdict, so treating any non-zero exit as failure would throw away a correct\nanswer. Emptiness — not exit status — is what proves the probe never ran, and\nthe second line is the only place the fragment manufactures a payload of its\nown — one that records the *absence* of a verdict rather than asserting one.\n\nThe detector's exit code and `--json` payload now distinguish a real negative\nfrom an unexamined input (ADR-3889 Phase 3, #3907): empty/whitespace-only\n`$SCOPE` or a stdin read failure emit `{\"skipped\":true,\"reason\":\"no_input\"|\n\"stdin_error\"}` — no `detected` key at all. **Check for `skipped` before\nreading `detected`**: a `skipped` payload is not a confirmed \"no API\nintegration\" verdict, it means the detector never examined real input. Do not\ntreat it as `detected:false`. Read `API_COVERAGE_JSON.detected` only when\n`skipped` is absent — act on it only, do **not** pattern-match the prose\nyourself.\n\n**If `skipped` is `true`:** the detector could not establish a scope (empty\n`$SCOPE`) or failed to run (stdin read error). Skip the checkpoint for this\nrun rather than asserting a verdict about input that was never examined; do\nnot raise it with the user.\n\n**If `detected` is `false`:** this phase does not integrate an external API. Skip\nthe checkpoint entirely and continue planning. Do not raise it with the user.\n\n**If `detected` is `true`:** an external-API integration is in scope. You MUST\nproduce a **coverage matrix** before the plan is finalized.\n\n**If `detected` is `true` but the phase genuinely integrates no external API**\n(the detector is deterministic, not infallible — confirm by re-reading the phase\nscope, not by preference): do NOT fabricate a matrix row for a capability that\ndoes not exist. Write a reasoned declaration to `${PHASE_DIR}/COVERAGE.md`\ninstead:\n\n```markdown\nNo external API integration: <one-line reason — what the phase touches instead>.\n```\n\nThe reason is required, exactly like an `OPT-OUT` reason. The seal-time gate\naccepts this declaration in place of a matrix.\n\n## Produce the coverage matrix\n\nEnumerate the external API's full **capability surface** — the verb/endpoint/method\nlist (e.g. for a music service: `search`, `play`, `pause`, `skip`, `set_volume`,\n`get_playlist`, `create_playlist`, `add_to_playlist`, …). For each capability\nrecord a decision, starting from **full coverage** as the default:\n\n| capability | decision | reason |\n|---|---|---|\n| `<capability-id>` | `INTEGRATE` \\| `OPT-OUT` | `<one-line reason if OPT-OUT>` |\n\nRules:\n\n- **`INTEGRATE` is the default.** Every capability starts as INTEGRATE; the\n matrix is the *subtraction record*.\n- **Every `OPT-OUT` MUST carry a one-line reason** (`not needed`, `not needed\n yet`, `explicitly out of scope`, …). An opt-out without a reason is an\n un-decided hole — the exact failure mode this gate exists to close.\n- **A second integration against the same need** (e.g. a second platform for the\n same capability) starts from the **same full-coverage baseline** as the first.\n Do not carry over the first integration's opt-outs silently — re-decide each\n capability for the new surface, so a first-class/fallback asymmetry cannot\n accumulate.\n\nWrite the matrix to `${PHASE_DIR}/COVERAGE.md` (canonical markdown-table form):\n\n```markdown\n# API Coverage — <service>\n\n> Full coverage by default. Opt-outs are explicit, reasoned decisions.\n\n| capability | decision | reason |\n|---|---|---|\n| search | INTEGRATE | |\n| playlists | INTEGRATE | |\n| skip | OPT-OUT | not needed yet — tracked for follow-up phase |\n```\n\nA fenced ` ```coverage ` JSON block is also accepted for machine-generated\nmatrices; the markdown table is preferred (human-editable, diff-friendly).\n\n## The seal-time gate\n\nThis checkpoint is enforced. At `verify:pre` the `api-coverage.verify-pre` gate\nruns `check api-coverage.verify-pre <phase-dir>`:\n\n- If `COVERAGE.md` exists, it is validated — every row needs a valid decision and\n every `OPT-OUT` a reason. A malformed/partial matrix **blocks the seal**. A\n reasoned `No external API integration: …` declaration (and no rows) passes.\n- If `COVERAGE.md` is absent, the detector runs again over the phase scope. If a\n strong external-API-integration signal is found, the seal is **blocked** until a\n matrix is produced. If no signal is found, the phase is treated as a non-API\n phase and the seal proceeds.\n\nSo: an API-integrating phase cannot seal without a decided matrix. Produce it at\nplan time; do not leave it for seal time.\n\n## Tuning the vocabulary (optional)\n\nThe trigger vocabulary is a curated, additive-only set in\n`gsd-core/bin/lib/api-coverage.cjs` (`DEFAULT_API_COVERAGE_TERMS`). To widen it\nfor a project, override at the call site:\n\n```bash\nprintf '%s' \"$SCOPE\" | node gsd-core/bin/lib/api-coverage.cjs --json \\\n --verbs integrate,wrap,connect,embed --nouns api,sdk,rest,grpc,webhook,plugin\n```\n\nThe whole checkpoint is toggleable via `workflow.api_coverage_gate` in\n`.planning/config.json`.\n"
|
|
4152
4260
|
},
|
|
4153
4261
|
"produces": [
|
|
4154
4262
|
"COVERAGE.md"
|
|
@@ -4165,7 +4273,7 @@ const byLoopPoint = {
|
|
|
4165
4273
|
"into": "planner",
|
|
4166
4274
|
"fragment": {
|
|
4167
4275
|
"path": "fragments/plan-pre.md",
|
|
4168
|
-
"inline": "# Assumption-Delta Architecture Checkpoint\n\n> Advisory, non-blocking. Fires **only** when the phase scope shows a singular→plural / required→optional / derived→chosen transition. When it fires, it surfaces ONE identity-model question before the plan is finalized. Most phases will not fire it — that is the point.\n\n## Why this exists\n\nMost quietly-imported architectural debt does not come from a missing upfront design phase. It comes at the *seam*: a later phase introduces a second case (a second platform, auth method, tenant, region, source of truth) and nobody re-asks whether the original abstraction still names the right thing. The phase that adds the second case is exactly the 20-minute conversation that prevents an afternoon of later cleanup.\n\n## Run the detector\n\nThe detector is a deterministic scan over the phase scope text. It strips fenced code blocks first, so a trigger word that appears only inside a code snippet does not fire. It returns a typed result: `{ detected, signals[], terms }`. Resolve it through the `assumption-delta scan` query (same phase-section resolver as `roadmap.get-phase`):\n\n```bash\nASSUMPTION_DELTA_JSON=$(gsd_run query assumption-delta scan \"${PHASE}\" --json 2>/dev/null ||
|
|
4276
|
+
"inline": "# Assumption-Delta Architecture Checkpoint\n\n> Advisory, non-blocking. Fires **only** when the phase scope shows a singular→plural / required→optional / derived→chosen transition. When it fires, it surfaces ONE identity-model question before the plan is finalized. Most phases will not fire it — that is the point.\n\n## Why this exists\n\nMost quietly-imported architectural debt does not come from a missing upfront design phase. It comes at the *seam*: a later phase introduces a second case (a second platform, auth method, tenant, region, source of truth) and nobody re-asks whether the original abstraction still names the right thing. The phase that adds the second case is exactly the 20-minute conversation that prevents an afternoon of later cleanup.\n\n## Run the detector\n\nThe detector is a deterministic scan over the phase scope text. It strips fenced code blocks first, so a trigger word that appears only inside a code snippet does not fire. It returns a typed result: `{ detected, signals[], terms }`. Resolve it through the `assumption-delta scan` query (same phase-section resolver as `roadmap.get-phase`):\n\n```bash\nASSUMPTION_DELTA_JSON=$(gsd_run query assumption-delta scan \"${PHASE}\" --json 2>/dev/null) || true\n[ -n \"$ASSUMPTION_DELTA_JSON\" ] || ASSUMPTION_DELTA_JSON='{\"skipped\":true,\"reason\":\"probe_unavailable\"}'\n```\n\n> If the phase section cannot be resolved (no `ROADMAP.md` / unknown phase, or a section with no body), the query emits `{ \"skipped\": true, \"reason\": \"phase_unresolved\" }` — **not** `detected:false`. A probe that never had input does not get to assert that this phase changes no core assumption. The checkpoint does not fire either way; the difference is that a skip is now distinguishable from a real negative. Do not block on it.\n>\n> Optional tuning — pass `--terms <comma-list>` to replace the curated pluralization cues for this project (the `optional`/`chosen` cues keep their defaults): `gsd_run query assumption-delta scan \"${PHASE}\" --json --terms second,alternative,fallback`.\n\n## Decision branch\n\nRead `ASSUMPTION_DELTA_JSON`. Act on `detected` only — do **not** pattern-match the human prose.\n\n**If `skipped` is `true`:** the detector never examined a phase section — it could not resolve one (`phase_unresolved`) or could not run at all (`probe_unavailable`). Skip the checkpoint for this run rather than asserting a verdict about input that was never examined; do not raise it with the user. **Check for `skipped` before reading `detected`** — a skipped payload carries no `detected` key, and treating its absence as `false` re-creates the fabrication this branch exists to prevent.\n\n**If `detected` is `false`:** this phase does not change a core assumption. Skip the checkpoint entirely and continue planning. Do not raise it with the user.\n\n**If `detected` is `true`:** a core assumption may have lost its monopoly. The `signals[]` array tells you which family fired:\n\n| `kind` | What changed | The question to answer |\n|---|---|---|\n| `pluralization` | A second X was introduced where there was one (second platform / auth method / tenant / region / source of truth) | Does the current primary key / identity model still name the right noun? |\n| `optional` | A required / `only` field became optional | Is the field still the right anchor, or has the anchor moved? |\n| `chosen` | A derived value became chosen, or a constant became a parameter | Has a configuration decision become a modeling decision? |\n\nBefore finalizing the plan, answer this for the user and record the decision explicitly:\n\n> **Promote vs. add-alongside.** The usual correct move when a generalization occurs is to **promote** the new general representation to the primary and **demote** the old specific one to a detail of one variant — *not* to add the new one alongside the still-required old one. Adding alongside silently contradicts the generalized intent (a later variant that does not fit the old primary can be stored but never confirmed as a default).\n\nRecord the outcome in the PLAN.md front matter / a `<assumption_delta_decision>` block:\n\n- The **noun** that is now primary (the generalized identity).\n- The **decision**: `promote` | `add-alongside` | `no-change`, with a one-line rationale.\n- If `add-alongside`: call it out as accepted debt and note what would force a later promote.\n\n## Optional companion: an invariant test\n\nWhen `detected` is `true`, suggest (do not require) a contract/invariant test that encodes the now-generalized intent — e.g. *\"every confirmed default round-trips through the primary use-path, for every supported variant.\"* That test goes red the instant a future phase reintroduces the singular assumption, so the regression cannot land silently. If the user accepts, add the test as a task in the plan.\n\n## Tuning the vocabulary (optional)\n\nThe trigger vocabulary is a curated, additive-only set in `gsd-core/bin/lib/assumption-delta.cjs` (`DEFAULT_ASSUMPTION_DELTA_TERMS`). Bare \"or\" is intentionally excluded — it is too common in prose and would make the gate fire constantly. To widen or narrow the cues for a project, override at the call site with `--terms <comma-list>` (replaces the pluralization cues; `optional`/`chosen` keep defaults). The whole checkpoint is toggleable via `workflow.assumption_delta` in `.planning/config.json`.\n\nThis checkpoint is advisory: it informs and records; it never blocks the phase.\n"
|
|
4169
4277
|
},
|
|
4170
4278
|
"produces": [],
|
|
4171
4279
|
"consumes": [
|
|
@@ -4315,7 +4423,7 @@ const byLoopPoint = {
|
|
|
4315
4423
|
"into": "executor",
|
|
4316
4424
|
"fragment": {
|
|
4317
4425
|
"path": "fragments/execute-wave-pre.md",
|
|
4318
|
-
"inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version <ver>` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME <objective>...<success_criteria> prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the `<objective>`/`<execution_context>`/`<required_reading>`/\n `<success_criteria>` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version <ver>` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `<worktree_metadata>` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"<metadata.agent_id>\" --path \"<metadata.worktree_path>\" \\\n --branch \"<metadata.branch>\" --base \"<metadata.expected_base>\" \\\n --files \"<plan files_modified, space-separated>\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n"
|
|
4426
|
+
"inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version <ver>` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME <objective>...<success_criteria> prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the `<objective>`/`<execution_context>`/`<required_reading>`/\n `<success_criteria>` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version <ver>` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `<worktree_metadata>` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"<metadata.agent_id>\" --path \"<metadata.worktree_path>\" \\\n --branch \"<metadata.branch>\" --base \"<metadata.expected_base>\" \\\n --files \"<plan files_modified, space-separated>\" \\\n --deletions \"<plan files_deleted, space-separated>\"\n ```\n\n `--deletions` (#3003) carries the plan's declared `files_deleted` so a plan that scoped a file\n removal merges through `cleanup-wave` instead of being blocked. Unlike `--files` it is not\n advisory: omitting it leaves the deletions guard blocking on any deletion at all, so this\n dispatch path must pass it or plans declaring a removal fail to merge here while succeeding on\n the inline path.\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n"
|
|
4319
4427
|
},
|
|
4320
4428
|
"produces": [],
|
|
4321
4429
|
"consumes": [
|
|
@@ -4328,7 +4436,27 @@ const byLoopPoint = {
|
|
|
4328
4436
|
"gates": []
|
|
4329
4437
|
},
|
|
4330
4438
|
"execute:wave:post": {
|
|
4331
|
-
"steps": [
|
|
4439
|
+
"steps": [
|
|
4440
|
+
{
|
|
4441
|
+
"capId": "live-dom-uat",
|
|
4442
|
+
"point": "execute:wave:post",
|
|
4443
|
+
"ref": {
|
|
4444
|
+
"agent": "gsd-dom-verifier"
|
|
4445
|
+
},
|
|
4446
|
+
"fragment": {
|
|
4447
|
+
"path": "fragments/execute-wave-post.md",
|
|
4448
|
+
"inline": "<objective>\nVerify the live-DOM acceptance criteria for the execution wave that just completed.\nAnswer: \"of this wave's stated UI acceptance criteria, which can I observe in a live DOM\nright now, and which could I not look at?\"\n\nThis step is ADDITIVE. It never halts the wave, never fails the phase, and never rewrites\nSUMMARY.md. If you cannot look, say so and finish.\n</objective>\n\n<required_reading>\n- {phase_dir}/{phase_num}-PLAN.md (the wave's tasks and their acceptance criteria)\n- {phase_dir}/{phase_num}-UI-SPEC.md if it exists (the design contract, when the phase has one)\n</required_reading>\n\n<browser_surface>\nYou carry exactly two browser MCP families: `mcp__chrome-devtools__*` and\n`mcp__claude-in-chrome__*`. Use whichever responds. Do not assume they expose the same\ntool names — probe, then use what is there. Do not paper over differences between them.\n\nYou do NOT carry the Playwright MCP family. That path belongs to the orchestrator's\nown verification step and is not yours.\n</browser_surface>\n\n<profile_lock>\n`chrome-devtools-mcp` holds an exclusive lock on its browser profile\n(`$HOME/.cache/chrome-devtools-mcp/chrome-profile`). A second concurrent instance fails with:\n\n```\nThe browser is already running for <dir>. Use --isolated to run multiple browser instances.\n```\n\nIf you see that, or any equivalent lock error:\n\n1. Record `outcome: could_not_look` and `reason: profile_locked`.\n2. Name `--isolated` in the notes, so the operator knows the remedy is a flag on THEIR MCP\n server registration.\n3. **Stop.** Do not retry, do not loop, do not wait for the lock. GSD cannot pass\n `--isolated` — it is not GSD's flag — and a retry loop here just holds up the wave.\n\nParallel execution waves sharing one profile WILL hit this. It is an expected condition,\nnot a defect, and it is not a reason to fail anything.\n</profile_lock>\n\n<method>\nFor each UI acceptance criterion you can identify in the wave's plan:\n\n1. Resolve its target URL. If no dev server or target is reachable, that criterion is\n `could_not_look` / `target_unreachable` — not a failure.\n2. Open it with the browser family that responded.\n3. Observe the DOM for the specific, stated condition. Assert on structure and content —\n an element's presence, its text, its attributes, its computed state.\n4. Record `passed` when the stated condition is observably true, `needs_review` when it is\n ambiguous or requires human judgement (subjective aesthetics, content accuracy).\n\nScope limit for this version: DOM observation against stated criteria only. No screenshot\ndiffing, no accessibility audit, no performance tracing. If a criterion needs one of those,\nmark it `needs_review` and say which.\n\nNever invent a criterion. If the plan states no UI acceptance criteria, that is\n`outcome: nothing_to_report` / `reason: no_criteria`, and it is a perfectly good result.\n</method>\n\n<output>\nWrite to: {phase_dir}/{phase_num}-DOM-VERIFY.md\n\nFrontmatter carries scalars only, so a reader can get the verdict without parsing prose:\n\n```\n---\nschema_version: 1\nwave: {wave_number}\noutcome: verified | nothing_to_report | could_not_look\nreason: ok | no_criteria | no_browser_mcp | profile_locked | target_unreachable\nchecked: <integer>\npassed: <integer>\nneeds_review: <integer>\n---\n```\n\nThen a short body: one line per criterion with its verdict, and — when `outcome` is\n`could_not_look` — exactly what stopped you and what the operator would change.\n\n**`nothing_to_report` and `could_not_look` are different outcomes and must never be\nconflated.** \"There were no UI criteria in this wave\" and \"there were criteria but I had no\nbrowser\" look identical in a summary that collapses them, and that ambiguity is the reported\nproblem this capability exists to remove.\n</output>\n"
|
|
4449
|
+
},
|
|
4450
|
+
"produces": [
|
|
4451
|
+
"DOM-VERIFY.md"
|
|
4452
|
+
],
|
|
4453
|
+
"consumes": [
|
|
4454
|
+
"PLAN.md"
|
|
4455
|
+
],
|
|
4456
|
+
"when": "workflow.live_dom_uat",
|
|
4457
|
+
"onError": "skip"
|
|
4458
|
+
}
|
|
4459
|
+
],
|
|
4332
4460
|
"contributions": [
|
|
4333
4461
|
{
|
|
4334
4462
|
"capId": "external-job",
|
|
@@ -4580,15 +4708,20 @@ const configKeys = {
|
|
|
4580
4708
|
"workflow.ai_integration_phase": "ai-integration",
|
|
4581
4709
|
"workflow.api_coverage_gate": "ai-integration",
|
|
4582
4710
|
"review.models.agy": "antigravity",
|
|
4711
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": "antigravity",
|
|
4583
4712
|
"workflow.assumption_delta": "assumption-delta",
|
|
4584
4713
|
"workflow.windows_enforce": "broken-windows",
|
|
4585
4714
|
"review.models.claude": "claude",
|
|
4715
|
+
"review.max_prompt_tokens_per_reviewer.claude": "claude",
|
|
4586
4716
|
"claude_orchestration.enabled": "claude-orchestration",
|
|
4587
4717
|
"claude_orchestration.execution_backend": "claude-orchestration",
|
|
4588
4718
|
"claude_orchestration.min_agent_sdk_version": "claude-orchestration",
|
|
4589
4719
|
"workflow.code_review": "code-review",
|
|
4590
4720
|
"workflow.code_review_depth": "code-review",
|
|
4721
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": "coderabbit",
|
|
4591
4722
|
"review.models.codex": "codex",
|
|
4723
|
+
"review.max_prompt_tokens_per_reviewer.codex": "codex",
|
|
4724
|
+
"review.max_prompt_tokens_per_reviewer.cursor": "cursor",
|
|
4592
4725
|
"workflow.drift_threshold": "drift",
|
|
4593
4726
|
"workflow.drift_action": "drift",
|
|
4594
4727
|
"workflow.schema_drift_gate": "drift",
|
|
@@ -4600,9 +4733,12 @@ const configKeys = {
|
|
|
4600
4733
|
"external_job.poll_timeout_ms": "external-job",
|
|
4601
4734
|
"workflow.post_planning_gaps": "gap-analysis",
|
|
4602
4735
|
"review.models.gemini": "gemini",
|
|
4736
|
+
"review.max_prompt_tokens_per_reviewer.gemini": "gemini",
|
|
4603
4737
|
"graphify.enabled": "graphify",
|
|
4604
4738
|
"intel.enabled": "intel",
|
|
4605
4739
|
"review.models.kimi-code": "kimi-code",
|
|
4740
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": "kimi-code",
|
|
4741
|
+
"workflow.live_dom_uat": "live-dom-uat",
|
|
4606
4742
|
"review.models.llama_cpp": "llama-cpp",
|
|
4607
4743
|
"review.llama_cpp_host": "llama-cpp",
|
|
4608
4744
|
"review.max_prompt_tokens_per_reviewer.llama_cpp": "llama-cpp",
|
|
@@ -4624,8 +4760,10 @@ const configKeys = {
|
|
|
4624
4760
|
"review.ollama_host": "ollama",
|
|
4625
4761
|
"review.max_prompt_tokens_per_reviewer.ollama": "ollama",
|
|
4626
4762
|
"review.models.opencode": "opencode",
|
|
4763
|
+
"review.max_prompt_tokens_per_reviewer.opencode": "opencode",
|
|
4627
4764
|
"workflow.pattern_mapper": "pattern-mapper",
|
|
4628
4765
|
"profile-pipeline.enabled": "profile-pipeline",
|
|
4766
|
+
"review.max_prompt_tokens_per_reviewer.qwen": "qwen",
|
|
4629
4767
|
"refactor.trigger_enabled": "refactor-trigger",
|
|
4630
4768
|
"refactor.complexity_threshold": "refactor-trigger",
|
|
4631
4769
|
"refactor.complexity_jump_delta": "refactor-trigger",
|
|
@@ -4660,6 +4798,12 @@ const configSchema = {
|
|
|
4660
4798
|
"default": "",
|
|
4661
4799
|
"description": "Model passed to the Antigravity reviewer lane. The key suffix is the lane binary/flag alias `agy`, not the slug `antigravity` — preserved verbatim so existing .planning/config.json files keep working."
|
|
4662
4800
|
},
|
|
4801
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
4802
|
+
"owner": "antigravity",
|
|
4803
|
+
"type": "number",
|
|
4804
|
+
"default": -1,
|
|
4805
|
+
"description": "Prompt-token budget for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\". Keyed on the reviewer slug `antigravity`, not the `agy` binary alias used by review.models.agy."
|
|
4806
|
+
},
|
|
4663
4807
|
"workflow.assumption_delta": {
|
|
4664
4808
|
"owner": "assumption-delta",
|
|
4665
4809
|
"type": "boolean",
|
|
@@ -4678,6 +4822,12 @@ const configSchema = {
|
|
|
4678
4822
|
"default": "",
|
|
4679
4823
|
"description": "Model passed to the Claude reviewer lane."
|
|
4680
4824
|
},
|
|
4825
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
4826
|
+
"owner": "claude",
|
|
4827
|
+
"type": "number",
|
|
4828
|
+
"default": -1,
|
|
4829
|
+
"description": "Prompt-token budget for the Claude reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4830
|
+
},
|
|
4681
4831
|
"claude_orchestration.enabled": {
|
|
4682
4832
|
"owner": "claude-orchestration",
|
|
4683
4833
|
"type": "boolean",
|
|
@@ -4718,12 +4868,30 @@ const configSchema = {
|
|
|
4718
4868
|
"deep"
|
|
4719
4869
|
]
|
|
4720
4870
|
},
|
|
4871
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": {
|
|
4872
|
+
"owner": "coderabbit",
|
|
4873
|
+
"type": "number",
|
|
4874
|
+
"default": -1,
|
|
4875
|
+
"description": "Prompt-token budget for the CodeRabbit reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4876
|
+
},
|
|
4721
4877
|
"review.models.codex": {
|
|
4722
4878
|
"owner": "codex",
|
|
4723
4879
|
"type": "string",
|
|
4724
4880
|
"default": "",
|
|
4725
4881
|
"description": "Model passed to the Codex reviewer lane."
|
|
4726
4882
|
},
|
|
4883
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
4884
|
+
"owner": "codex",
|
|
4885
|
+
"type": "number",
|
|
4886
|
+
"default": -1,
|
|
4887
|
+
"description": "Prompt-token budget for the Codex reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4888
|
+
},
|
|
4889
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
4890
|
+
"owner": "cursor",
|
|
4891
|
+
"type": "number",
|
|
4892
|
+
"default": -1,
|
|
4893
|
+
"description": "Prompt-token budget for the Cursor reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4894
|
+
},
|
|
4727
4895
|
"workflow.drift_threshold": {
|
|
4728
4896
|
"owner": "drift",
|
|
4729
4897
|
"type": "number",
|
|
@@ -4797,6 +4965,12 @@ const configSchema = {
|
|
|
4797
4965
|
"default": "",
|
|
4798
4966
|
"description": "Model passed to the Gemini reviewer lane."
|
|
4799
4967
|
},
|
|
4968
|
+
"review.max_prompt_tokens_per_reviewer.gemini": {
|
|
4969
|
+
"owner": "gemini",
|
|
4970
|
+
"type": "number",
|
|
4971
|
+
"default": -1,
|
|
4972
|
+
"description": "Prompt-token budget for the Gemini reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4973
|
+
},
|
|
4800
4974
|
"graphify.enabled": {
|
|
4801
4975
|
"owner": "graphify",
|
|
4802
4976
|
"type": "boolean",
|
|
@@ -4815,6 +4989,18 @@ const configSchema = {
|
|
|
4815
4989
|
"default": "",
|
|
4816
4990
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
4817
4991
|
},
|
|
4992
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
4993
|
+
"owner": "kimi-code",
|
|
4994
|
+
"type": "number",
|
|
4995
|
+
"default": -1,
|
|
4996
|
+
"description": "Prompt-token budget for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
4997
|
+
},
|
|
4998
|
+
"workflow.live_dom_uat": {
|
|
4999
|
+
"owner": "live-dom-uat",
|
|
5000
|
+
"type": "boolean",
|
|
5001
|
+
"default": false,
|
|
5002
|
+
"description": "Enable live-DOM verification. Default-off: browser MCP reach is opt-in per project. When on, the orchestrator's automated UI verification may additionally use mcp__chrome-devtools__* / mcp__claude-in-chrome__* when present, and a gsd-dom-verifier step runs after each execution wave. When off, neither surface reaches a browser and the pre-existing mcp__playwright__* path is unchanged."
|
|
5003
|
+
},
|
|
4818
5004
|
"review.models.llama_cpp": {
|
|
4819
5005
|
"owner": "llama-cpp",
|
|
4820
5006
|
"type": "string",
|
|
@@ -4946,6 +5132,12 @@ const configSchema = {
|
|
|
4946
5132
|
"default": "",
|
|
4947
5133
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
4948
5134
|
},
|
|
5135
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
5136
|
+
"owner": "opencode",
|
|
5137
|
+
"type": "number",
|
|
5138
|
+
"default": -1,
|
|
5139
|
+
"description": "Prompt-token budget for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
5140
|
+
},
|
|
4949
5141
|
"workflow.pattern_mapper": {
|
|
4950
5142
|
"owner": "pattern-mapper",
|
|
4951
5143
|
"type": "boolean",
|
|
@@ -4958,6 +5150,12 @@ const configSchema = {
|
|
|
4958
5150
|
"default": false,
|
|
4959
5151
|
"description": "Enable the developer profiling pipeline commands (scan-sessions, extract-messages, profile-sample, write-profile, etc.)."
|
|
4960
5152
|
},
|
|
5153
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
5154
|
+
"owner": "qwen",
|
|
5155
|
+
"type": "number",
|
|
5156
|
+
"default": -1,
|
|
5157
|
+
"description": "Prompt-token budget for the Qwen Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
5158
|
+
},
|
|
4961
5159
|
"refactor.trigger_enabled": {
|
|
4962
5160
|
"owner": "refactor-trigger",
|
|
4963
5161
|
"type": "boolean",
|
|
@@ -5049,9 +5247,9 @@ const runtimes = {
|
|
|
5049
5247
|
"antigravity": {
|
|
5050
5248
|
"id": "antigravity",
|
|
5051
5249
|
"role": "runtime",
|
|
5052
|
-
"version": "1.
|
|
5250
|
+
"version": "1.12.0",
|
|
5053
5251
|
"title": "Antigravity",
|
|
5054
|
-
"description": "Google Antigravity IDE — nested under ~/.gemini/antigravity
|
|
5252
|
+
"description": "Google Antigravity IDE — config/settings home nested under ~/.gemini/antigravity (probed across 1.x and 2.x layouts); global skills/agents install under ~/.gemini/config, the dir AGY scans for global discovery (#3738); Gemini hook event dialect; flat skill layout; tier-1 support.",
|
|
5055
5253
|
"tier": "core",
|
|
5056
5254
|
"requires": [],
|
|
5057
5255
|
"engines": {
|
|
@@ -5082,7 +5280,8 @@ const runtimes = {
|
|
|
5082
5280
|
"prefix": "gsd-",
|
|
5083
5281
|
"nesting": "flat",
|
|
5084
5282
|
"recursive": false,
|
|
5085
|
-
"converter": "convertClaudeCommandToAntigravitySkill"
|
|
5283
|
+
"converter": "convertClaudeCommandToAntigravitySkill",
|
|
5284
|
+
"home": ".gemini/config"
|
|
5086
5285
|
},
|
|
5087
5286
|
{
|
|
5088
5287
|
"kind": "agents",
|
|
@@ -5090,7 +5289,8 @@ const runtimes = {
|
|
|
5090
5289
|
"prefix": "gsd-",
|
|
5091
5290
|
"nesting": "flat",
|
|
5092
5291
|
"recursive": false,
|
|
5093
|
-
"converter": "convertClaudeAgentToAntigravityAgent"
|
|
5292
|
+
"converter": "convertClaudeAgentToAntigravityAgent",
|
|
5293
|
+
"home": ".gemini/config"
|
|
5094
5294
|
}
|
|
5095
5295
|
],
|
|
5096
5296
|
"local": [
|
|
@@ -5181,7 +5381,7 @@ const runtimes = {
|
|
|
5181
5381
|
"reviewsSection": "Antigravity",
|
|
5182
5382
|
"evidenceClass": "source-grounded",
|
|
5183
5383
|
"requiresBinaries": [],
|
|
5184
|
-
"promptBudgetKey":
|
|
5384
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.antigravity",
|
|
5185
5385
|
"modelConfigKey": "review.models.agy",
|
|
5186
5386
|
"handler": "antigravity"
|
|
5187
5387
|
},
|
|
@@ -5190,13 +5390,18 @@ const runtimes = {
|
|
|
5190
5390
|
"type": "string",
|
|
5191
5391
|
"default": "",
|
|
5192
5392
|
"description": "Model passed to the Antigravity reviewer lane. The key suffix is the lane binary/flag alias `agy`, not the slug `antigravity` — preserved verbatim so existing .planning/config.json files keep working."
|
|
5393
|
+
},
|
|
5394
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
5395
|
+
"type": "number",
|
|
5396
|
+
"default": -1,
|
|
5397
|
+
"description": "Prompt-token budget for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\". Keyed on the reviewer slug `antigravity`, not the `agy` binary alias used by review.models.agy."
|
|
5193
5398
|
}
|
|
5194
5399
|
}
|
|
5195
5400
|
},
|
|
5196
5401
|
"augment": {
|
|
5197
5402
|
"id": "augment",
|
|
5198
5403
|
"role": "runtime",
|
|
5199
|
-
"version": "1.
|
|
5404
|
+
"version": "1.12.0",
|
|
5200
5405
|
"title": "Augment Code",
|
|
5201
5406
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
5202
5407
|
"tier": "core",
|
|
@@ -5309,7 +5514,7 @@ const runtimes = {
|
|
|
5309
5514
|
"claude": {
|
|
5310
5515
|
"id": "claude",
|
|
5311
5516
|
"role": "runtime",
|
|
5312
|
-
"version": "1.
|
|
5517
|
+
"version": "1.12.0",
|
|
5313
5518
|
"title": "Claude Code",
|
|
5314
5519
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
5315
5520
|
"tier": "core",
|
|
@@ -5456,7 +5661,7 @@ const runtimes = {
|
|
|
5456
5661
|
"reviewsSection": "Claude",
|
|
5457
5662
|
"evidenceClass": "source-grounded",
|
|
5458
5663
|
"requiresBinaries": [],
|
|
5459
|
-
"promptBudgetKey":
|
|
5664
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.claude",
|
|
5460
5665
|
"modelConfigKey": "review.models.claude",
|
|
5461
5666
|
"handler": null
|
|
5462
5667
|
},
|
|
@@ -5465,13 +5670,18 @@ const runtimes = {
|
|
|
5465
5670
|
"type": "string",
|
|
5466
5671
|
"default": "",
|
|
5467
5672
|
"description": "Model passed to the Claude reviewer lane."
|
|
5673
|
+
},
|
|
5674
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
5675
|
+
"type": "number",
|
|
5676
|
+
"default": -1,
|
|
5677
|
+
"description": "Prompt-token budget for the Claude reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
5468
5678
|
}
|
|
5469
5679
|
}
|
|
5470
5680
|
},
|
|
5471
5681
|
"cline": {
|
|
5472
5682
|
"id": "cline",
|
|
5473
5683
|
"role": "runtime",
|
|
5474
|
-
"version": "1.
|
|
5684
|
+
"version": "1.12.0",
|
|
5475
5685
|
"title": "Cline",
|
|
5476
5686
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
5477
5687
|
"tier": "core",
|
|
@@ -5563,7 +5773,7 @@ const runtimes = {
|
|
|
5563
5773
|
"codebuddy": {
|
|
5564
5774
|
"id": "codebuddy",
|
|
5565
5775
|
"role": "runtime",
|
|
5566
|
-
"version": "1.
|
|
5776
|
+
"version": "1.12.0",
|
|
5567
5777
|
"title": "CodeBuddy",
|
|
5568
5778
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
5569
5779
|
"tier": "core",
|
|
@@ -5680,7 +5890,7 @@ const runtimes = {
|
|
|
5680
5890
|
"codex": {
|
|
5681
5891
|
"id": "codex",
|
|
5682
5892
|
"role": "runtime",
|
|
5683
|
-
"version": "1.
|
|
5893
|
+
"version": "1.12.0",
|
|
5684
5894
|
"title": "OpenAI Codex CLI",
|
|
5685
5895
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
5686
5896
|
"tier": "core",
|
|
@@ -5779,7 +5989,8 @@ const runtimes = {
|
|
|
5779
5989
|
"exec"
|
|
5780
5990
|
],
|
|
5781
5991
|
"cwdFlag": "--cd",
|
|
5782
|
-
"promptFlag": null
|
|
5992
|
+
"promptFlag": null,
|
|
5993
|
+
"modelFlag": "--model"
|
|
5783
5994
|
},
|
|
5784
5995
|
"hostBehaviors": {
|
|
5785
5996
|
"reapplyCommand": "$gsd-update --reapply",
|
|
@@ -5821,7 +6032,7 @@ const runtimes = {
|
|
|
5821
6032
|
"reviewsSection": "Codex",
|
|
5822
6033
|
"evidenceClass": "source-grounded",
|
|
5823
6034
|
"requiresBinaries": [],
|
|
5824
|
-
"promptBudgetKey":
|
|
6035
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.codex",
|
|
5825
6036
|
"modelConfigKey": "review.models.codex",
|
|
5826
6037
|
"handler": null
|
|
5827
6038
|
},
|
|
@@ -5830,13 +6041,18 @@ const runtimes = {
|
|
|
5830
6041
|
"type": "string",
|
|
5831
6042
|
"default": "",
|
|
5832
6043
|
"description": "Model passed to the Codex reviewer lane."
|
|
6044
|
+
},
|
|
6045
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
6046
|
+
"type": "number",
|
|
6047
|
+
"default": -1,
|
|
6048
|
+
"description": "Prompt-token budget for the Codex reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
5833
6049
|
}
|
|
5834
6050
|
}
|
|
5835
6051
|
},
|
|
5836
6052
|
"copilot": {
|
|
5837
6053
|
"id": "copilot",
|
|
5838
6054
|
"role": "runtime",
|
|
5839
|
-
"version": "1.
|
|
6055
|
+
"version": "1.12.0",
|
|
5840
6056
|
"title": "GitHub Copilot",
|
|
5841
6057
|
"description": "GitHub Copilot (VS Code) — markdown config format; copilot-inline hook surface; no hook events emitted; flat skill nesting (unconfirmed recursive loader); tier-2 support.",
|
|
5842
6058
|
"tier": "core",
|
|
@@ -5935,7 +6151,7 @@ const runtimes = {
|
|
|
5935
6151
|
"cursor": {
|
|
5936
6152
|
"id": "cursor",
|
|
5937
6153
|
"role": "runtime",
|
|
5938
|
-
"version": "1.
|
|
6154
|
+
"version": "1.12.0",
|
|
5939
6155
|
"title": "Cursor",
|
|
5940
6156
|
"description": "Cursor IDE — skills-only workflow surface; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
5941
6157
|
"tier": "core",
|
|
@@ -6079,15 +6295,22 @@ const runtimes = {
|
|
|
6079
6295
|
"reviewsSection": "Cursor",
|
|
6080
6296
|
"evidenceClass": "source-grounded",
|
|
6081
6297
|
"requiresBinaries": [],
|
|
6082
|
-
"promptBudgetKey":
|
|
6298
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
|
6083
6299
|
"modelConfigKey": null,
|
|
6084
6300
|
"handler": null
|
|
6301
|
+
},
|
|
6302
|
+
"config": {
|
|
6303
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
6304
|
+
"type": "number",
|
|
6305
|
+
"default": -1,
|
|
6306
|
+
"description": "Prompt-token budget for the Cursor reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
6307
|
+
}
|
|
6085
6308
|
}
|
|
6086
6309
|
},
|
|
6087
6310
|
"hermes": {
|
|
6088
6311
|
"id": "hermes",
|
|
6089
6312
|
"role": "runtime",
|
|
6090
|
-
"version": "1.
|
|
6313
|
+
"version": "1.12.0",
|
|
6091
6314
|
"title": "Hermes Agent",
|
|
6092
6315
|
"description": "Hermes Agent (NousResearch) — skills nest under skills/gsd/ category bucket; nested skill layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
6093
6316
|
"tier": "core",
|
|
@@ -6198,7 +6421,7 @@ const runtimes = {
|
|
|
6198
6421
|
"kilo": {
|
|
6199
6422
|
"id": "kilo",
|
|
6200
6423
|
"role": "runtime",
|
|
6201
|
-
"version": "1.
|
|
6424
|
+
"version": "1.12.0",
|
|
6202
6425
|
"title": "Kilo Code",
|
|
6203
6426
|
"description": "Kilo Code — XDG-based config dir; global skills at ~/.kilo/skills (separate from XDG config); flat command/ + skills artifact layout; no lifecycle hook registration; tier-2 support.",
|
|
6204
6427
|
"tier": "core",
|
|
@@ -6327,7 +6550,7 @@ const runtimes = {
|
|
|
6327
6550
|
"kimi": {
|
|
6328
6551
|
"id": "kimi",
|
|
6329
6552
|
"role": "runtime",
|
|
6330
|
-
"version": "1.
|
|
6553
|
+
"version": "1.12.0",
|
|
6331
6554
|
"title": "Kimi CLI",
|
|
6332
6555
|
"description": "Kimi CLI (Moonshot AI) — generic agents root at ~/.config/agents; skills + kimi-agents artifact layout; native config.toml [[hooks]] bus at ~/.kimi/config.toml; background dispatch; tier-2 support.",
|
|
6333
6556
|
"tier": "core",
|
|
@@ -6429,7 +6652,7 @@ const runtimes = {
|
|
|
6429
6652
|
"kimi-code": {
|
|
6430
6653
|
"id": "kimi-code",
|
|
6431
6654
|
"role": "runtime",
|
|
6432
|
-
"version": "1.
|
|
6655
|
+
"version": "1.12.0",
|
|
6433
6656
|
"title": "Kimi Code CLI",
|
|
6434
6657
|
"description": "Kimi Code CLI (Moonshot AI, Node) — Agent Skills auto-discovered at ~/.kimi-code/skills; global AGENTS.md at ~/.kimi-code/AGENTS.md; native config.toml + [[hooks]] bus; three built-in subagents (coder/explore/plan), NO custom named subagents; background dispatch; tier-2 support. Distinct from Python kimi-cli (the 'kimi' capability) per ADR-1239 EoS — Kimi Code cannot dispatch named subagents so the kimi-agents YAML layout does NOT apply; persona injection rides the existing ${AGENT_SKILLS_*} workflow fallback. Install-layout, agent-install-check, and install-time decision (kimi vs kimi-code) land in follow-up PRs; this descriptor is the EoS foundation.",
|
|
6435
6658
|
"tier": "core",
|
|
@@ -6567,7 +6790,7 @@ const runtimes = {
|
|
|
6567
6790
|
"reviewsSection": "Kimi Code",
|
|
6568
6791
|
"evidenceClass": "source-grounded",
|
|
6569
6792
|
"requiresBinaries": [],
|
|
6570
|
-
"promptBudgetKey":
|
|
6793
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.kimi-code",
|
|
6571
6794
|
"modelConfigKey": "review.models.kimi-code",
|
|
6572
6795
|
"handler": null
|
|
6573
6796
|
},
|
|
@@ -6576,13 +6799,18 @@ const runtimes = {
|
|
|
6576
6799
|
"type": "string",
|
|
6577
6800
|
"default": "",
|
|
6578
6801
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
6802
|
+
},
|
|
6803
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
6804
|
+
"type": "number",
|
|
6805
|
+
"default": -1,
|
|
6806
|
+
"description": "Prompt-token budget for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
6579
6807
|
}
|
|
6580
6808
|
}
|
|
6581
6809
|
},
|
|
6582
6810
|
"opencode": {
|
|
6583
6811
|
"id": "opencode",
|
|
6584
6812
|
"role": "runtime",
|
|
6585
|
-
"version": "1.
|
|
6813
|
+
"version": "1.12.0",
|
|
6586
6814
|
"title": "OpenCode",
|
|
6587
6815
|
"description": "OpenCode — XDG-based config dir; flat commands/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
6588
6816
|
"tier": "core",
|
|
@@ -6743,7 +6971,7 @@ const runtimes = {
|
|
|
6743
6971
|
"reviewsSection": "OpenCode",
|
|
6744
6972
|
"evidenceClass": "source-grounded",
|
|
6745
6973
|
"requiresBinaries": [],
|
|
6746
|
-
"promptBudgetKey":
|
|
6974
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.opencode",
|
|
6747
6975
|
"modelConfigKey": "review.models.opencode",
|
|
6748
6976
|
"handler": "opencode"
|
|
6749
6977
|
},
|
|
@@ -6752,13 +6980,18 @@ const runtimes = {
|
|
|
6752
6980
|
"type": "string",
|
|
6753
6981
|
"default": "",
|
|
6754
6982
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
6983
|
+
},
|
|
6984
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
6985
|
+
"type": "number",
|
|
6986
|
+
"default": -1,
|
|
6987
|
+
"description": "Prompt-token budget for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
6755
6988
|
}
|
|
6756
6989
|
}
|
|
6757
6990
|
},
|
|
6758
6991
|
"pi": {
|
|
6759
6992
|
"id": "pi",
|
|
6760
6993
|
"role": "runtime",
|
|
6761
|
-
"version": "1.
|
|
6994
|
+
"version": "1.12.0",
|
|
6762
6995
|
"title": "pi",
|
|
6763
6996
|
"description": "pi (pi.dev) — bun-runtime programmatic-CLI; TS ExtensionAPI (registerCommand/registerTool/registerProvider/pi.on); single native-extension file at ~/.pi/agent/extensions/gsd.js (.js, not .cjs — pi's extension auto-discovery accepts only .ts/.js, #2470); no shared-settings hook surface; tier-2 support.",
|
|
6764
6997
|
"tier": "core",
|
|
@@ -6827,7 +7060,7 @@ const runtimes = {
|
|
|
6827
7060
|
"qwen": {
|
|
6828
7061
|
"id": "qwen",
|
|
6829
7062
|
"role": "runtime",
|
|
6830
|
-
"version": "1.
|
|
7063
|
+
"version": "1.12.0",
|
|
6831
7064
|
"title": "Qwen Code",
|
|
6832
7065
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
6833
7066
|
"tier": "core",
|
|
@@ -6958,15 +7191,22 @@ const runtimes = {
|
|
|
6958
7191
|
"reviewsSection": "Qwen",
|
|
6959
7192
|
"evidenceClass": "source-grounded",
|
|
6960
7193
|
"requiresBinaries": [],
|
|
6961
|
-
"promptBudgetKey":
|
|
7194
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.qwen",
|
|
6962
7195
|
"modelConfigKey": null,
|
|
6963
7196
|
"handler": null
|
|
7197
|
+
},
|
|
7198
|
+
"config": {
|
|
7199
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
7200
|
+
"type": "number",
|
|
7201
|
+
"default": -1,
|
|
7202
|
+
"description": "Prompt-token budget for the Qwen Code reviewer lane. Unset is -1, a sentinel: 0 is a legitimate value meaning \"do not trim this lane\", so it cannot double as \"not configured\"."
|
|
7203
|
+
}
|
|
6964
7204
|
}
|
|
6965
7205
|
},
|
|
6966
7206
|
"trae": {
|
|
6967
7207
|
"id": "trae",
|
|
6968
7208
|
"role": "runtime",
|
|
6969
|
-
"version": "1.
|
|
7209
|
+
"version": "1.12.0",
|
|
6970
7210
|
"title": "Trae IDE",
|
|
6971
7211
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
6972
7212
|
"tier": "core",
|
|
@@ -7063,7 +7303,7 @@ const runtimes = {
|
|
|
7063
7303
|
"vscode": {
|
|
7064
7304
|
"id": "vscode",
|
|
7065
7305
|
"role": "runtime",
|
|
7066
|
-
"version": "1.
|
|
7306
|
+
"version": "1.12.0",
|
|
7067
7307
|
"title": "VS Code",
|
|
7068
7308
|
"description": "VS Code — Marketplace/VSIX extension; no file-projected config directory; IDE-profile reference host (active vscode.lm model, engine-owned hook bus, sandboxed globalState/workspaceState stateIO).",
|
|
7069
7309
|
"tier": "core",
|
|
@@ -7120,7 +7360,7 @@ const runtimes = {
|
|
|
7120
7360
|
"windsurf": {
|
|
7121
7361
|
"id": "windsurf",
|
|
7122
7362
|
"role": "runtime",
|
|
7123
|
-
"version": "1.
|
|
7363
|
+
"version": "1.12.0",
|
|
7124
7364
|
"title": "Windsurf",
|
|
7125
7365
|
"description": "Windsurf (Codeium) — workspace workflow artifact layout for slash commands; Cascade native hooks.json blocking hook bus (pre_write_code, pre_run_command); tier-2 support.",
|
|
7126
7366
|
"tier": "core",
|
|
@@ -7211,7 +7451,7 @@ const runtimes = {
|
|
|
7211
7451
|
"zcode": {
|
|
7212
7452
|
"id": "zcode",
|
|
7213
7453
|
"role": "runtime",
|
|
7214
|
-
"version": "1.
|
|
7454
|
+
"version": "1.12.0",
|
|
7215
7455
|
"title": "ZCode",
|
|
7216
7456
|
"description": "ZCode (Z.ai) — desktop Agentic Development Environment for GLM-5.2; Claude-shaped nested skills at ~/.zcode/skills/<name>/SKILL.md, slash commands, named subagents, native MCP; declarative plugin surface; profile-marker install; tier-2 community support.",
|
|
7217
7457
|
"tier": "core",
|
|
@@ -7500,6 +7740,7 @@ const _requiresGraph = {
|
|
|
7500
7740
|
"kilo": [],
|
|
7501
7741
|
"kimi": [],
|
|
7502
7742
|
"kimi-code": [],
|
|
7743
|
+
"live-dom-uat": [],
|
|
7503
7744
|
"llama-cpp": [],
|
|
7504
7745
|
"lm-studio": [],
|
|
7505
7746
|
"mempalace": [],
|