@opengsd/gsd-core 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- 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 +78 -42
- 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 +91 -112
- package/agents/gsd-planner.md +20 -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 +82 -7
- package/agents/gsd-ui-researcher.md +70 -3
- package/agents/gsd-verifier.md +24 -2
- package/bin/install.js +847 -200
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/quick.md +8 -4
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +761 -100
- 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-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +785 -144
- package/gsd-core/bin/lib/capability-state.cjs +25 -4
- package/gsd-core/bin/lib/capability-validator.cjs +321 -18
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +229 -6
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- 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-aliases.cjs +16 -0
- 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 +877 -54
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +121 -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 +118 -14
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +23 -2
- 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/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +975 -326
- package/gsd-core/bin/lib/gap-checker.cjs +41 -8
- package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- 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 +96 -11
- package/gsd-core/bin/lib/init-command-router.cjs +132 -21
- package/gsd-core/bin/lib/init.cjs +252 -56
- package/gsd-core/bin/lib/install-engine.cjs +252 -15
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
- package/gsd-core/bin/lib/install-profiles.cjs +100 -18
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -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 +195 -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/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +175 -4
- package/gsd-core/bin/lib/milestone.cjs +112 -7
- 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-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +321 -13
- 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 +1175 -115
- package/gsd-core/bin/lib/plan-document.cjs +273 -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 +165 -34
- package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
- 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/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- 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 +62 -14
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
- package/gsd-core/bin/lib/roadmap.cjs +248 -64
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
- 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 +75 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -31
- 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 +216 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
- package/gsd-core/bin/lib/state-transition.cjs +850 -145
- package/gsd-core/bin/lib/state.cjs +1629 -287
- package/gsd-core/bin/lib/surface.cjs +33 -10
- 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/tdd-red-evidence.cjs +133 -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 +2542 -387
- 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/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- 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-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +287 -13
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +441 -56
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- 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 +185 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -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/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +6 -5
- 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 +17 -5
- package/gsd-core/references/execute-mvp-tdd.md +18 -18
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- 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/mvp-concepts.md +2 -2
- 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/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- 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-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +76 -3
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +39 -9
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +15 -12
- 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/verifier-evidence-gate.md +160 -0
- 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 +7 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +3 -1
- package/gsd-core/workflows/add-phase.md +5 -3
- package/gsd-core/workflows/add-tests.md +4 -9
- package/gsd-core/workflows/add-todo.md +2 -2
- package/gsd-core/workflows/ai-integration-phase.md +5 -10
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +14 -3
- package/gsd-core/workflows/audit-milestone.md +11 -9
- package/gsd-core/workflows/audit-uat.md +19 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +12 -26
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +3 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
- package/gsd-core/workflows/code-review-fix.md +3 -1
- package/gsd-core/workflows/code-review.md +192 -69
- package/gsd-core/workflows/complete-milestone.md +28 -14
- package/gsd-core/workflows/debug.md +6 -4
- package/gsd-core/workflows/diagnose-issues.md +17 -7
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +46 -19
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +3 -1
- package/gsd-core/workflows/eval-review.md +5 -10
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -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 +29 -5
- 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 +4 -2
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +68 -66
- package/gsd-core/workflows/execute-plan.md +25 -20
- package/gsd-core/workflows/explore.md +3 -1
- package/gsd-core/workflows/extract-learnings.md +3 -1
- package/gsd-core/workflows/fast.md +8 -2
- package/gsd-core/workflows/forensics.md +3 -1
- package/gsd-core/workflows/graduation.md +6 -6
- package/gsd-core/workflows/health.md +4 -7
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +17 -14
- package/gsd-core/workflows/inbox.md +5 -6
- package/gsd-core/workflows/ingest-docs.md +45 -12
- package/gsd-core/workflows/insert-phase.md +7 -5
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +7 -3
- package/gsd-core/workflows/list-workspaces.md +3 -1
- package/gsd-core/workflows/manager.md +15 -26
- package/gsd-core/workflows/map-codebase.md +3 -1
- package/gsd-core/workflows/milestone-summary.md +3 -1
- package/gsd-core/workflows/mvp-phase.md +3 -3
- package/gsd-core/workflows/new-milestone.md +10 -22
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +17 -29
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +4 -2
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +20 -5
- 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 +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
- package/gsd-core/workflows/plan-phase.md +251 -54
- package/gsd-core/workflows/plan-review-convergence.md +148 -19
- package/gsd-core/workflows/plant-seed.md +3 -3
- package/gsd-core/workflows/pr-branch.md +195 -51
- package/gsd-core/workflows/profile-user.md +17 -15
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +52 -15
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +33 -32
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +6 -4
- package/gsd-core/workflows/remove-workspace.md +3 -3
- package/gsd-core/workflows/resume-project.md +14 -14
- package/gsd-core/workflows/review.md +404 -21
- package/gsd-core/workflows/scan.md +3 -1
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +9 -9
- package/gsd-core/workflows/settings-integrations.md +66 -32
- package/gsd-core/workflows/settings.md +4 -6
- package/gsd-core/workflows/ship.md +22 -16
- package/gsd-core/workflows/sketch-wrap-up.md +13 -17
- package/gsd-core/workflows/sketch.md +13 -19
- package/gsd-core/workflows/smart-entry.md +4 -6
- package/gsd-core/workflows/spec-phase.md +31 -4
- package/gsd-core/workflows/spike-wrap-up.md +9 -11
- package/gsd-core/workflows/spike.md +21 -32
- package/gsd-core/workflows/stats.md +4 -2
- package/gsd-core/workflows/sync-skills.md +13 -5
- package/gsd-core/workflows/thread.md +13 -7
- package/gsd-core/workflows/transition.md +7 -5
- package/gsd-core/workflows/ui-phase.md +36 -21
- package/gsd-core/workflows/ui-review.md +7 -11
- package/gsd-core/workflows/ultraplan-phase.md +7 -13
- package/gsd-core/workflows/undo.md +9 -17
- package/gsd-core/workflows/update.md +47 -48
- package/gsd-core/workflows/validate-phase.md +3 -3
- 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 +106 -21
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +302 -22
- 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 +77 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +46 -12
- package/hooks/dist/gsd-read-guard.js +18 -7
- package/hooks/dist/gsd-read-injection-scanner.js +22 -13
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +222 -29
- package/hooks/dist/gsd-validate-commit.sh +523 -12
- 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 +36 -17
- 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-cmd.js +210 -1
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +4 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +302 -22
- 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 +77 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +46 -12
- package/hooks/gsd-read-guard.js +18 -7
- package/hooks/gsd-read-injection-scanner.js +22 -13
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +222 -29
- package/hooks/gsd-validate-commit.sh +523 -12
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +36 -17
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/hooks.json +6 -0
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +4 -0
- package/package.json +14 -9
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +12 -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 +52 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +406 -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 +189 -4
- 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/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- 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 +198 -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 +45 -14
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-response-language-coverage.cjs +524 -0
- 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 +124 -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/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +83 -14
- package/scripts/require-issue-link-policy.cjs +16 -1
- 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-execute-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- 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.13.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.13.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": [
|
|
@@ -181,7 +183,8 @@ const capabilities = {
|
|
|
181
183
|
"background": true,
|
|
182
184
|
"subagentToolkit": "full",
|
|
183
185
|
"backgroundDispatch": "undocumented",
|
|
184
|
-
"isolation": "undocumented"
|
|
186
|
+
"isolation": "undocumented",
|
|
187
|
+
"maxConcurrency": "undocumented"
|
|
185
188
|
},
|
|
186
189
|
"modelMode": "passive",
|
|
187
190
|
"hookBus": "host",
|
|
@@ -212,7 +215,7 @@ const capabilities = {
|
|
|
212
215
|
"binary": "agy",
|
|
213
216
|
"args": [
|
|
214
217
|
"--print-timeout",
|
|
215
|
-
"
|
|
218
|
+
"{{nativeTimeout}}",
|
|
216
219
|
"{{model}}",
|
|
217
220
|
"-p",
|
|
218
221
|
"{{prompt}}"
|
|
@@ -223,12 +226,15 @@ const capabilities = {
|
|
|
223
226
|
"effortChannel": "none"
|
|
224
227
|
},
|
|
225
228
|
"timeoutFloorMs": 600000,
|
|
229
|
+
"timeoutConfigKey": "review.timeouts.antigravity",
|
|
226
230
|
"emptyOutput": "handler-owned",
|
|
227
231
|
"reviewsSection": "Antigravity",
|
|
228
232
|
"evidenceClass": "source-grounded",
|
|
229
233
|
"requiresBinaries": [],
|
|
230
|
-
"promptBudgetKey":
|
|
234
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.antigravity",
|
|
231
235
|
"modelConfigKey": "review.models.agy",
|
|
236
|
+
"effortConfigKey": null,
|
|
237
|
+
"defaultEffort": null,
|
|
232
238
|
"handler": "antigravity"
|
|
233
239
|
},
|
|
234
240
|
"config": {
|
|
@@ -236,13 +242,23 @@ const capabilities = {
|
|
|
236
242
|
"type": "string",
|
|
237
243
|
"default": "",
|
|
238
244
|
"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."
|
|
245
|
+
},
|
|
246
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
247
|
+
"type": "number",
|
|
248
|
+
"default": -1,
|
|
249
|
+
"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."
|
|
250
|
+
},
|
|
251
|
+
"review.timeouts.antigravity": {
|
|
252
|
+
"type": "number",
|
|
253
|
+
"default": -1,
|
|
254
|
+
"description": "Outer wall-clock timeout override (seconds) for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
239
255
|
}
|
|
240
256
|
}
|
|
241
257
|
},
|
|
242
258
|
"assumption-delta": {
|
|
243
259
|
"id": "assumption-delta",
|
|
244
260
|
"role": "feature",
|
|
245
|
-
"version": "1.
|
|
261
|
+
"version": "1.13.0",
|
|
246
262
|
"title": "Assumption-delta architecture checkpoint",
|
|
247
263
|
"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
264
|
"tier": "full",
|
|
@@ -273,7 +289,7 @@ const capabilities = {
|
|
|
273
289
|
"into": "planner",
|
|
274
290
|
"fragment": {
|
|
275
291
|
"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 ||
|
|
292
|
+
"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
293
|
},
|
|
278
294
|
"produces": [],
|
|
279
295
|
"consumes": [
|
|
@@ -288,7 +304,7 @@ const capabilities = {
|
|
|
288
304
|
"audit": {
|
|
289
305
|
"id": "audit",
|
|
290
306
|
"role": "feature",
|
|
291
|
-
"version": "1.
|
|
307
|
+
"version": "1.13.0",
|
|
292
308
|
"title": "Audit",
|
|
293
309
|
"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
310
|
"tier": "full",
|
|
@@ -325,7 +341,7 @@ const capabilities = {
|
|
|
325
341
|
"augment": {
|
|
326
342
|
"id": "augment",
|
|
327
343
|
"role": "runtime",
|
|
328
|
-
"version": "1.
|
|
344
|
+
"version": "1.13.0",
|
|
329
345
|
"title": "Augment Code",
|
|
330
346
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
331
347
|
"tier": "core",
|
|
@@ -424,7 +440,8 @@ const capabilities = {
|
|
|
424
440
|
"background": true,
|
|
425
441
|
"subagentToolkit": "full",
|
|
426
442
|
"backgroundDispatch": "undocumented",
|
|
427
|
-
"isolation": "undocumented"
|
|
443
|
+
"isolation": "undocumented",
|
|
444
|
+
"maxConcurrency": "undocumented"
|
|
428
445
|
},
|
|
429
446
|
"modelMode": "passive",
|
|
430
447
|
"hookBus": "host",
|
|
@@ -438,7 +455,7 @@ const capabilities = {
|
|
|
438
455
|
"broken-windows": {
|
|
439
456
|
"id": "broken-windows",
|
|
440
457
|
"role": "feature",
|
|
441
|
-
"version": "1.
|
|
458
|
+
"version": "1.13.0",
|
|
442
459
|
"title": "Broken-windows ledger",
|
|
443
460
|
"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
461
|
"tier": "full",
|
|
@@ -484,7 +501,7 @@ const capabilities = {
|
|
|
484
501
|
"claude": {
|
|
485
502
|
"id": "claude",
|
|
486
503
|
"role": "runtime",
|
|
487
|
-
"version": "1.
|
|
504
|
+
"version": "1.13.0",
|
|
488
505
|
"title": "Claude Code",
|
|
489
506
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
490
507
|
"tier": "core",
|
|
@@ -568,7 +585,8 @@ const capabilities = {
|
|
|
568
585
|
"background": true,
|
|
569
586
|
"subagentToolkit": "full",
|
|
570
587
|
"backgroundDispatch": false,
|
|
571
|
-
"isolation": "harness-worktree"
|
|
588
|
+
"isolation": "harness-worktree",
|
|
589
|
+
"maxConcurrency": 20
|
|
572
590
|
},
|
|
573
591
|
"modelMode": "passive",
|
|
574
592
|
"hookBus": "host",
|
|
@@ -627,12 +645,15 @@ const capabilities = {
|
|
|
627
645
|
}
|
|
628
646
|
},
|
|
629
647
|
"timeoutFloorMs": 1200000,
|
|
648
|
+
"timeoutConfigKey": "review.timeouts.claude",
|
|
630
649
|
"emptyOutput": "stub-with-stderr",
|
|
631
650
|
"reviewsSection": "Claude",
|
|
632
651
|
"evidenceClass": "source-grounded",
|
|
633
652
|
"requiresBinaries": [],
|
|
634
|
-
"promptBudgetKey":
|
|
653
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.claude",
|
|
635
654
|
"modelConfigKey": "review.models.claude",
|
|
655
|
+
"effortConfigKey": "review.effort.claude",
|
|
656
|
+
"defaultEffort": "high",
|
|
636
657
|
"handler": null
|
|
637
658
|
},
|
|
638
659
|
"config": {
|
|
@@ -640,13 +661,28 @@ const capabilities = {
|
|
|
640
661
|
"type": "string",
|
|
641
662
|
"default": "",
|
|
642
663
|
"description": "Model passed to the Claude reviewer lane."
|
|
664
|
+
},
|
|
665
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
666
|
+
"type": "number",
|
|
667
|
+
"default": -1,
|
|
668
|
+
"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\"."
|
|
669
|
+
},
|
|
670
|
+
"review.timeouts.claude": {
|
|
671
|
+
"type": "number",
|
|
672
|
+
"default": -1,
|
|
673
|
+
"description": "Outer wall-clock timeout override (seconds) for the Claude reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
674
|
+
},
|
|
675
|
+
"review.effort.claude": {
|
|
676
|
+
"type": "string",
|
|
677
|
+
"default": "",
|
|
678
|
+
"description": "Reasoning effort for the Claude reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
643
679
|
}
|
|
644
680
|
}
|
|
645
681
|
},
|
|
646
682
|
"claude-orchestration": {
|
|
647
683
|
"id": "claude-orchestration",
|
|
648
684
|
"role": "feature",
|
|
649
|
-
"version": "1.
|
|
685
|
+
"version": "1.13.0",
|
|
650
686
|
"title": "Claude orchestration (Workflow backend)",
|
|
651
687
|
"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
688
|
"tier": "full",
|
|
@@ -705,7 +741,7 @@ const capabilities = {
|
|
|
705
741
|
"into": "executor",
|
|
706
742
|
"fragment": {
|
|
707
743
|
"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"
|
|
744
|
+
"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
745
|
},
|
|
710
746
|
"produces": [],
|
|
711
747
|
"consumes": [
|
|
@@ -734,7 +770,7 @@ const capabilities = {
|
|
|
734
770
|
"cline": {
|
|
735
771
|
"id": "cline",
|
|
736
772
|
"role": "runtime",
|
|
737
|
-
"version": "1.
|
|
773
|
+
"version": "1.13.0",
|
|
738
774
|
"title": "Cline",
|
|
739
775
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
740
776
|
"tier": "core",
|
|
@@ -804,7 +840,8 @@ const capabilities = {
|
|
|
804
840
|
"background": true,
|
|
805
841
|
"subagentToolkit": "read-only",
|
|
806
842
|
"backgroundDispatch": false,
|
|
807
|
-
"isolation": "undocumented"
|
|
843
|
+
"isolation": "undocumented",
|
|
844
|
+
"maxConcurrency": "undocumented"
|
|
808
845
|
},
|
|
809
846
|
"modelMode": "active",
|
|
810
847
|
"hookBus": "host",
|
|
@@ -826,7 +863,7 @@ const capabilities = {
|
|
|
826
863
|
"code-review": {
|
|
827
864
|
"id": "code-review",
|
|
828
865
|
"role": "feature",
|
|
829
|
-
"version": "1.
|
|
866
|
+
"version": "1.13.0",
|
|
830
867
|
"title": "Code review",
|
|
831
868
|
"description": "Source-file code review and review-fix workflow support for completed execution work.",
|
|
832
869
|
"tier": "full",
|
|
@@ -863,6 +900,15 @@ const capabilities = {
|
|
|
863
900
|
],
|
|
864
901
|
"default": "standard",
|
|
865
902
|
"description": "Default depth for code review when no --depth override is supplied."
|
|
903
|
+
},
|
|
904
|
+
"workflow.code_review_point": {
|
|
905
|
+
"type": "enum",
|
|
906
|
+
"values": [
|
|
907
|
+
"execute:post",
|
|
908
|
+
"execute:wave:post"
|
|
909
|
+
],
|
|
910
|
+
"default": "execute:post",
|
|
911
|
+
"description": "Loop point at which the code-review step registers — execute:post reviews once per phase (default); execute:wave:post reviews once per completed wave, scoped to that wave's diff."
|
|
866
912
|
}
|
|
867
913
|
},
|
|
868
914
|
"steps": [
|
|
@@ -878,6 +924,20 @@ const capabilities = {
|
|
|
878
924
|
"SUMMARY.md"
|
|
879
925
|
],
|
|
880
926
|
"when": "workflow.code_review",
|
|
927
|
+
"pointFrom": "workflow.code_review_point",
|
|
928
|
+
"onError": "skip"
|
|
929
|
+
},
|
|
930
|
+
{
|
|
931
|
+
"point": "execute:wave:post",
|
|
932
|
+
"ref": {
|
|
933
|
+
"skill": "code-review"
|
|
934
|
+
},
|
|
935
|
+
"produces": [
|
|
936
|
+
"REVIEW.md"
|
|
937
|
+
],
|
|
938
|
+
"consumes": [],
|
|
939
|
+
"when": "workflow.code_review",
|
|
940
|
+
"pointFrom": "workflow.code_review_point",
|
|
881
941
|
"onError": "skip"
|
|
882
942
|
}
|
|
883
943
|
],
|
|
@@ -887,7 +947,7 @@ const capabilities = {
|
|
|
887
947
|
"codebuddy": {
|
|
888
948
|
"id": "codebuddy",
|
|
889
949
|
"role": "runtime",
|
|
890
|
-
"version": "1.
|
|
950
|
+
"version": "1.13.0",
|
|
891
951
|
"title": "CodeBuddy",
|
|
892
952
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
893
953
|
"tier": "core",
|
|
@@ -987,7 +1047,8 @@ const capabilities = {
|
|
|
987
1047
|
"background": true,
|
|
988
1048
|
"subagentToolkit": "full",
|
|
989
1049
|
"backgroundDispatch": false,
|
|
990
|
-
"isolation": "undocumented"
|
|
1050
|
+
"isolation": "undocumented",
|
|
1051
|
+
"maxConcurrency": "undocumented"
|
|
991
1052
|
},
|
|
992
1053
|
"modelMode": "passive",
|
|
993
1054
|
"hookBus": "host",
|
|
@@ -1004,7 +1065,7 @@ const capabilities = {
|
|
|
1004
1065
|
"coderabbit": {
|
|
1005
1066
|
"id": "coderabbit",
|
|
1006
1067
|
"role": "reviewer",
|
|
1007
|
-
"version": "1.
|
|
1068
|
+
"version": "1.13.0",
|
|
1008
1069
|
"title": "CodeRabbit",
|
|
1009
1070
|
"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
1071
|
"tier": "full",
|
|
@@ -1034,19 +1095,29 @@ const capabilities = {
|
|
|
1034
1095
|
"effortChannel": "none"
|
|
1035
1096
|
},
|
|
1036
1097
|
"timeoutFloorMs": 360000,
|
|
1098
|
+
"timeoutConfigKey": null,
|
|
1037
1099
|
"emptyOutput": "stub-with-stderr",
|
|
1038
1100
|
"reviewsSection": "CodeRabbit",
|
|
1039
1101
|
"evidenceClass": "diff-only",
|
|
1040
1102
|
"requiresBinaries": [],
|
|
1041
|
-
"promptBudgetKey":
|
|
1103
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.coderabbit",
|
|
1042
1104
|
"modelConfigKey": null,
|
|
1105
|
+
"effortConfigKey": null,
|
|
1106
|
+
"defaultEffort": null,
|
|
1043
1107
|
"handler": null
|
|
1108
|
+
},
|
|
1109
|
+
"config": {
|
|
1110
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": {
|
|
1111
|
+
"type": "number",
|
|
1112
|
+
"default": -1,
|
|
1113
|
+
"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\"."
|
|
1114
|
+
}
|
|
1044
1115
|
}
|
|
1045
1116
|
},
|
|
1046
1117
|
"codex": {
|
|
1047
1118
|
"id": "codex",
|
|
1048
1119
|
"role": "runtime",
|
|
1049
|
-
"version": "1.
|
|
1120
|
+
"version": "1.13.0",
|
|
1050
1121
|
"title": "OpenAI Codex CLI",
|
|
1051
1122
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
1052
1123
|
"tier": "core",
|
|
@@ -1130,7 +1201,8 @@ const capabilities = {
|
|
|
1130
1201
|
"background": true,
|
|
1131
1202
|
"subagentToolkit": "full",
|
|
1132
1203
|
"backgroundDispatch": true,
|
|
1133
|
-
"isolation": "orchestrator-worktree"
|
|
1204
|
+
"isolation": "orchestrator-worktree",
|
|
1205
|
+
"maxConcurrency": "undocumented"
|
|
1134
1206
|
},
|
|
1135
1207
|
"modelMode": "passive",
|
|
1136
1208
|
"hookBus": "host",
|
|
@@ -1145,7 +1217,8 @@ const capabilities = {
|
|
|
1145
1217
|
"exec"
|
|
1146
1218
|
],
|
|
1147
1219
|
"cwdFlag": "--cd",
|
|
1148
|
-
"promptFlag": null
|
|
1220
|
+
"promptFlag": null,
|
|
1221
|
+
"modelFlag": "--model"
|
|
1149
1222
|
},
|
|
1150
1223
|
"hostBehaviors": {
|
|
1151
1224
|
"reapplyCommand": "$gsd-update --reapply",
|
|
@@ -1183,12 +1256,15 @@ const capabilities = {
|
|
|
1183
1256
|
"effortChannel": "argv"
|
|
1184
1257
|
},
|
|
1185
1258
|
"timeoutFloorMs": 1200000,
|
|
1259
|
+
"timeoutConfigKey": "review.timeouts.codex",
|
|
1186
1260
|
"emptyOutput": "stub-with-stderr",
|
|
1187
1261
|
"reviewsSection": "Codex",
|
|
1188
1262
|
"evidenceClass": "source-grounded",
|
|
1189
1263
|
"requiresBinaries": [],
|
|
1190
|
-
"promptBudgetKey":
|
|
1264
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.codex",
|
|
1191
1265
|
"modelConfigKey": "review.models.codex",
|
|
1266
|
+
"effortConfigKey": "review.effort.codex",
|
|
1267
|
+
"defaultEffort": "high",
|
|
1192
1268
|
"handler": null
|
|
1193
1269
|
},
|
|
1194
1270
|
"config": {
|
|
@@ -1196,13 +1272,28 @@ const capabilities = {
|
|
|
1196
1272
|
"type": "string",
|
|
1197
1273
|
"default": "",
|
|
1198
1274
|
"description": "Model passed to the Codex reviewer lane."
|
|
1275
|
+
},
|
|
1276
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
1277
|
+
"type": "number",
|
|
1278
|
+
"default": -1,
|
|
1279
|
+
"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\"."
|
|
1280
|
+
},
|
|
1281
|
+
"review.timeouts.codex": {
|
|
1282
|
+
"type": "number",
|
|
1283
|
+
"default": -1,
|
|
1284
|
+
"description": "Outer wall-clock timeout override (seconds) for the Codex reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
1285
|
+
},
|
|
1286
|
+
"review.effort.codex": {
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"default": "",
|
|
1289
|
+
"description": "Reasoning effort for the Codex reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
1199
1290
|
}
|
|
1200
1291
|
}
|
|
1201
1292
|
},
|
|
1202
1293
|
"copilot": {
|
|
1203
1294
|
"id": "copilot",
|
|
1204
1295
|
"role": "runtime",
|
|
1205
|
-
"version": "1.
|
|
1296
|
+
"version": "1.13.0",
|
|
1206
1297
|
"title": "GitHub Copilot",
|
|
1207
1298
|
"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
1299
|
"tier": "core",
|
|
@@ -1281,7 +1372,8 @@ const capabilities = {
|
|
|
1281
1372
|
"background": true,
|
|
1282
1373
|
"subagentToolkit": "full",
|
|
1283
1374
|
"backgroundDispatch": false,
|
|
1284
|
-
"isolation": "undocumented"
|
|
1375
|
+
"isolation": "undocumented",
|
|
1376
|
+
"maxConcurrency": "undocumented"
|
|
1285
1377
|
},
|
|
1286
1378
|
"modelMode": "passive",
|
|
1287
1379
|
"hookBus": "host",
|
|
@@ -1301,7 +1393,7 @@ const capabilities = {
|
|
|
1301
1393
|
"cursor": {
|
|
1302
1394
|
"id": "cursor",
|
|
1303
1395
|
"role": "runtime",
|
|
1304
|
-
"version": "1.
|
|
1396
|
+
"version": "1.13.0",
|
|
1305
1397
|
"title": "Cursor",
|
|
1306
1398
|
"description": "Cursor IDE — skills-only workflow surface; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
1307
1399
|
"tier": "core",
|
|
@@ -1380,7 +1472,8 @@ const capabilities = {
|
|
|
1380
1472
|
"background": true,
|
|
1381
1473
|
"subagentToolkit": "full",
|
|
1382
1474
|
"backgroundDispatch": true,
|
|
1383
|
-
"isolation": "harness-worktree"
|
|
1475
|
+
"isolation": "harness-worktree",
|
|
1476
|
+
"maxConcurrency": "undocumented"
|
|
1384
1477
|
},
|
|
1385
1478
|
"modelMode": "passive",
|
|
1386
1479
|
"hookBus": "host",
|
|
@@ -1428,6 +1521,7 @@ const capabilities = {
|
|
|
1428
1521
|
"binary": "cursor-agent",
|
|
1429
1522
|
"args": [
|
|
1430
1523
|
"-p",
|
|
1524
|
+
"{{model}}",
|
|
1431
1525
|
"--mode",
|
|
1432
1526
|
"ask",
|
|
1433
1527
|
"--trust",
|
|
@@ -1437,23 +1531,38 @@ const capabilities = {
|
|
|
1437
1531
|
],
|
|
1438
1532
|
"promptChannel": "argv-file-ref",
|
|
1439
1533
|
"outputChannel": "stdout",
|
|
1440
|
-
"modelArg":
|
|
1534
|
+
"modelArg": "--model",
|
|
1441
1535
|
"effortChannel": "none"
|
|
1442
1536
|
},
|
|
1443
1537
|
"timeoutFloorMs": 900000,
|
|
1538
|
+
"timeoutConfigKey": null,
|
|
1444
1539
|
"emptyOutput": "stub-with-stderr",
|
|
1445
1540
|
"reviewsSection": "Cursor",
|
|
1446
1541
|
"evidenceClass": "source-grounded",
|
|
1447
1542
|
"requiresBinaries": [],
|
|
1448
|
-
"promptBudgetKey":
|
|
1449
|
-
"modelConfigKey":
|
|
1543
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
|
1544
|
+
"modelConfigKey": "review.models.cursor",
|
|
1545
|
+
"effortConfigKey": null,
|
|
1546
|
+
"defaultEffort": null,
|
|
1450
1547
|
"handler": null
|
|
1548
|
+
},
|
|
1549
|
+
"config": {
|
|
1550
|
+
"review.models.cursor": {
|
|
1551
|
+
"type": "string",
|
|
1552
|
+
"default": "",
|
|
1553
|
+
"description": "Model passed to the Cursor reviewer lane."
|
|
1554
|
+
},
|
|
1555
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
1556
|
+
"type": "number",
|
|
1557
|
+
"default": -1,
|
|
1558
|
+
"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\"."
|
|
1559
|
+
}
|
|
1451
1560
|
}
|
|
1452
1561
|
},
|
|
1453
1562
|
"drift": {
|
|
1454
1563
|
"id": "drift",
|
|
1455
1564
|
"role": "feature",
|
|
1456
|
-
"version": "1.
|
|
1565
|
+
"version": "1.13.0",
|
|
1457
1566
|
"title": "Drift detection gates",
|
|
1458
1567
|
"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
1568
|
"tier": "full",
|
|
@@ -1494,6 +1603,20 @@ const capabilities = {
|
|
|
1494
1603
|
"type": "boolean",
|
|
1495
1604
|
"default": true,
|
|
1496
1605
|
"description": "Enable the non-blocking codebase drift pre-check at plan:pre, before /gsd:plan-phase spawns the planner. When enabled, a stale STRUCTURE.md (structural additions exceeding drift_threshold) is surfaced up front as a warn-only advisory pointing to /gsd:map-codebase; it never blocks planning and never spawns the mapper agent. Separate from schema_drift_gate so autonomous/CI runs can silence the plan-time advisory while keeping the execute:wave:post gates enabled."
|
|
1606
|
+
},
|
|
1607
|
+
"workflow.context_drift_precheck": {
|
|
1608
|
+
"type": "boolean",
|
|
1609
|
+
"default": true,
|
|
1610
|
+
"description": "Enable the non-blocking context-drift pre-check at plan:pre, before /gsd:plan-phase reuses an existing RESEARCH.md/PATTERNS.md/VALIDATION.md/SPEC.md. Compares each artifact's effective last-changed time (git commit time, falling back to mtime for uncommitted edits) against CONTEXT.md's own — an artifact that predates CONTEXT.md's newest decision was derived from a premise that has since changed. Warn-only by default (see workflow.context_drift_action); never blocks planning on its own."
|
|
1611
|
+
},
|
|
1612
|
+
"workflow.context_drift_action": {
|
|
1613
|
+
"type": "enum",
|
|
1614
|
+
"values": [
|
|
1615
|
+
"warn",
|
|
1616
|
+
"block"
|
|
1617
|
+
],
|
|
1618
|
+
"default": "warn",
|
|
1619
|
+
"description": "Action taken by the context-drift gate when a stale upstream artifact is found: warn (advisory message naming the stale artifacts and how to regenerate them) or block (halt plan-phase until the artifacts are regenerated or the check is disabled)."
|
|
1497
1620
|
}
|
|
1498
1621
|
},
|
|
1499
1622
|
"steps": [],
|
|
@@ -1525,15 +1648,24 @@ const capabilities = {
|
|
|
1525
1648
|
"when": "workflow.plan_drift_precheck",
|
|
1526
1649
|
"blocking": false,
|
|
1527
1650
|
"onError": "skip"
|
|
1651
|
+
},
|
|
1652
|
+
{
|
|
1653
|
+
"point": "plan:pre",
|
|
1654
|
+
"check": {
|
|
1655
|
+
"query": "verify.context-drift"
|
|
1656
|
+
},
|
|
1657
|
+
"when": "workflow.context_drift_precheck",
|
|
1658
|
+
"blocking": false,
|
|
1659
|
+
"onError": "skip"
|
|
1528
1660
|
}
|
|
1529
1661
|
]
|
|
1530
1662
|
},
|
|
1531
1663
|
"external-job": {
|
|
1532
1664
|
"id": "external-job",
|
|
1533
1665
|
"role": "feature",
|
|
1534
|
-
"version": "1.
|
|
1666
|
+
"version": "1.13.0",
|
|
1535
1667
|
"title": "Async external-job scheduler adapter",
|
|
1536
|
-
"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
|
|
1668
|
+
"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 classification at execute:wave:pre and recording at execute:wave:post. This capability still contributes executor guidance at wave:post; execute-phase now renders wave:pre entries and dispatches generic step hooks there independently. Moving external-job classification to wave:pre is a separate capability change, not part of #4148. 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
1669
|
"tier": "full",
|
|
1538
1670
|
"requires": [],
|
|
1539
1671
|
"engines": {
|
|
@@ -1585,7 +1717,7 @@ const capabilities = {
|
|
|
1585
1717
|
"into": "executor",
|
|
1586
1718
|
"fragment": {
|
|
1587
1719
|
"path": "fragments/execute-wave-post.md",
|
|
1588
|
-
"inline": "<!-- external-job capability — execute:wave:post fragment, injected into the executor (#1164).\n\n
|
|
1720
|
+
"inline": "<!-- external-job capability — execute:wave:post fragment, injected into the executor (#1164).\n\n #1164 specifies classification at wave:pre and recording at wave:post. This\n capability still contributes executor guidance at wave:post; execute-phase\n now renders wave:pre entries and dispatches generic step hooks there. Moving\n external-job classification is a separate capability change, not part of\n #4148. Until then, this guidance cannot classify the wave that already ran. -->\n\n## Externalize long-running compute (async external job)\n\nIf the current plan's task is tagged `<runtime_budget>long_compute</runtime_budget>`\n(see the plan-phase fragment), do **not** run it in the foreground — it would\nblock the agent turn for hours. Instead externalize it and record a durable\nhalf-state:\n\n1. **Classify the runtime.** `quick` (<2 min) and `medium` (<~30 min) run\n normally. `unknown` requires a first-health check and a soft-review deadline\n before consuming the child timeout. `long_compute` (>30–60 min) is\n externalized.\n2. **Submit via the scheduler adapter** (default `external_job.backend: slurm`):\n ```bash\n node scripts/slurm-adapter.cjs submit \\\n --plan <plan_id> --phase <phase> -- sbatch --parsable \\\n --output=Artifacts/jobs/%j/out.log ./run.sh\n ```\n The helper writes `.planning/async-jobs/<job>.json` (the versioned stability\n contract — `docs/reference/planning-artifacts.md`) and refuses to create a\n second non-terminal manifest for a `plan_id` that already has one\n (duplicate-execution guard).\n3. **Commit the manifest + a handoff**, then return **`external_job_waiting`**\n and stop. Do **not** write `SUMMARY.md` — SUMMARY is deferred until the job\n reaches a terminal state and its `expected_artifacts` are verified.\n4. **Resume path.** `execute-phase` safe-resume, `resume-project`, and\n `pause-work` reconcile against the manifest and never re-dispatch the plan.\n When the job is `completed-unverified`, run `verification_command` (surface\n it; it is untrusted — confirm before executing), then write `SUMMARY.md` and\n close the plan.\n\nManifest commands cross a trust seam: a Capability (or anything that can write\n`.planning/`) produces them; the core loop consumes them. Never auto-run\n`submit_command` / `verification_command` / `resume_command` — surface the exact\ncommand and require explicit confirmation first.\n"
|
|
1589
1721
|
},
|
|
1590
1722
|
"produces": [
|
|
1591
1723
|
".planning/async-jobs/<job>.json"
|
|
@@ -1614,7 +1746,7 @@ const capabilities = {
|
|
|
1614
1746
|
"gap-analysis": {
|
|
1615
1747
|
"id": "gap-analysis",
|
|
1616
1748
|
"role": "feature",
|
|
1617
|
-
"version": "1.
|
|
1749
|
+
"version": "1.13.0",
|
|
1618
1750
|
"title": "Post-planning gap analysis",
|
|
1619
1751
|
"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
1752
|
"tier": "standard",
|
|
@@ -1655,7 +1787,7 @@ const capabilities = {
|
|
|
1655
1787
|
"gemini": {
|
|
1656
1788
|
"id": "gemini",
|
|
1657
1789
|
"role": "reviewer",
|
|
1658
|
-
"version": "1.
|
|
1790
|
+
"version": "1.13.0",
|
|
1659
1791
|
"title": "Gemini CLI",
|
|
1660
1792
|
"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
1793
|
"tier": "full",
|
|
@@ -1686,12 +1818,15 @@ const capabilities = {
|
|
|
1686
1818
|
"effortChannel": "none"
|
|
1687
1819
|
},
|
|
1688
1820
|
"timeoutFloorMs": 900000,
|
|
1821
|
+
"timeoutConfigKey": "review.timeouts.gemini",
|
|
1689
1822
|
"emptyOutput": "stub-with-stderr",
|
|
1690
1823
|
"reviewsSection": "Gemini",
|
|
1691
1824
|
"evidenceClass": "source-grounded",
|
|
1692
1825
|
"requiresBinaries": [],
|
|
1693
|
-
"promptBudgetKey":
|
|
1826
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.gemini",
|
|
1694
1827
|
"modelConfigKey": "review.models.gemini",
|
|
1828
|
+
"effortConfigKey": null,
|
|
1829
|
+
"defaultEffort": null,
|
|
1695
1830
|
"handler": null
|
|
1696
1831
|
},
|
|
1697
1832
|
"config": {
|
|
@@ -1699,13 +1834,23 @@ const capabilities = {
|
|
|
1699
1834
|
"type": "string",
|
|
1700
1835
|
"default": "",
|
|
1701
1836
|
"description": "Model passed to the Gemini reviewer lane."
|
|
1837
|
+
},
|
|
1838
|
+
"review.max_prompt_tokens_per_reviewer.gemini": {
|
|
1839
|
+
"type": "number",
|
|
1840
|
+
"default": -1,
|
|
1841
|
+
"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\"."
|
|
1842
|
+
},
|
|
1843
|
+
"review.timeouts.gemini": {
|
|
1844
|
+
"type": "number",
|
|
1845
|
+
"default": -1,
|
|
1846
|
+
"description": "Outer wall-clock timeout override (seconds) for the Gemini reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
1702
1847
|
}
|
|
1703
1848
|
}
|
|
1704
1849
|
},
|
|
1705
1850
|
"graphify": {
|
|
1706
1851
|
"id": "graphify",
|
|
1707
1852
|
"role": "feature",
|
|
1708
|
-
"version": "1.
|
|
1853
|
+
"version": "1.13.0",
|
|
1709
1854
|
"title": "Knowledge graph",
|
|
1710
1855
|
"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
1856
|
"tier": "full",
|
|
@@ -1746,7 +1891,7 @@ const capabilities = {
|
|
|
1746
1891
|
"hermes": {
|
|
1747
1892
|
"id": "hermes",
|
|
1748
1893
|
"role": "runtime",
|
|
1749
|
-
"version": "1.
|
|
1894
|
+
"version": "1.13.0",
|
|
1750
1895
|
"title": "Hermes Agent",
|
|
1751
1896
|
"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
1897
|
"tier": "core",
|
|
@@ -1843,7 +1988,8 @@ const capabilities = {
|
|
|
1843
1988
|
"background": true,
|
|
1844
1989
|
"subagentToolkit": "read-only",
|
|
1845
1990
|
"backgroundDispatch": false,
|
|
1846
|
-
"isolation": "undocumented"
|
|
1991
|
+
"isolation": "undocumented",
|
|
1992
|
+
"maxConcurrency": "undocumented"
|
|
1847
1993
|
},
|
|
1848
1994
|
"modelMode": "active",
|
|
1849
1995
|
"hookBus": "host",
|
|
@@ -1857,7 +2003,7 @@ const capabilities = {
|
|
|
1857
2003
|
"intel": {
|
|
1858
2004
|
"id": "intel",
|
|
1859
2005
|
"role": "feature",
|
|
1860
|
-
"version": "1.
|
|
2006
|
+
"version": "1.13.0",
|
|
1861
2007
|
"title": "Codebase intelligence",
|
|
1862
2008
|
"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
2009
|
"tier": "full",
|
|
@@ -1909,7 +2055,7 @@ const capabilities = {
|
|
|
1909
2055
|
"kilo": {
|
|
1910
2056
|
"id": "kilo",
|
|
1911
2057
|
"role": "runtime",
|
|
1912
|
-
"version": "1.
|
|
2058
|
+
"version": "1.13.0",
|
|
1913
2059
|
"title": "Kilo Code",
|
|
1914
2060
|
"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
2061
|
"tier": "core",
|
|
@@ -2011,7 +2157,8 @@ const capabilities = {
|
|
|
2011
2157
|
"background": true,
|
|
2012
2158
|
"subagentToolkit": "undocumented",
|
|
2013
2159
|
"backgroundDispatch": false,
|
|
2014
|
-
"isolation": "undocumented"
|
|
2160
|
+
"isolation": "undocumented",
|
|
2161
|
+
"maxConcurrency": "undocumented"
|
|
2015
2162
|
},
|
|
2016
2163
|
"modelMode": "active",
|
|
2017
2164
|
"hookBus": "host",
|
|
@@ -2038,7 +2185,7 @@ const capabilities = {
|
|
|
2038
2185
|
"kimi": {
|
|
2039
2186
|
"id": "kimi",
|
|
2040
2187
|
"role": "runtime",
|
|
2041
|
-
"version": "1.
|
|
2188
|
+
"version": "1.13.0",
|
|
2042
2189
|
"title": "Kimi CLI",
|
|
2043
2190
|
"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
2191
|
"tier": "core",
|
|
@@ -2110,7 +2257,8 @@ const capabilities = {
|
|
|
2110
2257
|
"background": true,
|
|
2111
2258
|
"subagentToolkit": "undocumented",
|
|
2112
2259
|
"backgroundDispatch": true,
|
|
2113
|
-
"isolation": "orchestrator-worktree"
|
|
2260
|
+
"isolation": "orchestrator-worktree",
|
|
2261
|
+
"maxConcurrency": "undocumented"
|
|
2114
2262
|
},
|
|
2115
2263
|
"modelMode": "passive",
|
|
2116
2264
|
"hookBus": "host",
|
|
@@ -2133,14 +2281,15 @@ const capabilities = {
|
|
|
2133
2281
|
"verificationStyle": "kimi",
|
|
2134
2282
|
"agentManifestStyle": "kimi-nested",
|
|
2135
2283
|
"doneBannerStyle": "kimi-agent-file",
|
|
2136
|
-
"skipSharedHooksInstall": true
|
|
2284
|
+
"skipSharedHooksInstall": true,
|
|
2285
|
+
"noPathRewrite": true
|
|
2137
2286
|
}
|
|
2138
2287
|
}
|
|
2139
2288
|
},
|
|
2140
2289
|
"kimi-code": {
|
|
2141
2290
|
"id": "kimi-code",
|
|
2142
2291
|
"role": "runtime",
|
|
2143
|
-
"version": "1.
|
|
2292
|
+
"version": "1.13.0",
|
|
2144
2293
|
"title": "Kimi Code CLI",
|
|
2145
2294
|
"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
2295
|
"tier": "core",
|
|
@@ -2225,7 +2374,8 @@ const capabilities = {
|
|
|
2225
2374
|
"explore",
|
|
2226
2375
|
"plan"
|
|
2227
2376
|
],
|
|
2228
|
-
"isolation": "orchestrator-worktree"
|
|
2377
|
+
"isolation": "orchestrator-worktree",
|
|
2378
|
+
"maxConcurrency": "undocumented"
|
|
2229
2379
|
},
|
|
2230
2380
|
"modelMode": "passive",
|
|
2231
2381
|
"hookBus": "host",
|
|
@@ -2274,12 +2424,15 @@ const capabilities = {
|
|
|
2274
2424
|
"effortChannel": "none"
|
|
2275
2425
|
},
|
|
2276
2426
|
"timeoutFloorMs": 900000,
|
|
2427
|
+
"timeoutConfigKey": "review.timeouts.kimi-code",
|
|
2277
2428
|
"emptyOutput": "stub-with-stderr",
|
|
2278
2429
|
"reviewsSection": "Kimi Code",
|
|
2279
2430
|
"evidenceClass": "source-grounded",
|
|
2280
2431
|
"requiresBinaries": [],
|
|
2281
|
-
"promptBudgetKey":
|
|
2432
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.kimi-code",
|
|
2282
2433
|
"modelConfigKey": "review.models.kimi-code",
|
|
2434
|
+
"effortConfigKey": null,
|
|
2435
|
+
"defaultEffort": null,
|
|
2283
2436
|
"handler": null
|
|
2284
2437
|
},
|
|
2285
2438
|
"config": {
|
|
@@ -2287,13 +2440,76 @@ const capabilities = {
|
|
|
2287
2440
|
"type": "string",
|
|
2288
2441
|
"default": "",
|
|
2289
2442
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
2443
|
+
},
|
|
2444
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
2445
|
+
"type": "number",
|
|
2446
|
+
"default": -1,
|
|
2447
|
+
"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\"."
|
|
2448
|
+
},
|
|
2449
|
+
"review.timeouts.kimi-code": {
|
|
2450
|
+
"type": "number",
|
|
2451
|
+
"default": -1,
|
|
2452
|
+
"description": "Outer wall-clock timeout override (seconds) for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
2290
2453
|
}
|
|
2291
2454
|
}
|
|
2292
2455
|
},
|
|
2456
|
+
"live-dom-uat": {
|
|
2457
|
+
"id": "live-dom-uat",
|
|
2458
|
+
"role": "feature",
|
|
2459
|
+
"version": "1.13.0",
|
|
2460
|
+
"title": "Live-DOM UAT",
|
|
2461
|
+
"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.",
|
|
2462
|
+
"tier": "full",
|
|
2463
|
+
"requires": [],
|
|
2464
|
+
"engines": {
|
|
2465
|
+
"gsd": ">=1.11.0"
|
|
2466
|
+
},
|
|
2467
|
+
"runtimeCompat": {
|
|
2468
|
+
"supported": [
|
|
2469
|
+
"*"
|
|
2470
|
+
],
|
|
2471
|
+
"unsupported": []
|
|
2472
|
+
},
|
|
2473
|
+
"skills": [],
|
|
2474
|
+
"agents": [
|
|
2475
|
+
"gsd-dom-verifier"
|
|
2476
|
+
],
|
|
2477
|
+
"activationKey": "workflow.live_dom_uat",
|
|
2478
|
+
"config": {
|
|
2479
|
+
"workflow.live_dom_uat": {
|
|
2480
|
+
"type": "boolean",
|
|
2481
|
+
"default": false,
|
|
2482
|
+
"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."
|
|
2483
|
+
}
|
|
2484
|
+
},
|
|
2485
|
+
"hooks": [],
|
|
2486
|
+
"steps": [
|
|
2487
|
+
{
|
|
2488
|
+
"point": "execute:wave:post",
|
|
2489
|
+
"ref": {
|
|
2490
|
+
"agent": "gsd-dom-verifier"
|
|
2491
|
+
},
|
|
2492
|
+
"fragment": {
|
|
2493
|
+
"path": "fragments/execute-wave-post.md",
|
|
2494
|
+
"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"
|
|
2495
|
+
},
|
|
2496
|
+
"produces": [
|
|
2497
|
+
"DOM-VERIFY.md"
|
|
2498
|
+
],
|
|
2499
|
+
"consumes": [
|
|
2500
|
+
"PLAN.md"
|
|
2501
|
+
],
|
|
2502
|
+
"when": "workflow.live_dom_uat",
|
|
2503
|
+
"onError": "skip"
|
|
2504
|
+
}
|
|
2505
|
+
],
|
|
2506
|
+
"contributions": [],
|
|
2507
|
+
"gates": []
|
|
2508
|
+
},
|
|
2293
2509
|
"llama-cpp": {
|
|
2294
2510
|
"id": "llama-cpp",
|
|
2295
2511
|
"role": "reviewer",
|
|
2296
|
-
"version": "1.
|
|
2512
|
+
"version": "1.13.0",
|
|
2297
2513
|
"title": "llama.cpp",
|
|
2298
2514
|
"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
2515
|
"tier": "full",
|
|
@@ -2322,12 +2538,15 @@ const capabilities = {
|
|
|
2322
2538
|
"effortChannel": "none"
|
|
2323
2539
|
},
|
|
2324
2540
|
"timeoutFloorMs": 120000,
|
|
2541
|
+
"timeoutConfigKey": "review.timeouts.llama_cpp",
|
|
2325
2542
|
"emptyOutput": "stub-with-stderr",
|
|
2326
2543
|
"reviewsSection": "llama.cpp",
|
|
2327
2544
|
"evidenceClass": "source-grounded",
|
|
2328
2545
|
"requiresBinaries": [],
|
|
2329
2546
|
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.llama_cpp",
|
|
2330
2547
|
"modelConfigKey": "review.models.llama_cpp",
|
|
2548
|
+
"effortConfigKey": null,
|
|
2549
|
+
"defaultEffort": null,
|
|
2331
2550
|
"handler": "openai-compatible"
|
|
2332
2551
|
},
|
|
2333
2552
|
"config": {
|
|
@@ -2345,13 +2564,18 @@ const capabilities = {
|
|
|
2345
2564
|
"type": "number",
|
|
2346
2565
|
"default": -1,
|
|
2347
2566
|
"description": "Prompt-token budget for the llama.cpp 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\"."
|
|
2567
|
+
},
|
|
2568
|
+
"review.timeouts.llama_cpp": {
|
|
2569
|
+
"type": "number",
|
|
2570
|
+
"default": -1,
|
|
2571
|
+
"description": "Outer wall-clock timeout override (seconds) for the llama.cpp reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
2348
2572
|
}
|
|
2349
2573
|
}
|
|
2350
2574
|
},
|
|
2351
2575
|
"lm-studio": {
|
|
2352
2576
|
"id": "lm-studio",
|
|
2353
2577
|
"role": "reviewer",
|
|
2354
|
-
"version": "1.
|
|
2578
|
+
"version": "1.13.0",
|
|
2355
2579
|
"title": "LM Studio",
|
|
2356
2580
|
"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
2581
|
"tier": "full",
|
|
@@ -2380,12 +2604,15 @@ const capabilities = {
|
|
|
2380
2604
|
"effortChannel": "none"
|
|
2381
2605
|
},
|
|
2382
2606
|
"timeoutFloorMs": 120000,
|
|
2607
|
+
"timeoutConfigKey": "review.timeouts.lm_studio",
|
|
2383
2608
|
"emptyOutput": "stub-with-stderr",
|
|
2384
2609
|
"reviewsSection": "LM Studio",
|
|
2385
2610
|
"evidenceClass": "source-grounded",
|
|
2386
2611
|
"requiresBinaries": [],
|
|
2387
2612
|
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.lm_studio",
|
|
2388
2613
|
"modelConfigKey": "review.models.lm_studio",
|
|
2614
|
+
"effortConfigKey": null,
|
|
2615
|
+
"defaultEffort": null,
|
|
2389
2616
|
"handler": "openai-compatible"
|
|
2390
2617
|
},
|
|
2391
2618
|
"config": {
|
|
@@ -2403,13 +2630,18 @@ const capabilities = {
|
|
|
2403
2630
|
"type": "number",
|
|
2404
2631
|
"default": -1,
|
|
2405
2632
|
"description": "Prompt-token budget for the LM Studio 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\"."
|
|
2633
|
+
},
|
|
2634
|
+
"review.timeouts.lm_studio": {
|
|
2635
|
+
"type": "number",
|
|
2636
|
+
"default": -1,
|
|
2637
|
+
"description": "Outer wall-clock timeout override (seconds) for the LM Studio reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
2406
2638
|
}
|
|
2407
2639
|
}
|
|
2408
2640
|
},
|
|
2409
2641
|
"mempalace": {
|
|
2410
2642
|
"id": "mempalace",
|
|
2411
2643
|
"role": "feature",
|
|
2412
|
-
"version": "1.
|
|
2644
|
+
"version": "1.13.0",
|
|
2413
2645
|
"title": "MemPalace memory",
|
|
2414
2646
|
"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
2647
|
"tier": "full",
|
|
@@ -2583,7 +2815,7 @@ const capabilities = {
|
|
|
2583
2815
|
"nyquist": {
|
|
2584
2816
|
"id": "nyquist",
|
|
2585
2817
|
"role": "feature",
|
|
2586
|
-
"version": "1.
|
|
2818
|
+
"version": "1.13.0",
|
|
2587
2819
|
"title": "Nyquist validation",
|
|
2588
2820
|
"description": "Validation coverage audit that maps executed work back to tests and manual-only evidence.",
|
|
2589
2821
|
"tier": "full",
|
|
@@ -2633,7 +2865,7 @@ const capabilities = {
|
|
|
2633
2865
|
"ollama": {
|
|
2634
2866
|
"id": "ollama",
|
|
2635
2867
|
"role": "reviewer",
|
|
2636
|
-
"version": "1.
|
|
2868
|
+
"version": "1.13.0",
|
|
2637
2869
|
"title": "Ollama",
|
|
2638
2870
|
"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
2871
|
"tier": "full",
|
|
@@ -2662,12 +2894,15 @@ const capabilities = {
|
|
|
2662
2894
|
"effortChannel": "none"
|
|
2663
2895
|
},
|
|
2664
2896
|
"timeoutFloorMs": 120000,
|
|
2897
|
+
"timeoutConfigKey": "review.timeouts.ollama",
|
|
2665
2898
|
"emptyOutput": "stub-with-stderr",
|
|
2666
2899
|
"reviewsSection": "Ollama",
|
|
2667
2900
|
"evidenceClass": "source-grounded",
|
|
2668
2901
|
"requiresBinaries": [],
|
|
2669
2902
|
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.ollama",
|
|
2670
2903
|
"modelConfigKey": "review.models.ollama",
|
|
2904
|
+
"effortConfigKey": null,
|
|
2905
|
+
"defaultEffort": null,
|
|
2671
2906
|
"handler": "openai-compatible"
|
|
2672
2907
|
},
|
|
2673
2908
|
"config": {
|
|
@@ -2685,13 +2920,18 @@ const capabilities = {
|
|
|
2685
2920
|
"type": "number",
|
|
2686
2921
|
"default": -1,
|
|
2687
2922
|
"description": "Prompt-token budget for the Ollama 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\"."
|
|
2923
|
+
},
|
|
2924
|
+
"review.timeouts.ollama": {
|
|
2925
|
+
"type": "number",
|
|
2926
|
+
"default": -1,
|
|
2927
|
+
"description": "Outer wall-clock timeout override (seconds) for the Ollama reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
2688
2928
|
}
|
|
2689
2929
|
}
|
|
2690
2930
|
},
|
|
2691
2931
|
"opencode": {
|
|
2692
2932
|
"id": "opencode",
|
|
2693
2933
|
"role": "runtime",
|
|
2694
|
-
"version": "1.
|
|
2934
|
+
"version": "1.13.0",
|
|
2695
2935
|
"title": "OpenCode",
|
|
2696
2936
|
"description": "OpenCode — XDG-based config dir; flat commands/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
2697
2937
|
"tier": "core",
|
|
@@ -2788,7 +3028,8 @@ const capabilities = {
|
|
|
2788
3028
|
"background": false,
|
|
2789
3029
|
"subagentToolkit": "full",
|
|
2790
3030
|
"backgroundDispatch": false,
|
|
2791
|
-
"isolation": "orchestrator-worktree"
|
|
3031
|
+
"isolation": "orchestrator-worktree",
|
|
3032
|
+
"maxConcurrency": "undocumented"
|
|
2792
3033
|
},
|
|
2793
3034
|
"modelMode": "active",
|
|
2794
3035
|
"hookBus": "host",
|
|
@@ -2848,12 +3089,15 @@ const capabilities = {
|
|
|
2848
3089
|
"effortChannel": "argv"
|
|
2849
3090
|
},
|
|
2850
3091
|
"timeoutFloorMs": 660000,
|
|
3092
|
+
"timeoutConfigKey": "review.timeouts.opencode",
|
|
2851
3093
|
"emptyOutput": "stub-with-stderr",
|
|
2852
3094
|
"reviewsSection": "OpenCode",
|
|
2853
3095
|
"evidenceClass": "source-grounded",
|
|
2854
3096
|
"requiresBinaries": [],
|
|
2855
|
-
"promptBudgetKey":
|
|
3097
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.opencode",
|
|
2856
3098
|
"modelConfigKey": "review.models.opencode",
|
|
3099
|
+
"effortConfigKey": "review.effort.opencode",
|
|
3100
|
+
"defaultEffort": "high",
|
|
2857
3101
|
"handler": "opencode"
|
|
2858
3102
|
},
|
|
2859
3103
|
"config": {
|
|
@@ -2861,13 +3105,28 @@ const capabilities = {
|
|
|
2861
3105
|
"type": "string",
|
|
2862
3106
|
"default": "",
|
|
2863
3107
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
3108
|
+
},
|
|
3109
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
3110
|
+
"type": "number",
|
|
3111
|
+
"default": -1,
|
|
3112
|
+
"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\"."
|
|
3113
|
+
},
|
|
3114
|
+
"review.timeouts.opencode": {
|
|
3115
|
+
"type": "number",
|
|
3116
|
+
"default": -1,
|
|
3117
|
+
"description": "Outer wall-clock timeout override (seconds) for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
3118
|
+
},
|
|
3119
|
+
"review.effort.opencode": {
|
|
3120
|
+
"type": "string",
|
|
3121
|
+
"default": "",
|
|
3122
|
+
"description": "Reasoning effort for the OpenCode reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
2864
3123
|
}
|
|
2865
3124
|
}
|
|
2866
3125
|
},
|
|
2867
3126
|
"pattern-mapper": {
|
|
2868
3127
|
"id": "pattern-mapper",
|
|
2869
3128
|
"role": "feature",
|
|
2870
|
-
"version": "1.
|
|
3129
|
+
"version": "1.13.0",
|
|
2871
3130
|
"title": "Pattern mapping",
|
|
2872
3131
|
"description": "Optional codebase-pattern mapping before planning; owns the pattern mapper agent and workflow.pattern_mapper activation key.",
|
|
2873
3132
|
"tier": "full",
|
|
@@ -2921,7 +3180,7 @@ const capabilities = {
|
|
|
2921
3180
|
"pi": {
|
|
2922
3181
|
"id": "pi",
|
|
2923
3182
|
"role": "runtime",
|
|
2924
|
-
"version": "1.
|
|
3183
|
+
"version": "1.13.0",
|
|
2925
3184
|
"title": "pi",
|
|
2926
3185
|
"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
3186
|
"tier": "core",
|
|
@@ -2967,7 +3226,8 @@ const capabilities = {
|
|
|
2967
3226
|
"background": false,
|
|
2968
3227
|
"backgroundDispatch": false,
|
|
2969
3228
|
"subagentToolkit": "undocumented",
|
|
2970
|
-
"isolation": "none"
|
|
3229
|
+
"isolation": "none",
|
|
3230
|
+
"maxConcurrency": "undocumented"
|
|
2971
3231
|
},
|
|
2972
3232
|
"modelMode": "active",
|
|
2973
3233
|
"hookBus": "host",
|
|
@@ -2990,7 +3250,7 @@ const capabilities = {
|
|
|
2990
3250
|
"profile-pipeline": {
|
|
2991
3251
|
"id": "profile-pipeline",
|
|
2992
3252
|
"role": "feature",
|
|
2993
|
-
"version": "1.
|
|
3253
|
+
"version": "1.13.0",
|
|
2994
3254
|
"title": "Developer profiling pipeline",
|
|
2995
3255
|
"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
3256
|
"tier": "full",
|
|
@@ -3067,7 +3327,7 @@ const capabilities = {
|
|
|
3067
3327
|
"qwen": {
|
|
3068
3328
|
"id": "qwen",
|
|
3069
3329
|
"role": "runtime",
|
|
3070
|
-
"version": "1.
|
|
3330
|
+
"version": "1.13.0",
|
|
3071
3331
|
"title": "Qwen Code",
|
|
3072
3332
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
3073
3333
|
"tier": "core",
|
|
@@ -3151,7 +3411,8 @@ const capabilities = {
|
|
|
3151
3411
|
"background": true,
|
|
3152
3412
|
"subagentToolkit": "full",
|
|
3153
3413
|
"backgroundDispatch": false,
|
|
3154
|
-
"isolation": "undocumented"
|
|
3414
|
+
"isolation": "undocumented",
|
|
3415
|
+
"maxConcurrency": "undocumented"
|
|
3155
3416
|
},
|
|
3156
3417
|
"modelMode": "passive",
|
|
3157
3418
|
"hookBus": "host",
|
|
@@ -3194,19 +3455,29 @@ const capabilities = {
|
|
|
3194
3455
|
"effortChannel": "none"
|
|
3195
3456
|
},
|
|
3196
3457
|
"timeoutFloorMs": 900000,
|
|
3458
|
+
"timeoutConfigKey": null,
|
|
3197
3459
|
"emptyOutput": "stub-with-stderr",
|
|
3198
3460
|
"reviewsSection": "Qwen",
|
|
3199
3461
|
"evidenceClass": "source-grounded",
|
|
3200
3462
|
"requiresBinaries": [],
|
|
3201
|
-
"promptBudgetKey":
|
|
3463
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.qwen",
|
|
3202
3464
|
"modelConfigKey": null,
|
|
3465
|
+
"effortConfigKey": null,
|
|
3466
|
+
"defaultEffort": null,
|
|
3203
3467
|
"handler": null
|
|
3468
|
+
},
|
|
3469
|
+
"config": {
|
|
3470
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
3471
|
+
"type": "number",
|
|
3472
|
+
"default": -1,
|
|
3473
|
+
"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\"."
|
|
3474
|
+
}
|
|
3204
3475
|
}
|
|
3205
3476
|
},
|
|
3206
3477
|
"refactor-trigger": {
|
|
3207
3478
|
"id": "refactor-trigger",
|
|
3208
3479
|
"role": "feature",
|
|
3209
|
-
"version": "1.
|
|
3480
|
+
"version": "1.13.0",
|
|
3210
3481
|
"title": "Complexity-triggered refactor",
|
|
3211
3482
|
"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
3483
|
"tier": "full",
|
|
@@ -3273,7 +3544,7 @@ const capabilities = {
|
|
|
3273
3544
|
"research": {
|
|
3274
3545
|
"id": "research",
|
|
3275
3546
|
"role": "feature",
|
|
3276
|
-
"version": "1.
|
|
3547
|
+
"version": "1.13.0",
|
|
3277
3548
|
"title": "Phase research",
|
|
3278
3549
|
"description": "Optional phase research before planning; owns the phase researcher agent and workflow.research activation key.",
|
|
3279
3550
|
"tier": "standard",
|
|
@@ -3325,7 +3596,7 @@ const capabilities = {
|
|
|
3325
3596
|
"schema-gate": {
|
|
3326
3597
|
"id": "schema-gate",
|
|
3327
3598
|
"role": "feature",
|
|
3328
|
-
"version": "1.
|
|
3599
|
+
"version": "1.13.0",
|
|
3329
3600
|
"title": "Schema push detection gate",
|
|
3330
3601
|
"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
3602
|
"tier": "full",
|
|
@@ -3371,7 +3642,7 @@ const capabilities = {
|
|
|
3371
3642
|
"security": {
|
|
3372
3643
|
"id": "security",
|
|
3373
3644
|
"role": "feature",
|
|
3374
|
-
"version": "1.
|
|
3645
|
+
"version": "1.13.0",
|
|
3375
3646
|
"title": "Security enforcement",
|
|
3376
3647
|
"description": "Threat mitigation verification and ship-time security blocking for phases with security enforcement enabled.",
|
|
3377
3648
|
"tier": "full",
|
|
@@ -3470,7 +3741,7 @@ const capabilities = {
|
|
|
3470
3741
|
"tdd": {
|
|
3471
3742
|
"id": "tdd",
|
|
3472
3743
|
"role": "feature",
|
|
3473
|
-
"version": "1.
|
|
3744
|
+
"version": "1.13.0",
|
|
3474
3745
|
"title": "Test-driven development",
|
|
3475
3746
|
"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
3747
|
"tier": "full",
|
|
@@ -3523,7 +3794,7 @@ const capabilities = {
|
|
|
3523
3794
|
"trae": {
|
|
3524
3795
|
"id": "trae",
|
|
3525
3796
|
"role": "runtime",
|
|
3526
|
-
"version": "1.
|
|
3797
|
+
"version": "1.13.0",
|
|
3527
3798
|
"title": "Trae IDE",
|
|
3528
3799
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
3529
3800
|
"tier": "core",
|
|
@@ -3601,7 +3872,8 @@ const capabilities = {
|
|
|
3601
3872
|
"background": true,
|
|
3602
3873
|
"subagentToolkit": "undocumented",
|
|
3603
3874
|
"backgroundDispatch": "undocumented",
|
|
3604
|
-
"isolation": "undocumented"
|
|
3875
|
+
"isolation": "undocumented",
|
|
3876
|
+
"maxConcurrency": "undocumented"
|
|
3605
3877
|
},
|
|
3606
3878
|
"modelMode": "passive",
|
|
3607
3879
|
"hookBus": "engine",
|
|
@@ -3620,7 +3892,7 @@ const capabilities = {
|
|
|
3620
3892
|
"ui": {
|
|
3621
3893
|
"id": "ui",
|
|
3622
3894
|
"role": "feature",
|
|
3623
|
-
"version": "1.
|
|
3895
|
+
"version": "1.13.0",
|
|
3624
3896
|
"title": "UI design contracts",
|
|
3625
3897
|
"description": "UI-SPEC design contract + retrospective UI audit for frontend phases.",
|
|
3626
3898
|
"tier": "full",
|
|
@@ -3715,7 +3987,7 @@ const capabilities = {
|
|
|
3715
3987
|
"vscode": {
|
|
3716
3988
|
"id": "vscode",
|
|
3717
3989
|
"role": "runtime",
|
|
3718
|
-
"version": "1.
|
|
3990
|
+
"version": "1.13.0",
|
|
3719
3991
|
"title": "VS Code",
|
|
3720
3992
|
"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
3993
|
"tier": "core",
|
|
@@ -3758,7 +4030,8 @@ const capabilities = {
|
|
|
3758
4030
|
"background": true,
|
|
3759
4031
|
"subagentToolkit": "undocumented",
|
|
3760
4032
|
"backgroundDispatch": "undocumented",
|
|
3761
|
-
"isolation": "undocumented"
|
|
4033
|
+
"isolation": "undocumented",
|
|
4034
|
+
"maxConcurrency": "undocumented"
|
|
3762
4035
|
},
|
|
3763
4036
|
"modelMode": "active",
|
|
3764
4037
|
"hookBus": "engine",
|
|
@@ -3772,7 +4045,7 @@ const capabilities = {
|
|
|
3772
4045
|
"windsurf": {
|
|
3773
4046
|
"id": "windsurf",
|
|
3774
4047
|
"role": "runtime",
|
|
3775
|
-
"version": "1.
|
|
4048
|
+
"version": "1.13.0",
|
|
3776
4049
|
"title": "Windsurf",
|
|
3777
4050
|
"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
4051
|
"tier": "core",
|
|
@@ -3843,7 +4116,8 @@ const capabilities = {
|
|
|
3843
4116
|
"background": "undocumented",
|
|
3844
4117
|
"subagentToolkit": "undocumented",
|
|
3845
4118
|
"backgroundDispatch": "undocumented",
|
|
3846
|
-
"isolation": "none"
|
|
4119
|
+
"isolation": "none",
|
|
4120
|
+
"maxConcurrency": "undocumented"
|
|
3847
4121
|
},
|
|
3848
4122
|
"modelMode": "passive",
|
|
3849
4123
|
"hookBus": "host",
|
|
@@ -3863,7 +4137,7 @@ const capabilities = {
|
|
|
3863
4137
|
"zcode": {
|
|
3864
4138
|
"id": "zcode",
|
|
3865
4139
|
"role": "runtime",
|
|
3866
|
-
"version": "1.
|
|
4140
|
+
"version": "1.13.0",
|
|
3867
4141
|
"title": "ZCode",
|
|
3868
4142
|
"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
4143
|
"tier": "core",
|
|
@@ -3957,7 +4231,8 @@ const capabilities = {
|
|
|
3957
4231
|
"background": false,
|
|
3958
4232
|
"subagentToolkit": "full",
|
|
3959
4233
|
"backgroundDispatch": false,
|
|
3960
|
-
"isolation": "none"
|
|
4234
|
+
"isolation": "none",
|
|
4235
|
+
"maxConcurrency": "undocumented"
|
|
3961
4236
|
},
|
|
3962
4237
|
"modelMode": "passive",
|
|
3963
4238
|
"hookBus": "host",
|
|
@@ -3993,6 +4268,7 @@ const byAgent = {
|
|
|
3993
4268
|
"gsd-eval-planner": "ai-integration",
|
|
3994
4269
|
"gsd-code-reviewer": "code-review",
|
|
3995
4270
|
"gsd-code-fixer": "code-review",
|
|
4271
|
+
"gsd-dom-verifier": "live-dom-uat",
|
|
3996
4272
|
"gsd-mempalace-curator": "mempalace",
|
|
3997
4273
|
"gsd-nyquist-auditor": "nyquist",
|
|
3998
4274
|
"gsd-pattern-mapper": "pattern-mapper",
|
|
@@ -4148,7 +4424,7 @@ const byLoopPoint = {
|
|
|
4148
4424
|
"into": "planner",
|
|
4149
4425
|
"fragment": {
|
|
4150
4426
|
"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 ||
|
|
4427
|
+
"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
4428
|
},
|
|
4153
4429
|
"produces": [
|
|
4154
4430
|
"COVERAGE.md"
|
|
@@ -4165,7 +4441,7 @@ const byLoopPoint = {
|
|
|
4165
4441
|
"into": "planner",
|
|
4166
4442
|
"fragment": {
|
|
4167
4443
|
"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 ||
|
|
4444
|
+
"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
4445
|
},
|
|
4170
4446
|
"produces": [],
|
|
4171
4447
|
"consumes": [
|
|
@@ -4230,6 +4506,16 @@ const byLoopPoint = {
|
|
|
4230
4506
|
"blocking": false,
|
|
4231
4507
|
"onError": "skip"
|
|
4232
4508
|
},
|
|
4509
|
+
{
|
|
4510
|
+
"capId": "drift",
|
|
4511
|
+
"point": "plan:pre",
|
|
4512
|
+
"check": {
|
|
4513
|
+
"query": "verify.context-drift"
|
|
4514
|
+
},
|
|
4515
|
+
"when": "workflow.context_drift_precheck",
|
|
4516
|
+
"blocking": false,
|
|
4517
|
+
"onError": "skip"
|
|
4518
|
+
},
|
|
4233
4519
|
{
|
|
4234
4520
|
"capId": "ui",
|
|
4235
4521
|
"point": "plan:pre",
|
|
@@ -4315,7 +4601,7 @@ const byLoopPoint = {
|
|
|
4315
4601
|
"into": "executor",
|
|
4316
4602
|
"fragment": {
|
|
4317
4603
|
"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"
|
|
4604
|
+
"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
4605
|
},
|
|
4320
4606
|
"produces": [],
|
|
4321
4607
|
"consumes": [
|
|
@@ -4328,7 +4614,41 @@ const byLoopPoint = {
|
|
|
4328
4614
|
"gates": []
|
|
4329
4615
|
},
|
|
4330
4616
|
"execute:wave:post": {
|
|
4331
|
-
"steps": [
|
|
4617
|
+
"steps": [
|
|
4618
|
+
{
|
|
4619
|
+
"capId": "code-review",
|
|
4620
|
+
"point": "execute:wave:post",
|
|
4621
|
+
"ref": {
|
|
4622
|
+
"skill": "code-review"
|
|
4623
|
+
},
|
|
4624
|
+
"produces": [
|
|
4625
|
+
"REVIEW.md"
|
|
4626
|
+
],
|
|
4627
|
+
"consumes": [],
|
|
4628
|
+
"when": "workflow.code_review",
|
|
4629
|
+
"pointFrom": "workflow.code_review_point",
|
|
4630
|
+
"onError": "skip"
|
|
4631
|
+
},
|
|
4632
|
+
{
|
|
4633
|
+
"capId": "live-dom-uat",
|
|
4634
|
+
"point": "execute:wave:post",
|
|
4635
|
+
"ref": {
|
|
4636
|
+
"agent": "gsd-dom-verifier"
|
|
4637
|
+
},
|
|
4638
|
+
"fragment": {
|
|
4639
|
+
"path": "fragments/execute-wave-post.md",
|
|
4640
|
+
"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"
|
|
4641
|
+
},
|
|
4642
|
+
"produces": [
|
|
4643
|
+
"DOM-VERIFY.md"
|
|
4644
|
+
],
|
|
4645
|
+
"consumes": [
|
|
4646
|
+
"PLAN.md"
|
|
4647
|
+
],
|
|
4648
|
+
"when": "workflow.live_dom_uat",
|
|
4649
|
+
"onError": "skip"
|
|
4650
|
+
}
|
|
4651
|
+
],
|
|
4332
4652
|
"contributions": [
|
|
4333
4653
|
{
|
|
4334
4654
|
"capId": "external-job",
|
|
@@ -4336,7 +4656,7 @@ const byLoopPoint = {
|
|
|
4336
4656
|
"into": "executor",
|
|
4337
4657
|
"fragment": {
|
|
4338
4658
|
"path": "fragments/execute-wave-post.md",
|
|
4339
|
-
"inline": "<!-- external-job capability — execute:wave:post fragment, injected into the executor (#1164).\n\n
|
|
4659
|
+
"inline": "<!-- external-job capability — execute:wave:post fragment, injected into the executor (#1164).\n\n #1164 specifies classification at wave:pre and recording at wave:post. This\n capability still contributes executor guidance at wave:post; execute-phase\n now renders wave:pre entries and dispatches generic step hooks there. Moving\n external-job classification is a separate capability change, not part of\n #4148. Until then, this guidance cannot classify the wave that already ran. -->\n\n## Externalize long-running compute (async external job)\n\nIf the current plan's task is tagged `<runtime_budget>long_compute</runtime_budget>`\n(see the plan-phase fragment), do **not** run it in the foreground — it would\nblock the agent turn for hours. Instead externalize it and record a durable\nhalf-state:\n\n1. **Classify the runtime.** `quick` (<2 min) and `medium` (<~30 min) run\n normally. `unknown` requires a first-health check and a soft-review deadline\n before consuming the child timeout. `long_compute` (>30–60 min) is\n externalized.\n2. **Submit via the scheduler adapter** (default `external_job.backend: slurm`):\n ```bash\n node scripts/slurm-adapter.cjs submit \\\n --plan <plan_id> --phase <phase> -- sbatch --parsable \\\n --output=Artifacts/jobs/%j/out.log ./run.sh\n ```\n The helper writes `.planning/async-jobs/<job>.json` (the versioned stability\n contract — `docs/reference/planning-artifacts.md`) and refuses to create a\n second non-terminal manifest for a `plan_id` that already has one\n (duplicate-execution guard).\n3. **Commit the manifest + a handoff**, then return **`external_job_waiting`**\n and stop. Do **not** write `SUMMARY.md` — SUMMARY is deferred until the job\n reaches a terminal state and its `expected_artifacts` are verified.\n4. **Resume path.** `execute-phase` safe-resume, `resume-project`, and\n `pause-work` reconcile against the manifest and never re-dispatch the plan.\n When the job is `completed-unverified`, run `verification_command` (surface\n it; it is untrusted — confirm before executing), then write `SUMMARY.md` and\n close the plan.\n\nManifest commands cross a trust seam: a Capability (or anything that can write\n`.planning/`) produces them; the core loop consumes them. Never auto-run\n`submit_command` / `verification_command` / `resume_command` — surface the exact\ncommand and require explicit confirmation first.\n"
|
|
4340
4660
|
},
|
|
4341
4661
|
"produces": [
|
|
4342
4662
|
".planning/async-jobs/<job>.json"
|
|
@@ -4409,6 +4729,7 @@ const byLoopPoint = {
|
|
|
4409
4729
|
"SUMMARY.md"
|
|
4410
4730
|
],
|
|
4411
4731
|
"when": "workflow.code_review",
|
|
4732
|
+
"pointFrom": "workflow.code_review_point",
|
|
4412
4733
|
"onError": "skip"
|
|
4413
4734
|
},
|
|
4414
4735
|
{
|
|
@@ -4580,19 +4901,33 @@ const configKeys = {
|
|
|
4580
4901
|
"workflow.ai_integration_phase": "ai-integration",
|
|
4581
4902
|
"workflow.api_coverage_gate": "ai-integration",
|
|
4582
4903
|
"review.models.agy": "antigravity",
|
|
4904
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": "antigravity",
|
|
4905
|
+
"review.timeouts.antigravity": "antigravity",
|
|
4583
4906
|
"workflow.assumption_delta": "assumption-delta",
|
|
4584
4907
|
"workflow.windows_enforce": "broken-windows",
|
|
4585
4908
|
"review.models.claude": "claude",
|
|
4909
|
+
"review.max_prompt_tokens_per_reviewer.claude": "claude",
|
|
4910
|
+
"review.timeouts.claude": "claude",
|
|
4911
|
+
"review.effort.claude": "claude",
|
|
4586
4912
|
"claude_orchestration.enabled": "claude-orchestration",
|
|
4587
4913
|
"claude_orchestration.execution_backend": "claude-orchestration",
|
|
4588
4914
|
"claude_orchestration.min_agent_sdk_version": "claude-orchestration",
|
|
4589
4915
|
"workflow.code_review": "code-review",
|
|
4590
4916
|
"workflow.code_review_depth": "code-review",
|
|
4917
|
+
"workflow.code_review_point": "code-review",
|
|
4918
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": "coderabbit",
|
|
4591
4919
|
"review.models.codex": "codex",
|
|
4920
|
+
"review.max_prompt_tokens_per_reviewer.codex": "codex",
|
|
4921
|
+
"review.timeouts.codex": "codex",
|
|
4922
|
+
"review.effort.codex": "codex",
|
|
4923
|
+
"review.models.cursor": "cursor",
|
|
4924
|
+
"review.max_prompt_tokens_per_reviewer.cursor": "cursor",
|
|
4592
4925
|
"workflow.drift_threshold": "drift",
|
|
4593
4926
|
"workflow.drift_action": "drift",
|
|
4594
4927
|
"workflow.schema_drift_gate": "drift",
|
|
4595
4928
|
"workflow.plan_drift_precheck": "drift",
|
|
4929
|
+
"workflow.context_drift_precheck": "drift",
|
|
4930
|
+
"workflow.context_drift_action": "drift",
|
|
4596
4931
|
"external_job.enabled": "external-job",
|
|
4597
4932
|
"external_job.backend": "external-job",
|
|
4598
4933
|
"external_job.artifact_dir": "external-job",
|
|
@@ -4600,15 +4935,22 @@ const configKeys = {
|
|
|
4600
4935
|
"external_job.poll_timeout_ms": "external-job",
|
|
4601
4936
|
"workflow.post_planning_gaps": "gap-analysis",
|
|
4602
4937
|
"review.models.gemini": "gemini",
|
|
4938
|
+
"review.max_prompt_tokens_per_reviewer.gemini": "gemini",
|
|
4939
|
+
"review.timeouts.gemini": "gemini",
|
|
4603
4940
|
"graphify.enabled": "graphify",
|
|
4604
4941
|
"intel.enabled": "intel",
|
|
4605
4942
|
"review.models.kimi-code": "kimi-code",
|
|
4943
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": "kimi-code",
|
|
4944
|
+
"review.timeouts.kimi-code": "kimi-code",
|
|
4945
|
+
"workflow.live_dom_uat": "live-dom-uat",
|
|
4606
4946
|
"review.models.llama_cpp": "llama-cpp",
|
|
4607
4947
|
"review.llama_cpp_host": "llama-cpp",
|
|
4608
4948
|
"review.max_prompt_tokens_per_reviewer.llama_cpp": "llama-cpp",
|
|
4949
|
+
"review.timeouts.llama_cpp": "llama-cpp",
|
|
4609
4950
|
"review.models.lm_studio": "lm-studio",
|
|
4610
4951
|
"review.lm_studio_host": "lm-studio",
|
|
4611
4952
|
"review.max_prompt_tokens_per_reviewer.lm_studio": "lm-studio",
|
|
4953
|
+
"review.timeouts.lm_studio": "lm-studio",
|
|
4612
4954
|
"mempalace.enabled": "mempalace",
|
|
4613
4955
|
"mempalace.memory_mode": "mempalace",
|
|
4614
4956
|
"mempalace.wing": "mempalace",
|
|
@@ -4623,9 +4965,14 @@ const configKeys = {
|
|
|
4623
4965
|
"review.models.ollama": "ollama",
|
|
4624
4966
|
"review.ollama_host": "ollama",
|
|
4625
4967
|
"review.max_prompt_tokens_per_reviewer.ollama": "ollama",
|
|
4968
|
+
"review.timeouts.ollama": "ollama",
|
|
4626
4969
|
"review.models.opencode": "opencode",
|
|
4970
|
+
"review.max_prompt_tokens_per_reviewer.opencode": "opencode",
|
|
4971
|
+
"review.timeouts.opencode": "opencode",
|
|
4972
|
+
"review.effort.opencode": "opencode",
|
|
4627
4973
|
"workflow.pattern_mapper": "pattern-mapper",
|
|
4628
4974
|
"profile-pipeline.enabled": "profile-pipeline",
|
|
4975
|
+
"review.max_prompt_tokens_per_reviewer.qwen": "qwen",
|
|
4629
4976
|
"refactor.trigger_enabled": "refactor-trigger",
|
|
4630
4977
|
"refactor.complexity_threshold": "refactor-trigger",
|
|
4631
4978
|
"refactor.complexity_jump_delta": "refactor-trigger",
|
|
@@ -4660,6 +5007,18 @@ const configSchema = {
|
|
|
4660
5007
|
"default": "",
|
|
4661
5008
|
"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
5009
|
},
|
|
5010
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
5011
|
+
"owner": "antigravity",
|
|
5012
|
+
"type": "number",
|
|
5013
|
+
"default": -1,
|
|
5014
|
+
"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."
|
|
5015
|
+
},
|
|
5016
|
+
"review.timeouts.antigravity": {
|
|
5017
|
+
"owner": "antigravity",
|
|
5018
|
+
"type": "number",
|
|
5019
|
+
"default": -1,
|
|
5020
|
+
"description": "Outer wall-clock timeout override (seconds) for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5021
|
+
},
|
|
4663
5022
|
"workflow.assumption_delta": {
|
|
4664
5023
|
"owner": "assumption-delta",
|
|
4665
5024
|
"type": "boolean",
|
|
@@ -4678,6 +5037,24 @@ const configSchema = {
|
|
|
4678
5037
|
"default": "",
|
|
4679
5038
|
"description": "Model passed to the Claude reviewer lane."
|
|
4680
5039
|
},
|
|
5040
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
5041
|
+
"owner": "claude",
|
|
5042
|
+
"type": "number",
|
|
5043
|
+
"default": -1,
|
|
5044
|
+
"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\"."
|
|
5045
|
+
},
|
|
5046
|
+
"review.timeouts.claude": {
|
|
5047
|
+
"owner": "claude",
|
|
5048
|
+
"type": "number",
|
|
5049
|
+
"default": -1,
|
|
5050
|
+
"description": "Outer wall-clock timeout override (seconds) for the Claude reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5051
|
+
},
|
|
5052
|
+
"review.effort.claude": {
|
|
5053
|
+
"owner": "claude",
|
|
5054
|
+
"type": "string",
|
|
5055
|
+
"default": "",
|
|
5056
|
+
"description": "Reasoning effort for the Claude reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
5057
|
+
},
|
|
4681
5058
|
"claude_orchestration.enabled": {
|
|
4682
5059
|
"owner": "claude-orchestration",
|
|
4683
5060
|
"type": "boolean",
|
|
@@ -4718,12 +5095,58 @@ const configSchema = {
|
|
|
4718
5095
|
"deep"
|
|
4719
5096
|
]
|
|
4720
5097
|
},
|
|
5098
|
+
"workflow.code_review_point": {
|
|
5099
|
+
"owner": "code-review",
|
|
5100
|
+
"type": "enum",
|
|
5101
|
+
"default": "execute:post",
|
|
5102
|
+
"description": "Loop point at which the code-review step registers — execute:post reviews once per phase (default); execute:wave:post reviews once per completed wave, scoped to that wave's diff.",
|
|
5103
|
+
"values": [
|
|
5104
|
+
"execute:post",
|
|
5105
|
+
"execute:wave:post"
|
|
5106
|
+
]
|
|
5107
|
+
},
|
|
5108
|
+
"review.max_prompt_tokens_per_reviewer.coderabbit": {
|
|
5109
|
+
"owner": "coderabbit",
|
|
5110
|
+
"type": "number",
|
|
5111
|
+
"default": -1,
|
|
5112
|
+
"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\"."
|
|
5113
|
+
},
|
|
4721
5114
|
"review.models.codex": {
|
|
4722
5115
|
"owner": "codex",
|
|
4723
5116
|
"type": "string",
|
|
4724
5117
|
"default": "",
|
|
4725
5118
|
"description": "Model passed to the Codex reviewer lane."
|
|
4726
5119
|
},
|
|
5120
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
5121
|
+
"owner": "codex",
|
|
5122
|
+
"type": "number",
|
|
5123
|
+
"default": -1,
|
|
5124
|
+
"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\"."
|
|
5125
|
+
},
|
|
5126
|
+
"review.timeouts.codex": {
|
|
5127
|
+
"owner": "codex",
|
|
5128
|
+
"type": "number",
|
|
5129
|
+
"default": -1,
|
|
5130
|
+
"description": "Outer wall-clock timeout override (seconds) for the Codex reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5131
|
+
},
|
|
5132
|
+
"review.effort.codex": {
|
|
5133
|
+
"owner": "codex",
|
|
5134
|
+
"type": "string",
|
|
5135
|
+
"default": "",
|
|
5136
|
+
"description": "Reasoning effort for the Codex reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
5137
|
+
},
|
|
5138
|
+
"review.models.cursor": {
|
|
5139
|
+
"owner": "cursor",
|
|
5140
|
+
"type": "string",
|
|
5141
|
+
"default": "",
|
|
5142
|
+
"description": "Model passed to the Cursor reviewer lane."
|
|
5143
|
+
},
|
|
5144
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
5145
|
+
"owner": "cursor",
|
|
5146
|
+
"type": "number",
|
|
5147
|
+
"default": -1,
|
|
5148
|
+
"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\"."
|
|
5149
|
+
},
|
|
4727
5150
|
"workflow.drift_threshold": {
|
|
4728
5151
|
"owner": "drift",
|
|
4729
5152
|
"type": "number",
|
|
@@ -4752,6 +5175,22 @@ const configSchema = {
|
|
|
4752
5175
|
"default": true,
|
|
4753
5176
|
"description": "Enable the non-blocking codebase drift pre-check at plan:pre, before /gsd:plan-phase spawns the planner. When enabled, a stale STRUCTURE.md (structural additions exceeding drift_threshold) is surfaced up front as a warn-only advisory pointing to /gsd:map-codebase; it never blocks planning and never spawns the mapper agent. Separate from schema_drift_gate so autonomous/CI runs can silence the plan-time advisory while keeping the execute:wave:post gates enabled."
|
|
4754
5177
|
},
|
|
5178
|
+
"workflow.context_drift_precheck": {
|
|
5179
|
+
"owner": "drift",
|
|
5180
|
+
"type": "boolean",
|
|
5181
|
+
"default": true,
|
|
5182
|
+
"description": "Enable the non-blocking context-drift pre-check at plan:pre, before /gsd:plan-phase reuses an existing RESEARCH.md/PATTERNS.md/VALIDATION.md/SPEC.md. Compares each artifact's effective last-changed time (git commit time, falling back to mtime for uncommitted edits) against CONTEXT.md's own — an artifact that predates CONTEXT.md's newest decision was derived from a premise that has since changed. Warn-only by default (see workflow.context_drift_action); never blocks planning on its own."
|
|
5183
|
+
},
|
|
5184
|
+
"workflow.context_drift_action": {
|
|
5185
|
+
"owner": "drift",
|
|
5186
|
+
"type": "enum",
|
|
5187
|
+
"default": "warn",
|
|
5188
|
+
"description": "Action taken by the context-drift gate when a stale upstream artifact is found: warn (advisory message naming the stale artifacts and how to regenerate them) or block (halt plan-phase until the artifacts are regenerated or the check is disabled).",
|
|
5189
|
+
"values": [
|
|
5190
|
+
"warn",
|
|
5191
|
+
"block"
|
|
5192
|
+
]
|
|
5193
|
+
},
|
|
4755
5194
|
"external_job.enabled": {
|
|
4756
5195
|
"owner": "external-job",
|
|
4757
5196
|
"type": "boolean",
|
|
@@ -4797,6 +5236,18 @@ const configSchema = {
|
|
|
4797
5236
|
"default": "",
|
|
4798
5237
|
"description": "Model passed to the Gemini reviewer lane."
|
|
4799
5238
|
},
|
|
5239
|
+
"review.max_prompt_tokens_per_reviewer.gemini": {
|
|
5240
|
+
"owner": "gemini",
|
|
5241
|
+
"type": "number",
|
|
5242
|
+
"default": -1,
|
|
5243
|
+
"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\"."
|
|
5244
|
+
},
|
|
5245
|
+
"review.timeouts.gemini": {
|
|
5246
|
+
"owner": "gemini",
|
|
5247
|
+
"type": "number",
|
|
5248
|
+
"default": -1,
|
|
5249
|
+
"description": "Outer wall-clock timeout override (seconds) for the Gemini reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5250
|
+
},
|
|
4800
5251
|
"graphify.enabled": {
|
|
4801
5252
|
"owner": "graphify",
|
|
4802
5253
|
"type": "boolean",
|
|
@@ -4815,6 +5266,24 @@ const configSchema = {
|
|
|
4815
5266
|
"default": "",
|
|
4816
5267
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
4817
5268
|
},
|
|
5269
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
5270
|
+
"owner": "kimi-code",
|
|
5271
|
+
"type": "number",
|
|
5272
|
+
"default": -1,
|
|
5273
|
+
"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\"."
|
|
5274
|
+
},
|
|
5275
|
+
"review.timeouts.kimi-code": {
|
|
5276
|
+
"owner": "kimi-code",
|
|
5277
|
+
"type": "number",
|
|
5278
|
+
"default": -1,
|
|
5279
|
+
"description": "Outer wall-clock timeout override (seconds) for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5280
|
+
},
|
|
5281
|
+
"workflow.live_dom_uat": {
|
|
5282
|
+
"owner": "live-dom-uat",
|
|
5283
|
+
"type": "boolean",
|
|
5284
|
+
"default": false,
|
|
5285
|
+
"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."
|
|
5286
|
+
},
|
|
4818
5287
|
"review.models.llama_cpp": {
|
|
4819
5288
|
"owner": "llama-cpp",
|
|
4820
5289
|
"type": "string",
|
|
@@ -4833,6 +5302,12 @@ const configSchema = {
|
|
|
4833
5302
|
"default": -1,
|
|
4834
5303
|
"description": "Prompt-token budget for the llama.cpp 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\"."
|
|
4835
5304
|
},
|
|
5305
|
+
"review.timeouts.llama_cpp": {
|
|
5306
|
+
"owner": "llama-cpp",
|
|
5307
|
+
"type": "number",
|
|
5308
|
+
"default": -1,
|
|
5309
|
+
"description": "Outer wall-clock timeout override (seconds) for the llama.cpp reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5310
|
+
},
|
|
4836
5311
|
"review.models.lm_studio": {
|
|
4837
5312
|
"owner": "lm-studio",
|
|
4838
5313
|
"type": "string",
|
|
@@ -4851,6 +5326,12 @@ const configSchema = {
|
|
|
4851
5326
|
"default": -1,
|
|
4852
5327
|
"description": "Prompt-token budget for the LM Studio 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\"."
|
|
4853
5328
|
},
|
|
5329
|
+
"review.timeouts.lm_studio": {
|
|
5330
|
+
"owner": "lm-studio",
|
|
5331
|
+
"type": "number",
|
|
5332
|
+
"default": -1,
|
|
5333
|
+
"description": "Outer wall-clock timeout override (seconds) for the LM Studio reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5334
|
+
},
|
|
4854
5335
|
"mempalace.enabled": {
|
|
4855
5336
|
"owner": "mempalace",
|
|
4856
5337
|
"type": "boolean",
|
|
@@ -4940,12 +5421,36 @@ const configSchema = {
|
|
|
4940
5421
|
"default": -1,
|
|
4941
5422
|
"description": "Prompt-token budget for the Ollama 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\"."
|
|
4942
5423
|
},
|
|
5424
|
+
"review.timeouts.ollama": {
|
|
5425
|
+
"owner": "ollama",
|
|
5426
|
+
"type": "number",
|
|
5427
|
+
"default": -1,
|
|
5428
|
+
"description": "Outer wall-clock timeout override (seconds) for the Ollama reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5429
|
+
},
|
|
4943
5430
|
"review.models.opencode": {
|
|
4944
5431
|
"owner": "opencode",
|
|
4945
5432
|
"type": "string",
|
|
4946
5433
|
"default": "",
|
|
4947
5434
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
4948
5435
|
},
|
|
5436
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
5437
|
+
"owner": "opencode",
|
|
5438
|
+
"type": "number",
|
|
5439
|
+
"default": -1,
|
|
5440
|
+
"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\"."
|
|
5441
|
+
},
|
|
5442
|
+
"review.timeouts.opencode": {
|
|
5443
|
+
"owner": "opencode",
|
|
5444
|
+
"type": "number",
|
|
5445
|
+
"default": -1,
|
|
5446
|
+
"description": "Outer wall-clock timeout override (seconds) for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5447
|
+
},
|
|
5448
|
+
"review.effort.opencode": {
|
|
5449
|
+
"owner": "opencode",
|
|
5450
|
+
"type": "string",
|
|
5451
|
+
"default": "",
|
|
5452
|
+
"description": "Reasoning effort for the OpenCode reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
5453
|
+
},
|
|
4949
5454
|
"workflow.pattern_mapper": {
|
|
4950
5455
|
"owner": "pattern-mapper",
|
|
4951
5456
|
"type": "boolean",
|
|
@@ -4958,6 +5463,12 @@ const configSchema = {
|
|
|
4958
5463
|
"default": false,
|
|
4959
5464
|
"description": "Enable the developer profiling pipeline commands (scan-sessions, extract-messages, profile-sample, write-profile, etc.)."
|
|
4960
5465
|
},
|
|
5466
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
5467
|
+
"owner": "qwen",
|
|
5468
|
+
"type": "number",
|
|
5469
|
+
"default": -1,
|
|
5470
|
+
"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\"."
|
|
5471
|
+
},
|
|
4961
5472
|
"refactor.trigger_enabled": {
|
|
4962
5473
|
"owner": "refactor-trigger",
|
|
4963
5474
|
"type": "boolean",
|
|
@@ -5049,9 +5560,9 @@ const runtimes = {
|
|
|
5049
5560
|
"antigravity": {
|
|
5050
5561
|
"id": "antigravity",
|
|
5051
5562
|
"role": "runtime",
|
|
5052
|
-
"version": "1.
|
|
5563
|
+
"version": "1.13.0",
|
|
5053
5564
|
"title": "Antigravity",
|
|
5054
|
-
"description": "Google Antigravity IDE — nested under ~/.gemini/antigravity
|
|
5565
|
+
"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
5566
|
"tier": "core",
|
|
5056
5567
|
"requires": [],
|
|
5057
5568
|
"engines": {
|
|
@@ -5082,7 +5593,8 @@ const runtimes = {
|
|
|
5082
5593
|
"prefix": "gsd-",
|
|
5083
5594
|
"nesting": "flat",
|
|
5084
5595
|
"recursive": false,
|
|
5085
|
-
"converter": "convertClaudeCommandToAntigravitySkill"
|
|
5596
|
+
"converter": "convertClaudeCommandToAntigravitySkill",
|
|
5597
|
+
"home": ".gemini/config"
|
|
5086
5598
|
},
|
|
5087
5599
|
{
|
|
5088
5600
|
"kind": "agents",
|
|
@@ -5090,7 +5602,8 @@ const runtimes = {
|
|
|
5090
5602
|
"prefix": "gsd-",
|
|
5091
5603
|
"nesting": "flat",
|
|
5092
5604
|
"recursive": false,
|
|
5093
|
-
"converter": "convertClaudeAgentToAntigravityAgent"
|
|
5605
|
+
"converter": "convertClaudeAgentToAntigravityAgent",
|
|
5606
|
+
"home": ".gemini/config"
|
|
5094
5607
|
}
|
|
5095
5608
|
],
|
|
5096
5609
|
"local": [
|
|
@@ -5135,7 +5648,8 @@ const runtimes = {
|
|
|
5135
5648
|
"background": true,
|
|
5136
5649
|
"subagentToolkit": "full",
|
|
5137
5650
|
"backgroundDispatch": "undocumented",
|
|
5138
|
-
"isolation": "undocumented"
|
|
5651
|
+
"isolation": "undocumented",
|
|
5652
|
+
"maxConcurrency": "undocumented"
|
|
5139
5653
|
},
|
|
5140
5654
|
"modelMode": "passive",
|
|
5141
5655
|
"hookBus": "host",
|
|
@@ -5166,7 +5680,7 @@ const runtimes = {
|
|
|
5166
5680
|
"binary": "agy",
|
|
5167
5681
|
"args": [
|
|
5168
5682
|
"--print-timeout",
|
|
5169
|
-
"
|
|
5683
|
+
"{{nativeTimeout}}",
|
|
5170
5684
|
"{{model}}",
|
|
5171
5685
|
"-p",
|
|
5172
5686
|
"{{prompt}}"
|
|
@@ -5177,12 +5691,15 @@ const runtimes = {
|
|
|
5177
5691
|
"effortChannel": "none"
|
|
5178
5692
|
},
|
|
5179
5693
|
"timeoutFloorMs": 600000,
|
|
5694
|
+
"timeoutConfigKey": "review.timeouts.antigravity",
|
|
5180
5695
|
"emptyOutput": "handler-owned",
|
|
5181
5696
|
"reviewsSection": "Antigravity",
|
|
5182
5697
|
"evidenceClass": "source-grounded",
|
|
5183
5698
|
"requiresBinaries": [],
|
|
5184
|
-
"promptBudgetKey":
|
|
5699
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.antigravity",
|
|
5185
5700
|
"modelConfigKey": "review.models.agy",
|
|
5701
|
+
"effortConfigKey": null,
|
|
5702
|
+
"defaultEffort": null,
|
|
5186
5703
|
"handler": "antigravity"
|
|
5187
5704
|
},
|
|
5188
5705
|
"config": {
|
|
@@ -5190,13 +5707,23 @@ const runtimes = {
|
|
|
5190
5707
|
"type": "string",
|
|
5191
5708
|
"default": "",
|
|
5192
5709
|
"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."
|
|
5710
|
+
},
|
|
5711
|
+
"review.max_prompt_tokens_per_reviewer.antigravity": {
|
|
5712
|
+
"type": "number",
|
|
5713
|
+
"default": -1,
|
|
5714
|
+
"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."
|
|
5715
|
+
},
|
|
5716
|
+
"review.timeouts.antigravity": {
|
|
5717
|
+
"type": "number",
|
|
5718
|
+
"default": -1,
|
|
5719
|
+
"description": "Outer wall-clock timeout override (seconds) for the Antigravity reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
5193
5720
|
}
|
|
5194
5721
|
}
|
|
5195
5722
|
},
|
|
5196
5723
|
"augment": {
|
|
5197
5724
|
"id": "augment",
|
|
5198
5725
|
"role": "runtime",
|
|
5199
|
-
"version": "1.
|
|
5726
|
+
"version": "1.13.0",
|
|
5200
5727
|
"title": "Augment Code",
|
|
5201
5728
|
"description": "Augment Code CLI — commands + nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
5202
5729
|
"tier": "core",
|
|
@@ -5295,7 +5822,8 @@ const runtimes = {
|
|
|
5295
5822
|
"background": true,
|
|
5296
5823
|
"subagentToolkit": "full",
|
|
5297
5824
|
"backgroundDispatch": "undocumented",
|
|
5298
|
-
"isolation": "undocumented"
|
|
5825
|
+
"isolation": "undocumented",
|
|
5826
|
+
"maxConcurrency": "undocumented"
|
|
5299
5827
|
},
|
|
5300
5828
|
"modelMode": "passive",
|
|
5301
5829
|
"hookBus": "host",
|
|
@@ -5309,7 +5837,7 @@ const runtimes = {
|
|
|
5309
5837
|
"claude": {
|
|
5310
5838
|
"id": "claude",
|
|
5311
5839
|
"role": "runtime",
|
|
5312
|
-
"version": "1.
|
|
5840
|
+
"version": "1.13.0",
|
|
5313
5841
|
"title": "Claude Code",
|
|
5314
5842
|
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
|
5315
5843
|
"tier": "core",
|
|
@@ -5393,7 +5921,8 @@ const runtimes = {
|
|
|
5393
5921
|
"background": true,
|
|
5394
5922
|
"subagentToolkit": "full",
|
|
5395
5923
|
"backgroundDispatch": false,
|
|
5396
|
-
"isolation": "harness-worktree"
|
|
5924
|
+
"isolation": "harness-worktree",
|
|
5925
|
+
"maxConcurrency": 20
|
|
5397
5926
|
},
|
|
5398
5927
|
"modelMode": "passive",
|
|
5399
5928
|
"hookBus": "host",
|
|
@@ -5452,12 +5981,15 @@ const runtimes = {
|
|
|
5452
5981
|
}
|
|
5453
5982
|
},
|
|
5454
5983
|
"timeoutFloorMs": 1200000,
|
|
5984
|
+
"timeoutConfigKey": "review.timeouts.claude",
|
|
5455
5985
|
"emptyOutput": "stub-with-stderr",
|
|
5456
5986
|
"reviewsSection": "Claude",
|
|
5457
5987
|
"evidenceClass": "source-grounded",
|
|
5458
5988
|
"requiresBinaries": [],
|
|
5459
|
-
"promptBudgetKey":
|
|
5989
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.claude",
|
|
5460
5990
|
"modelConfigKey": "review.models.claude",
|
|
5991
|
+
"effortConfigKey": "review.effort.claude",
|
|
5992
|
+
"defaultEffort": "high",
|
|
5461
5993
|
"handler": null
|
|
5462
5994
|
},
|
|
5463
5995
|
"config": {
|
|
@@ -5465,13 +5997,28 @@ const runtimes = {
|
|
|
5465
5997
|
"type": "string",
|
|
5466
5998
|
"default": "",
|
|
5467
5999
|
"description": "Model passed to the Claude reviewer lane."
|
|
6000
|
+
},
|
|
6001
|
+
"review.max_prompt_tokens_per_reviewer.claude": {
|
|
6002
|
+
"type": "number",
|
|
6003
|
+
"default": -1,
|
|
6004
|
+
"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\"."
|
|
6005
|
+
},
|
|
6006
|
+
"review.timeouts.claude": {
|
|
6007
|
+
"type": "number",
|
|
6008
|
+
"default": -1,
|
|
6009
|
+
"description": "Outer wall-clock timeout override (seconds) for the Claude reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
6010
|
+
},
|
|
6011
|
+
"review.effort.claude": {
|
|
6012
|
+
"type": "string",
|
|
6013
|
+
"default": "",
|
|
6014
|
+
"description": "Reasoning effort for the Claude reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
5468
6015
|
}
|
|
5469
6016
|
}
|
|
5470
6017
|
},
|
|
5471
6018
|
"cline": {
|
|
5472
6019
|
"id": "cline",
|
|
5473
6020
|
"role": "runtime",
|
|
5474
|
-
"version": "1.
|
|
6021
|
+
"version": "1.13.0",
|
|
5475
6022
|
"title": "Cline",
|
|
5476
6023
|
"description": "Cline (VS Code extension) — global-only nested-skill layout; cline-rules hook surface (.clinerules); no hook events emitted; tier-2 support.",
|
|
5477
6024
|
"tier": "core",
|
|
@@ -5541,7 +6088,8 @@ const runtimes = {
|
|
|
5541
6088
|
"background": true,
|
|
5542
6089
|
"subagentToolkit": "read-only",
|
|
5543
6090
|
"backgroundDispatch": false,
|
|
5544
|
-
"isolation": "undocumented"
|
|
6091
|
+
"isolation": "undocumented",
|
|
6092
|
+
"maxConcurrency": "undocumented"
|
|
5545
6093
|
},
|
|
5546
6094
|
"modelMode": "active",
|
|
5547
6095
|
"hookBus": "host",
|
|
@@ -5563,7 +6111,7 @@ const runtimes = {
|
|
|
5563
6111
|
"codebuddy": {
|
|
5564
6112
|
"id": "codebuddy",
|
|
5565
6113
|
"role": "runtime",
|
|
5566
|
-
"version": "1.
|
|
6114
|
+
"version": "1.13.0",
|
|
5567
6115
|
"title": "CodeBuddy",
|
|
5568
6116
|
"description": "CodeBuddy (Tencent) — converted commands + skills artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
5569
6117
|
"tier": "core",
|
|
@@ -5663,7 +6211,8 @@ const runtimes = {
|
|
|
5663
6211
|
"background": true,
|
|
5664
6212
|
"subagentToolkit": "full",
|
|
5665
6213
|
"backgroundDispatch": false,
|
|
5666
|
-
"isolation": "undocumented"
|
|
6214
|
+
"isolation": "undocumented",
|
|
6215
|
+
"maxConcurrency": "undocumented"
|
|
5667
6216
|
},
|
|
5668
6217
|
"modelMode": "passive",
|
|
5669
6218
|
"hookBus": "host",
|
|
@@ -5680,7 +6229,7 @@ const runtimes = {
|
|
|
5680
6229
|
"codex": {
|
|
5681
6230
|
"id": "codex",
|
|
5682
6231
|
"role": "runtime",
|
|
5683
|
-
"version": "1.
|
|
6232
|
+
"version": "1.13.0",
|
|
5684
6233
|
"title": "OpenAI Codex CLI",
|
|
5685
6234
|
"description": "OpenAI Codex CLI — shell-var command style; per-agent sandbox tiers; config.toml + hooks.json hook surface; tier-1 support.",
|
|
5686
6235
|
"tier": "core",
|
|
@@ -5764,7 +6313,8 @@ const runtimes = {
|
|
|
5764
6313
|
"background": true,
|
|
5765
6314
|
"subagentToolkit": "full",
|
|
5766
6315
|
"backgroundDispatch": true,
|
|
5767
|
-
"isolation": "orchestrator-worktree"
|
|
6316
|
+
"isolation": "orchestrator-worktree",
|
|
6317
|
+
"maxConcurrency": "undocumented"
|
|
5768
6318
|
},
|
|
5769
6319
|
"modelMode": "passive",
|
|
5770
6320
|
"hookBus": "host",
|
|
@@ -5779,7 +6329,8 @@ const runtimes = {
|
|
|
5779
6329
|
"exec"
|
|
5780
6330
|
],
|
|
5781
6331
|
"cwdFlag": "--cd",
|
|
5782
|
-
"promptFlag": null
|
|
6332
|
+
"promptFlag": null,
|
|
6333
|
+
"modelFlag": "--model"
|
|
5783
6334
|
},
|
|
5784
6335
|
"hostBehaviors": {
|
|
5785
6336
|
"reapplyCommand": "$gsd-update --reapply",
|
|
@@ -5817,12 +6368,15 @@ const runtimes = {
|
|
|
5817
6368
|
"effortChannel": "argv"
|
|
5818
6369
|
},
|
|
5819
6370
|
"timeoutFloorMs": 1200000,
|
|
6371
|
+
"timeoutConfigKey": "review.timeouts.codex",
|
|
5820
6372
|
"emptyOutput": "stub-with-stderr",
|
|
5821
6373
|
"reviewsSection": "Codex",
|
|
5822
6374
|
"evidenceClass": "source-grounded",
|
|
5823
6375
|
"requiresBinaries": [],
|
|
5824
|
-
"promptBudgetKey":
|
|
6376
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.codex",
|
|
5825
6377
|
"modelConfigKey": "review.models.codex",
|
|
6378
|
+
"effortConfigKey": "review.effort.codex",
|
|
6379
|
+
"defaultEffort": "high",
|
|
5826
6380
|
"handler": null
|
|
5827
6381
|
},
|
|
5828
6382
|
"config": {
|
|
@@ -5830,13 +6384,28 @@ const runtimes = {
|
|
|
5830
6384
|
"type": "string",
|
|
5831
6385
|
"default": "",
|
|
5832
6386
|
"description": "Model passed to the Codex reviewer lane."
|
|
6387
|
+
},
|
|
6388
|
+
"review.max_prompt_tokens_per_reviewer.codex": {
|
|
6389
|
+
"type": "number",
|
|
6390
|
+
"default": -1,
|
|
6391
|
+
"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\"."
|
|
6392
|
+
},
|
|
6393
|
+
"review.timeouts.codex": {
|
|
6394
|
+
"type": "number",
|
|
6395
|
+
"default": -1,
|
|
6396
|
+
"description": "Outer wall-clock timeout override (seconds) for the Codex reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
6397
|
+
},
|
|
6398
|
+
"review.effort.codex": {
|
|
6399
|
+
"type": "string",
|
|
6400
|
+
"default": "",
|
|
6401
|
+
"description": "Reasoning effort for the Codex reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
5833
6402
|
}
|
|
5834
6403
|
}
|
|
5835
6404
|
},
|
|
5836
6405
|
"copilot": {
|
|
5837
6406
|
"id": "copilot",
|
|
5838
6407
|
"role": "runtime",
|
|
5839
|
-
"version": "1.
|
|
6408
|
+
"version": "1.13.0",
|
|
5840
6409
|
"title": "GitHub Copilot",
|
|
5841
6410
|
"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
6411
|
"tier": "core",
|
|
@@ -5915,7 +6484,8 @@ const runtimes = {
|
|
|
5915
6484
|
"background": true,
|
|
5916
6485
|
"subagentToolkit": "full",
|
|
5917
6486
|
"backgroundDispatch": false,
|
|
5918
|
-
"isolation": "undocumented"
|
|
6487
|
+
"isolation": "undocumented",
|
|
6488
|
+
"maxConcurrency": "undocumented"
|
|
5919
6489
|
},
|
|
5920
6490
|
"modelMode": "passive",
|
|
5921
6491
|
"hookBus": "host",
|
|
@@ -5935,7 +6505,7 @@ const runtimes = {
|
|
|
5935
6505
|
"cursor": {
|
|
5936
6506
|
"id": "cursor",
|
|
5937
6507
|
"role": "runtime",
|
|
5938
|
-
"version": "1.
|
|
6508
|
+
"version": "1.13.0",
|
|
5939
6509
|
"title": "Cursor",
|
|
5940
6510
|
"description": "Cursor IDE — skills-only workflow surface; hooks.json surface; Claude hook event dialect; recursive skill loader (flat nesting); tier-2 support.",
|
|
5941
6511
|
"tier": "core",
|
|
@@ -6014,7 +6584,8 @@ const runtimes = {
|
|
|
6014
6584
|
"background": true,
|
|
6015
6585
|
"subagentToolkit": "full",
|
|
6016
6586
|
"backgroundDispatch": true,
|
|
6017
|
-
"isolation": "harness-worktree"
|
|
6587
|
+
"isolation": "harness-worktree",
|
|
6588
|
+
"maxConcurrency": "undocumented"
|
|
6018
6589
|
},
|
|
6019
6590
|
"modelMode": "passive",
|
|
6020
6591
|
"hookBus": "host",
|
|
@@ -6062,6 +6633,7 @@ const runtimes = {
|
|
|
6062
6633
|
"binary": "cursor-agent",
|
|
6063
6634
|
"args": [
|
|
6064
6635
|
"-p",
|
|
6636
|
+
"{{model}}",
|
|
6065
6637
|
"--mode",
|
|
6066
6638
|
"ask",
|
|
6067
6639
|
"--trust",
|
|
@@ -6071,23 +6643,38 @@ const runtimes = {
|
|
|
6071
6643
|
],
|
|
6072
6644
|
"promptChannel": "argv-file-ref",
|
|
6073
6645
|
"outputChannel": "stdout",
|
|
6074
|
-
"modelArg":
|
|
6646
|
+
"modelArg": "--model",
|
|
6075
6647
|
"effortChannel": "none"
|
|
6076
6648
|
},
|
|
6077
6649
|
"timeoutFloorMs": 900000,
|
|
6650
|
+
"timeoutConfigKey": null,
|
|
6078
6651
|
"emptyOutput": "stub-with-stderr",
|
|
6079
6652
|
"reviewsSection": "Cursor",
|
|
6080
6653
|
"evidenceClass": "source-grounded",
|
|
6081
6654
|
"requiresBinaries": [],
|
|
6082
|
-
"promptBudgetKey":
|
|
6083
|
-
"modelConfigKey":
|
|
6655
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
|
6656
|
+
"modelConfigKey": "review.models.cursor",
|
|
6657
|
+
"effortConfigKey": null,
|
|
6658
|
+
"defaultEffort": null,
|
|
6084
6659
|
"handler": null
|
|
6660
|
+
},
|
|
6661
|
+
"config": {
|
|
6662
|
+
"review.models.cursor": {
|
|
6663
|
+
"type": "string",
|
|
6664
|
+
"default": "",
|
|
6665
|
+
"description": "Model passed to the Cursor reviewer lane."
|
|
6666
|
+
},
|
|
6667
|
+
"review.max_prompt_tokens_per_reviewer.cursor": {
|
|
6668
|
+
"type": "number",
|
|
6669
|
+
"default": -1,
|
|
6670
|
+
"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\"."
|
|
6671
|
+
}
|
|
6085
6672
|
}
|
|
6086
6673
|
},
|
|
6087
6674
|
"hermes": {
|
|
6088
6675
|
"id": "hermes",
|
|
6089
6676
|
"role": "runtime",
|
|
6090
|
-
"version": "1.
|
|
6677
|
+
"version": "1.13.0",
|
|
6091
6678
|
"title": "Hermes Agent",
|
|
6092
6679
|
"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
6680
|
"tier": "core",
|
|
@@ -6184,7 +6771,8 @@ const runtimes = {
|
|
|
6184
6771
|
"background": true,
|
|
6185
6772
|
"subagentToolkit": "read-only",
|
|
6186
6773
|
"backgroundDispatch": false,
|
|
6187
|
-
"isolation": "undocumented"
|
|
6774
|
+
"isolation": "undocumented",
|
|
6775
|
+
"maxConcurrency": "undocumented"
|
|
6188
6776
|
},
|
|
6189
6777
|
"modelMode": "active",
|
|
6190
6778
|
"hookBus": "host",
|
|
@@ -6198,7 +6786,7 @@ const runtimes = {
|
|
|
6198
6786
|
"kilo": {
|
|
6199
6787
|
"id": "kilo",
|
|
6200
6788
|
"role": "runtime",
|
|
6201
|
-
"version": "1.
|
|
6789
|
+
"version": "1.13.0",
|
|
6202
6790
|
"title": "Kilo Code",
|
|
6203
6791
|
"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
6792
|
"tier": "core",
|
|
@@ -6300,7 +6888,8 @@ const runtimes = {
|
|
|
6300
6888
|
"background": true,
|
|
6301
6889
|
"subagentToolkit": "undocumented",
|
|
6302
6890
|
"backgroundDispatch": false,
|
|
6303
|
-
"isolation": "undocumented"
|
|
6891
|
+
"isolation": "undocumented",
|
|
6892
|
+
"maxConcurrency": "undocumented"
|
|
6304
6893
|
},
|
|
6305
6894
|
"modelMode": "active",
|
|
6306
6895
|
"hookBus": "host",
|
|
@@ -6327,7 +6916,7 @@ const runtimes = {
|
|
|
6327
6916
|
"kimi": {
|
|
6328
6917
|
"id": "kimi",
|
|
6329
6918
|
"role": "runtime",
|
|
6330
|
-
"version": "1.
|
|
6919
|
+
"version": "1.13.0",
|
|
6331
6920
|
"title": "Kimi CLI",
|
|
6332
6921
|
"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
6922
|
"tier": "core",
|
|
@@ -6399,7 +6988,8 @@ const runtimes = {
|
|
|
6399
6988
|
"background": true,
|
|
6400
6989
|
"subagentToolkit": "undocumented",
|
|
6401
6990
|
"backgroundDispatch": true,
|
|
6402
|
-
"isolation": "orchestrator-worktree"
|
|
6991
|
+
"isolation": "orchestrator-worktree",
|
|
6992
|
+
"maxConcurrency": "undocumented"
|
|
6403
6993
|
},
|
|
6404
6994
|
"modelMode": "passive",
|
|
6405
6995
|
"hookBus": "host",
|
|
@@ -6422,14 +7012,15 @@ const runtimes = {
|
|
|
6422
7012
|
"verificationStyle": "kimi",
|
|
6423
7013
|
"agentManifestStyle": "kimi-nested",
|
|
6424
7014
|
"doneBannerStyle": "kimi-agent-file",
|
|
6425
|
-
"skipSharedHooksInstall": true
|
|
7015
|
+
"skipSharedHooksInstall": true,
|
|
7016
|
+
"noPathRewrite": true
|
|
6426
7017
|
}
|
|
6427
7018
|
}
|
|
6428
7019
|
},
|
|
6429
7020
|
"kimi-code": {
|
|
6430
7021
|
"id": "kimi-code",
|
|
6431
7022
|
"role": "runtime",
|
|
6432
|
-
"version": "1.
|
|
7023
|
+
"version": "1.13.0",
|
|
6433
7024
|
"title": "Kimi Code CLI",
|
|
6434
7025
|
"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
7026
|
"tier": "core",
|
|
@@ -6514,7 +7105,8 @@ const runtimes = {
|
|
|
6514
7105
|
"explore",
|
|
6515
7106
|
"plan"
|
|
6516
7107
|
],
|
|
6517
|
-
"isolation": "orchestrator-worktree"
|
|
7108
|
+
"isolation": "orchestrator-worktree",
|
|
7109
|
+
"maxConcurrency": "undocumented"
|
|
6518
7110
|
},
|
|
6519
7111
|
"modelMode": "passive",
|
|
6520
7112
|
"hookBus": "host",
|
|
@@ -6563,12 +7155,15 @@ const runtimes = {
|
|
|
6563
7155
|
"effortChannel": "none"
|
|
6564
7156
|
},
|
|
6565
7157
|
"timeoutFloorMs": 900000,
|
|
7158
|
+
"timeoutConfigKey": "review.timeouts.kimi-code",
|
|
6566
7159
|
"emptyOutput": "stub-with-stderr",
|
|
6567
7160
|
"reviewsSection": "Kimi Code",
|
|
6568
7161
|
"evidenceClass": "source-grounded",
|
|
6569
7162
|
"requiresBinaries": [],
|
|
6570
|
-
"promptBudgetKey":
|
|
7163
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.kimi-code",
|
|
6571
7164
|
"modelConfigKey": "review.models.kimi-code",
|
|
7165
|
+
"effortConfigKey": null,
|
|
7166
|
+
"defaultEffort": null,
|
|
6572
7167
|
"handler": null
|
|
6573
7168
|
},
|
|
6574
7169
|
"config": {
|
|
@@ -6576,13 +7171,23 @@ const runtimes = {
|
|
|
6576
7171
|
"type": "string",
|
|
6577
7172
|
"default": "",
|
|
6578
7173
|
"description": "Model passed to the Kimi Code reviewer lane."
|
|
7174
|
+
},
|
|
7175
|
+
"review.max_prompt_tokens_per_reviewer.kimi-code": {
|
|
7176
|
+
"type": "number",
|
|
7177
|
+
"default": -1,
|
|
7178
|
+
"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\"."
|
|
7179
|
+
},
|
|
7180
|
+
"review.timeouts.kimi-code": {
|
|
7181
|
+
"type": "number",
|
|
7182
|
+
"default": -1,
|
|
7183
|
+
"description": "Outer wall-clock timeout override (seconds) for the Kimi Code reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
6579
7184
|
}
|
|
6580
7185
|
}
|
|
6581
7186
|
},
|
|
6582
7187
|
"opencode": {
|
|
6583
7188
|
"id": "opencode",
|
|
6584
7189
|
"role": "runtime",
|
|
6585
|
-
"version": "1.
|
|
7190
|
+
"version": "1.13.0",
|
|
6586
7191
|
"title": "OpenCode",
|
|
6587
7192
|
"description": "OpenCode — XDG-based config dir; flat commands/ + skills artifact layout; settings-json config format; no lifecycle hook registration; tier-2 support.",
|
|
6588
7193
|
"tier": "core",
|
|
@@ -6679,7 +7284,8 @@ const runtimes = {
|
|
|
6679
7284
|
"background": false,
|
|
6680
7285
|
"subagentToolkit": "full",
|
|
6681
7286
|
"backgroundDispatch": false,
|
|
6682
|
-
"isolation": "orchestrator-worktree"
|
|
7287
|
+
"isolation": "orchestrator-worktree",
|
|
7288
|
+
"maxConcurrency": "undocumented"
|
|
6683
7289
|
},
|
|
6684
7290
|
"modelMode": "active",
|
|
6685
7291
|
"hookBus": "host",
|
|
@@ -6739,12 +7345,15 @@ const runtimes = {
|
|
|
6739
7345
|
"effortChannel": "argv"
|
|
6740
7346
|
},
|
|
6741
7347
|
"timeoutFloorMs": 660000,
|
|
7348
|
+
"timeoutConfigKey": "review.timeouts.opencode",
|
|
6742
7349
|
"emptyOutput": "stub-with-stderr",
|
|
6743
7350
|
"reviewsSection": "OpenCode",
|
|
6744
7351
|
"evidenceClass": "source-grounded",
|
|
6745
7352
|
"requiresBinaries": [],
|
|
6746
|
-
"promptBudgetKey":
|
|
7353
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.opencode",
|
|
6747
7354
|
"modelConfigKey": "review.models.opencode",
|
|
7355
|
+
"effortConfigKey": "review.effort.opencode",
|
|
7356
|
+
"defaultEffort": "high",
|
|
6748
7357
|
"handler": "opencode"
|
|
6749
7358
|
},
|
|
6750
7359
|
"config": {
|
|
@@ -6752,13 +7361,28 @@ const runtimes = {
|
|
|
6752
7361
|
"type": "string",
|
|
6753
7362
|
"default": "",
|
|
6754
7363
|
"description": "Model passed to the OpenCode reviewer lane."
|
|
7364
|
+
},
|
|
7365
|
+
"review.max_prompt_tokens_per_reviewer.opencode": {
|
|
7366
|
+
"type": "number",
|
|
7367
|
+
"default": -1,
|
|
7368
|
+
"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\"."
|
|
7369
|
+
},
|
|
7370
|
+
"review.timeouts.opencode": {
|
|
7371
|
+
"type": "number",
|
|
7372
|
+
"default": -1,
|
|
7373
|
+
"description": "Outer wall-clock timeout override (seconds) for the OpenCode reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
|
7374
|
+
},
|
|
7375
|
+
"review.effort.opencode": {
|
|
7376
|
+
"type": "string",
|
|
7377
|
+
"default": "",
|
|
7378
|
+
"description": "Reasoning effort for the OpenCode reviewer lane: minimal, low, medium, high, xhigh, max, or inherit. Unset falls back to the lane's declared review default (high); inherit emits no effort argument so the CLI's own configuration decides. An unrecognized value falls back to the lane default rather than being forwarded."
|
|
6755
7379
|
}
|
|
6756
7380
|
}
|
|
6757
7381
|
},
|
|
6758
7382
|
"pi": {
|
|
6759
7383
|
"id": "pi",
|
|
6760
7384
|
"role": "runtime",
|
|
6761
|
-
"version": "1.
|
|
7385
|
+
"version": "1.13.0",
|
|
6762
7386
|
"title": "pi",
|
|
6763
7387
|
"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
7388
|
"tier": "core",
|
|
@@ -6804,7 +7428,8 @@ const runtimes = {
|
|
|
6804
7428
|
"background": false,
|
|
6805
7429
|
"backgroundDispatch": false,
|
|
6806
7430
|
"subagentToolkit": "undocumented",
|
|
6807
|
-
"isolation": "none"
|
|
7431
|
+
"isolation": "none",
|
|
7432
|
+
"maxConcurrency": "undocumented"
|
|
6808
7433
|
},
|
|
6809
7434
|
"modelMode": "active",
|
|
6810
7435
|
"hookBus": "host",
|
|
@@ -6827,7 +7452,7 @@ const runtimes = {
|
|
|
6827
7452
|
"qwen": {
|
|
6828
7453
|
"id": "qwen",
|
|
6829
7454
|
"role": "runtime",
|
|
6830
|
-
"version": "1.
|
|
7455
|
+
"version": "1.13.0",
|
|
6831
7456
|
"title": "Qwen Code",
|
|
6832
7457
|
"description": "Qwen Code (Alibaba) — nested-skill artifact layout; settings-json hook surface; Claude hook event dialect; tier-2 support.",
|
|
6833
7458
|
"tier": "core",
|
|
@@ -6911,7 +7536,8 @@ const runtimes = {
|
|
|
6911
7536
|
"background": true,
|
|
6912
7537
|
"subagentToolkit": "full",
|
|
6913
7538
|
"backgroundDispatch": false,
|
|
6914
|
-
"isolation": "undocumented"
|
|
7539
|
+
"isolation": "undocumented",
|
|
7540
|
+
"maxConcurrency": "undocumented"
|
|
6915
7541
|
},
|
|
6916
7542
|
"modelMode": "passive",
|
|
6917
7543
|
"hookBus": "host",
|
|
@@ -6954,19 +7580,29 @@ const runtimes = {
|
|
|
6954
7580
|
"effortChannel": "none"
|
|
6955
7581
|
},
|
|
6956
7582
|
"timeoutFloorMs": 900000,
|
|
7583
|
+
"timeoutConfigKey": null,
|
|
6957
7584
|
"emptyOutput": "stub-with-stderr",
|
|
6958
7585
|
"reviewsSection": "Qwen",
|
|
6959
7586
|
"evidenceClass": "source-grounded",
|
|
6960
7587
|
"requiresBinaries": [],
|
|
6961
|
-
"promptBudgetKey":
|
|
7588
|
+
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.qwen",
|
|
6962
7589
|
"modelConfigKey": null,
|
|
7590
|
+
"effortConfigKey": null,
|
|
7591
|
+
"defaultEffort": null,
|
|
6963
7592
|
"handler": null
|
|
7593
|
+
},
|
|
7594
|
+
"config": {
|
|
7595
|
+
"review.max_prompt_tokens_per_reviewer.qwen": {
|
|
7596
|
+
"type": "number",
|
|
7597
|
+
"default": -1,
|
|
7598
|
+
"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\"."
|
|
7599
|
+
}
|
|
6964
7600
|
}
|
|
6965
7601
|
},
|
|
6966
7602
|
"trae": {
|
|
6967
7603
|
"id": "trae",
|
|
6968
7604
|
"role": "runtime",
|
|
6969
|
-
"version": "1.
|
|
7605
|
+
"version": "1.13.0",
|
|
6970
7606
|
"title": "Trae IDE",
|
|
6971
7607
|
"description": "Trae IDE — nested-skill artifact layout; no hook surface (profile-marker-only config); tier-2 support.",
|
|
6972
7608
|
"tier": "core",
|
|
@@ -7044,7 +7680,8 @@ const runtimes = {
|
|
|
7044
7680
|
"background": true,
|
|
7045
7681
|
"subagentToolkit": "undocumented",
|
|
7046
7682
|
"backgroundDispatch": "undocumented",
|
|
7047
|
-
"isolation": "undocumented"
|
|
7683
|
+
"isolation": "undocumented",
|
|
7684
|
+
"maxConcurrency": "undocumented"
|
|
7048
7685
|
},
|
|
7049
7686
|
"modelMode": "passive",
|
|
7050
7687
|
"hookBus": "engine",
|
|
@@ -7063,7 +7700,7 @@ const runtimes = {
|
|
|
7063
7700
|
"vscode": {
|
|
7064
7701
|
"id": "vscode",
|
|
7065
7702
|
"role": "runtime",
|
|
7066
|
-
"version": "1.
|
|
7703
|
+
"version": "1.13.0",
|
|
7067
7704
|
"title": "VS Code",
|
|
7068
7705
|
"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
7706
|
"tier": "core",
|
|
@@ -7106,7 +7743,8 @@ const runtimes = {
|
|
|
7106
7743
|
"background": true,
|
|
7107
7744
|
"subagentToolkit": "undocumented",
|
|
7108
7745
|
"backgroundDispatch": "undocumented",
|
|
7109
|
-
"isolation": "undocumented"
|
|
7746
|
+
"isolation": "undocumented",
|
|
7747
|
+
"maxConcurrency": "undocumented"
|
|
7110
7748
|
},
|
|
7111
7749
|
"modelMode": "active",
|
|
7112
7750
|
"hookBus": "engine",
|
|
@@ -7120,7 +7758,7 @@ const runtimes = {
|
|
|
7120
7758
|
"windsurf": {
|
|
7121
7759
|
"id": "windsurf",
|
|
7122
7760
|
"role": "runtime",
|
|
7123
|
-
"version": "1.
|
|
7761
|
+
"version": "1.13.0",
|
|
7124
7762
|
"title": "Windsurf",
|
|
7125
7763
|
"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
7764
|
"tier": "core",
|
|
@@ -7191,7 +7829,8 @@ const runtimes = {
|
|
|
7191
7829
|
"background": "undocumented",
|
|
7192
7830
|
"subagentToolkit": "undocumented",
|
|
7193
7831
|
"backgroundDispatch": "undocumented",
|
|
7194
|
-
"isolation": "none"
|
|
7832
|
+
"isolation": "none",
|
|
7833
|
+
"maxConcurrency": "undocumented"
|
|
7195
7834
|
},
|
|
7196
7835
|
"modelMode": "passive",
|
|
7197
7836
|
"hookBus": "host",
|
|
@@ -7211,7 +7850,7 @@ const runtimes = {
|
|
|
7211
7850
|
"zcode": {
|
|
7212
7851
|
"id": "zcode",
|
|
7213
7852
|
"role": "runtime",
|
|
7214
|
-
"version": "1.
|
|
7853
|
+
"version": "1.13.0",
|
|
7215
7854
|
"title": "ZCode",
|
|
7216
7855
|
"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
7856
|
"tier": "core",
|
|
@@ -7305,7 +7944,8 @@ const runtimes = {
|
|
|
7305
7944
|
"background": false,
|
|
7306
7945
|
"subagentToolkit": "full",
|
|
7307
7946
|
"backgroundDispatch": false,
|
|
7308
|
-
"isolation": "none"
|
|
7947
|
+
"isolation": "none",
|
|
7948
|
+
"maxConcurrency": "undocumented"
|
|
7309
7949
|
},
|
|
7310
7950
|
"modelMode": "passive",
|
|
7311
7951
|
"hookBus": "host",
|
|
@@ -7500,6 +8140,7 @@ const _requiresGraph = {
|
|
|
7500
8140
|
"kilo": [],
|
|
7501
8141
|
"kimi": [],
|
|
7502
8142
|
"kimi-code": [],
|
|
8143
|
+
"live-dom-uat": [],
|
|
7503
8144
|
"llama-cpp": [],
|
|
7504
8145
|
"lm-studio": [],
|
|
7505
8146
|
"mempalace": [],
|