@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.3

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.
Files changed (69) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/gsd-mempalace-curator.md +47 -0
  3. package/bin/install.js +25 -7
  4. package/commands/gsd/mempalace-capture.md +71 -0
  5. package/commands/gsd/mempalace-recall.md +102 -0
  6. package/commands/gsd/ns-context.md +4 -2
  7. package/gemini-extension.json +1 -1
  8. package/gsd-core/bin/gsd-tools.cjs +110 -92
  9. package/gsd-core/bin/lib/capability-activation.cjs +86 -0
  10. package/gsd-core/bin/lib/capability-registry.cjs +1468 -11
  11. package/gsd-core/bin/lib/capability-state.cjs +31 -18
  12. package/gsd-core/bin/lib/check-command-router.cjs +328 -1
  13. package/gsd-core/bin/lib/clusters.cjs +2 -0
  14. package/gsd-core/bin/lib/command-roster.cjs +19 -0
  15. package/gsd-core/bin/lib/commands.cjs +33 -10
  16. package/gsd-core/bin/lib/config-loader.cjs +7 -8
  17. package/gsd-core/bin/lib/config-schema.cjs +32 -3
  18. package/gsd-core/bin/lib/config.cjs +1 -2
  19. package/gsd-core/bin/lib/core.cjs +5 -2
  20. package/gsd-core/bin/lib/init.cjs +8 -5
  21. package/gsd-core/bin/lib/install-profiles.cjs +2 -1
  22. package/gsd-core/bin/lib/loop-resolver.cjs +157 -16
  23. package/gsd-core/bin/lib/model-resolver.cjs +47 -5
  24. package/gsd-core/bin/lib/phase.cjs +71 -11
  25. package/gsd-core/bin/lib/profile-output.cjs +45 -4
  26. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
  27. package/gsd-core/bin/lib/roadmap.cjs +97 -7
  28. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1700 -0
  29. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +20 -28
  30. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +27 -19
  31. package/gsd-core/bin/lib/runtime-homes.cjs +26 -20
  32. package/gsd-core/bin/lib/state-command-router.cjs +15 -3
  33. package/gsd-core/bin/lib/state-document.cjs +46 -1
  34. package/gsd-core/bin/lib/state.cjs +221 -35
  35. package/gsd-core/bin/lib/verify.cjs +19 -4
  36. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -2
  37. package/gsd-core/bin/shared/config-schema.manifest.json +0 -18
  38. package/gsd-core/bin/shared/model-catalog.json +1 -0
  39. package/gsd-core/references/loop-hook-dispatch.md +61 -0
  40. package/gsd-core/templates/config.json +1 -1
  41. package/gsd-core/workflows/audit-milestone.md +5 -3
  42. package/gsd-core/workflows/autonomous.md +10 -5
  43. package/gsd-core/workflows/code-review-fix.md +9 -7
  44. package/gsd-core/workflows/code-review.md +8 -6
  45. package/gsd-core/workflows/discuss-phase.md +14 -0
  46. package/gsd-core/workflows/execute-phase.md +82 -143
  47. package/gsd-core/workflows/help/modes/full.md +3 -1
  48. package/gsd-core/workflows/new-project.md +3 -3
  49. package/gsd-core/workflows/plan-phase.md +89 -221
  50. package/gsd-core/workflows/profile-user.md +3 -1
  51. package/gsd-core/workflows/progress.md +58 -1
  52. package/gsd-core/workflows/quick.md +9 -6
  53. package/gsd-core/workflows/review.md +19 -2
  54. package/gsd-core/workflows/secure-phase.md +4 -2
  55. package/gsd-core/workflows/settings-advanced.md +2 -0
  56. package/gsd-core/workflows/ship.md +57 -0
  57. package/gsd-core/workflows/validate-phase.md +4 -2
  58. package/gsd-core/workflows/verify-work.md +27 -11
  59. package/package.json +3 -2
  60. package/scripts/affected-tests-lib.cjs +16 -4
  61. package/scripts/gen-capability-registry.cjs +359 -48
  62. package/scripts/gen-inventory-manifest.cjs +1 -4
  63. package/scripts/gen-loop-host-contract.cjs +55 -0
  64. package/scripts/issue-version-gate.cjs +140 -0
  65. package/scripts/lint-allow-test-rule-refs.allowlist.json +326 -0
  66. package/scripts/lint-allow-test-rule-refs.cjs +162 -0
  67. package/scripts/lint-test-file-count.allowlist.json +8 -0
  68. package/scripts/release-tarball-smoke.cjs +7 -1
  69. package/scripts/run-tests.cjs +74 -14
@@ -74,11 +74,10 @@ AGENT_SKILLS_RESEARCHER=$(gsd_run query agent-skills gsd-phase-researcher)
74
74
  AGENT_SKILLS_PLANNER=$(gsd_run query agent-skills gsd-planner)
75
75
  AGENT_SKILLS_CHECKER=$(gsd_run query agent-skills gsd-plan-checker)
76
76
  CONTEXT_WINDOW=$(gsd_run query config-get context_window 2>/dev/null || echo "200000")
77
- TDD_MODE=$(gsd_run query config-get workflow.tdd_mode 2>/dev/null || echo "false")
78
77
  MVP_MODE_CFG=$(gsd_run query config-get workflow.mvp_mode 2>/dev/null || echo "false")
79
78
  ```
80
79
 
81
- When `TDD_MODE` is `true`, the planner agent is instructed to apply `type: tdd` to eligible tasks using heuristics from `references/tdd.md`. The planner's `<required_reading>` is extended to include `@~/.claude/gsd-core/references/tdd.md` so gate enforcement rules are available during planning.
80
+ When the tdd capability's `workflow.tdd_mode` is active (resolved via the plan:pre render-hooks), the planner agent is instructed to apply `type: tdd` to eligible tasks using heuristics from `references/tdd.md`. The TDD guidance is injected via the tdd capability's contribution hook at §5.6; no inline config-get is needed.
82
81
 
83
82
  When `CONTEXT_WINDOW >= 500000`, the planner prompt includes the 3 most recent prior phase CONTEXT.md and SUMMARY.md files PLUS any phases explicitly listed in the current phase's `Depends on:` field in ROADMAP.md. Explicit dependencies always load regardless of recency (e.g., Phase 7 declaring `Depends on: Phase 2` always sees Phase 2's context). Bounded recency keeps the planner's context budget focused on recent work.
84
83
 
@@ -165,7 +164,9 @@ Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from in
165
164
  ```bash
166
165
  MVP_FLAG_ARG=""
167
166
  if [[ "$ARGUMENTS" =~ (^|[[:space:]])--mvp([[:space:]]|$) ]]; then MVP_FLAG_ARG="--cli-flag"; fi
168
- if [[ "$ARGUMENTS" =~ (^|[[:space:]])--tdd([[:space:]]|$) ]]; then TDD_MODE=true; fi
167
+ if [[ "$ARGUMENTS" =~ (^|[[:space:]])--tdd([[:space:]]|$) ]]; then
168
+ gsd_run query config-set workflow.tdd_mode true 2>/dev/null || true
169
+ fi
169
170
  ```
170
171
 
171
172
  Defer the `phase.mvp-mode` query until `PHASE` is finalized (after explicit argument parsing/fallback phase detection + validation). The verb returns `true|false`; full result also exposes `source` (`cli_flag` | `roadmap` | `config` | `none`) for diagnostics. Mode is **all-or-nothing per phase** (PRD decision Q1).
@@ -411,45 +412,20 @@ If "Run discuss-phase first":
411
412
  ```
412
413
  **Exit the plan-phase workflow. Do not continue.**
413
414
 
414
- ## 4.5. Check AI-SPEC
415
+ ## 4.5. Resolve AI-SPEC Artifact
415
416
 
416
- **Skip if:** `ai_integration_phase_enabled` from config is false, or `--skip-ai-spec` flag provided.
417
+ AI integration activation is owned by the `ai-integration` capability's `plan:pre` step hook. The plan-phase host only discovers existing artifacts here so the planner can consume them; it must not read the capability's config key directly.
417
418
 
418
419
  ```bash
419
420
  AI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-AI-SPEC.md 2>/dev/null | head -1)
420
- AI_PHASE_CFG=$(gsd_run query config-get workflow.ai_integration_phase 2>/dev/null || echo "true")
421
- ```
422
-
423
- **Skip if `AI_PHASE_CFG` is `false`.**
424
-
425
- **If `AI_SPEC_FILE` is empty:** Check phase goal for AI keywords:
426
- ```bash
427
- echo "${phase_goal}" | grep -qi "agent\|llm\|rag\|chatbot\|embedding\|langchain\|llamaindex\|crewai\|langgraph\|openai\|anthropic\|vector\|eval\|ai system"
428
- ```
429
-
430
- **If AI keywords detected AND no AI-SPEC.md:**
431
- ```
432
- ◆ Note: This phase appears to involve AI system development.
433
- Consider running /gsd:ai-integration-phase {N} before planning to:
434
- - Select the right framework for your use case
435
- - Research its docs and best practices
436
- - Design an evaluation strategy
437
-
438
- Continue planning without AI-SPEC? (non-blocking — /gsd:ai-integration-phase can be run after)
421
+ AI_SPEC_PATH="${AI_SPEC_FILE}"
422
+ FRAMEWORK_LINE=""
423
+ if [ -n "$AI_SPEC_FILE" ]; then
424
+ FRAMEWORK_LINE=$(grep "Selected Framework:" "${AI_SPEC_FILE}" | head -1)
425
+ fi
439
426
  ```
440
427
 
441
- Use AskUserQuestion with options:
442
- - "Continue — plan without AI-SPEC"
443
- - "Stop — I'll run /gsd:ai-integration-phase {N} first"
444
-
445
- If "Stop": Exit with `/gsd:ai-integration-phase {N}` reminder.
446
- If "Continue": Proceed. (Non-blocking — planner will note AI-SPEC is absent.)
447
-
448
- **If `AI_SPEC_FILE` is non-empty:** Extract framework for planner context:
449
- ```bash
450
- FRAMEWORK_LINE=$(grep "Selected Framework:" "${AI_SPEC_FILE}" | head -1)
451
- ```
452
- Pass `ai_spec_path` and `framework_line` to planner in step 7 so it can reference the AI design contract.
428
+ If `AI_SPEC_FILE` is non-empty, pass `AI_SPEC_PATH` and `FRAMEWORK_LINE` to the planner in step 8 so it can reference the AI design contract. If it is empty, the active `ai-integration` capability hook in step 5.6 handles any AI-system nudge or `/gsd:ai-integration-phase` dispatch.
453
429
 
454
430
  ## 5. Handle Research
455
431
 
@@ -525,41 +501,21 @@ Display banner:
525
501
 
526
502
  ```bash
527
503
  PHASE_DESC=$(gsd_run query roadmap.get-phase "${PHASE}" --pick section)
504
+ if [ -z "${PLAN_PRE_HOOKS_JSON:-}" ]; then
505
+ PLAN_PRE_HOOKS_JSON=$(gsd_run loop render-hooks plan:pre --raw)
506
+ fi
528
507
  ```
529
508
 
530
- Research prompt:
509
+ Find the active `research` step hook in `PLAN_PRE_HOOKS_JSON`. Use the hook's `fragment.inline` as the prompt template and substitute the phase fields below before spawning its declared `ref.agent`.
531
510
 
532
511
  ```markdown
533
- <objective>
534
- Research how to implement Phase {phase_number}: {phase_name}
535
- Answer: "What do I need to know to PLAN this phase well?"
536
- </objective>
537
-
538
- <files_to_read>
539
- - {context_path} (USER DECISIONS from /gsd:discuss-phase)
540
- - {requirements_path} (Project requirements)
541
- - {state_path} (Project decisions and history)
542
- </files_to_read>
543
-
544
- ${AGENT_SKILLS_RESEARCHER}
545
-
546
- <additional_context>
547
- **Phase description:** {phase_description}
548
- **Phase requirement IDs (MUST address):** {phase_req_ids}
549
-
550
- **Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
551
- **Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — read SKILL.md files, research should account for project skill patterns
552
- </additional_context>
553
-
554
- <output>
555
- Write to: {phase_dir}/{phase_num}-RESEARCH.md
556
- </output>
512
+ {research_hook.fragment.inline}
557
513
  ```
558
514
 
559
515
  ```
560
516
  Agent(
561
- prompt=research_prompt,
562
- subagent_type="gsd-phase-researcher",
517
+ prompt=filled_research_hook_fragment,
518
+ subagent_type=research_hook.ref.agent,
563
519
  model="{researcher_model}",
564
520
  description="Research Phase {phase}"
565
521
  )
@@ -622,17 +578,19 @@ test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED
622
578
 
623
579
  ## 5.55. Security Threat Model Gate
624
580
 
625
- > Skip if `workflow.security_enforcement` is explicitly `false`. Absent = enabled.
581
+ > Capability-driven dispatch. Resolves active `plan:pre` hooks via the capability registry; the security hook's `when` condition is evaluated by the registry.
626
582
 
627
583
  ```bash
628
- SECURITY_CFG=$(gsd_run query config-get workflow.security_enforcement --raw 2>/dev/null || echo "true")
629
- SECURITY_ASVS=$(gsd_run query config-get workflow.security_asvs_level --raw 2>/dev/null || echo "1")
630
- SECURITY_BLOCK=$(gsd_run query config-get workflow.security_block_on --raw 2>/dev/null || echo "high")
584
+ PLAN_PRE_HOOKS_JSON=$(gsd_run loop render-hooks plan:pre --raw)
631
585
  ```
632
586
 
633
- **If `SECURITY_CFG` is `false`:** Skip to step 5.6.
587
+ Resolve active contribution hooks from `PLAN_PRE_HOOKS_JSON` where `kind == "contribution"` and `capId == "security"`.
634
588
 
635
- **If `SECURITY_CFG` is `true`:** Display banner:
589
+ **If no active security contribution hook exists:** Skip to step 5.6.
590
+
591
+ **If an active security contribution hook exists:** Read `SECURITY_ASVS` from the active hook's `configValues.security_asvs_level` (default: `1`) and `SECURITY_BLOCK` from `configValues.security_block_on` (default: `"high"`). These values are resolved by the capability registry from user config using the same four-level precedence as hook activation — no inline `config-get` is needed.
592
+
593
+ Display banner:
636
594
 
637
595
  ```
638
596
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -646,21 +604,31 @@ Opt out: set security_enforcement: false in .planning/config.json
646
604
 
647
605
  Continue to step 5.6. Security config is passed to the planner in step 8.
648
606
 
649
- ## 5.6. UI Design Contract Gate
607
+ ## 5.6. Plan:Pre Capability Dispatch and UI Design Contract Gate
650
608
 
651
- > Capability-driven dispatch. Resolves active `plan:pre` hooks via the capability registry; each hook's `when` condition (`workflow.ui_phase` for step hooks, `workflow.ui_safety_gate` for gate hooks) is evaluated by the registry — no inline config-get needed.
609
+ > Capability-driven dispatch. Resolves active `plan:pre` hooks via the capability registry; each hook's `when` condition is evaluated by the registry — no inline config-get needed. This section handles skill-based planning preflights such as `ai-integration`, agent-backed hooks through `ref.agent`, and the UI gate whose deterministic check comes from `check.query`.
652
610
  >
653
611
  > **Config semantics (cutover fix):** `workflow.ui_phase` gates UI-SPEC *generation* (step); `workflow.ui_safety_gate` gates the *planning block* (gate). Both-on = identical to OLD §5.6. Intended change: `{ui_phase:true, ui_safety_gate:false}` now auto-generates in pipelines but does NOT block manual planning (each key controls exactly what its description says).
654
612
 
655
613
  ```bash
656
- HOOKS_JSON=$(gsd_run loop render-hooks plan:pre --raw)
614
+ PLAN_PRE_HOOKS_JSON=${PLAN_PRE_HOOKS_JSON:-$(gsd_run loop render-hooks plan:pre --raw)}
615
+ HOOKS_JSON="$PLAN_PRE_HOOKS_JSON"
657
616
  ```
658
617
 
659
- Read the `activeHooks` array directly from `HOOKS_JSON` (in-context — do NOT invoke a shell pipeline).
618
+ Read the `activeHooks` array directly from `PLAN_PRE_HOOKS_JSON` / `HOOKS_JSON` (in-context — do NOT invoke a shell pipeline).
619
+
620
+ **Branch 1 — all plan:pre hooks inactive (`activeHooks` is empty or absent):** Skip to step 6.
660
621
 
661
- **Branch 1 — both toggles off (`activeHooks` is empty or absent):** Skip to step 6.
622
+ **Generic step hook dispatch contract:** For each active entry where `kind == "step"`:
623
+ - If `ref.skill` is set, dispatch with `Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")` when pipeline mode allows auto-chaining. Prepend `gsd-` to `ref.skill` — `ui-phase` → `gsd-ui-phase`.
624
+ - If `ref.agent` is set, dispatch with `Agent(prompt=filled_hook_fragment, subagent_type=ref.agent, model="{researcher_model}")`. Use the hook's `fragment.inline` as the prompt body and fill phase fields before spawning.
625
+ - The `research` hook is handled by §5.1's research decision. The `pattern-mapper` hook is handled by §7.8 after `RESEARCH_PATH` is known. Future plan:pre agent hooks use the same `ref.agent` fragment contract.
662
626
 
663
- Run whenever **any** `plan:pre` UI hook is active — including the step-only case (`workflow.ui_safety_gate` off). (`check.query` = `"ui.plan-gate"`; router normalizes dots→hyphens.)
627
+ **AI integration capability:** If the active `ai-integration` step hook is present, `AI_SPEC_PATH` is empty, and the phase goal contains AI keywords (`agent`, `llm`, `rag`, `chatbot`, `embedding`, `langchain`, `llamaindex`, `crewai`, `langgraph`, `openai`, `anthropic`, `vector`, `eval`, `ai system`), then:
628
+ - In pipeline / `--auto` mode, invoke the hook's `ref.skill` via `Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")`.
629
+ - In manual mode, display the existing non-blocking `/gsd:ai-integration-phase {N}` recommendation and let the user continue planning without AI-SPEC or stop to run the capability workflow first.
630
+
631
+ Run the UI deterministic gate whenever **any** `plan:pre` UI hook is active — including the step-only case (`workflow.ui_safety_gate` off). (`check.query` = `"ui.plan-gate"`; router normalizes dots→hyphens.)
664
632
 
665
633
  ```bash
666
634
  GATE=$(gsd_run check ui-plan-gate "${PHASE}" --raw)
@@ -668,7 +636,7 @@ GATE=$(gsd_run check ui-plan-gate "${PHASE}" --raw)
668
636
 
669
637
  Read `frontend`, `hasUiSpec`, and `block` from `GATE`.
670
638
 
671
- **Branch 2 — no frontend indicators (`frontend` is `false`):** Skip silently to step 5.7.
639
+ **Branch 2 — no frontend indicators (`frontend` is `false`):** Skip silently to step 6.
672
640
 
673
641
  **Branch 3 — UI-SPEC already exists (`hasUiSpec` is `true`):**
674
642
 
@@ -689,13 +657,13 @@ Read the ephemeral auto-chain flag:
689
657
  AUTO_CHAIN=$(gsd_run query check auto-mode --pick auto_chain_active 2>/dev/null || echo "false")
690
658
  ```
691
659
 
692
- **Branch 5 — `AUTO_CHAIN` is `true` (pipeline / `--auto`):** Fire each active **step** hook — runs independently of whether a gate is active (covers `{ui_phase:true, ui_safety_gate:false}`). For each entry in `activeHooks` (in array order) where `kind == "step"` and `ref.skill` is set:
660
+ **Branch 5 — `AUTO_CHAIN` is `true` (pipeline / `--auto`):** Fire each active UI **step** hook — runs independently of whether a gate is active (covers `{ui_phase:true,ui_safety_gate:false}`). For each entry in `activeHooks` (in array order) where `kind == "step"` and `ref.skill` is set:
693
661
 
694
662
  ```
695
663
  Skill(skill="gsd-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")
696
664
  ```
697
665
 
698
- (prepend `gsd-` to `ref.skill` — `ui-phase` → `gsd-ui-phase`.) After all step hooks return, re-read:
666
+ After all UI step hooks return, re-read:
699
667
 
700
668
  ```bash
701
669
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
@@ -719,68 +687,6 @@ Also available:
719
687
 
720
688
  **Exit the plan-phase workflow. Do not continue.**
721
689
 
722
- ## 5.7. Schema Push Detection Gate
723
-
724
- > Detects schema-relevant files in the phase scope 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.
725
-
726
- Check if any files in the phase scope match schema patterns:
727
-
728
- ```bash
729
- PHASE_SECTION=$(gsd_run query roadmap.get-phase "${PHASE}" --pick section 2>/dev/null)
730
- ```
731
-
732
- Scan `PHASE_SECTION`, `CONTEXT.md` (if loaded), and `RESEARCH.md` (if exists) for file paths matching these ORM patterns:
733
-
734
- | ORM | File Patterns |
735
- |-----|--------------|
736
- | Payload CMS | `src/collections/**/*.ts`, `src/globals/**/*.ts` |
737
- | Prisma | `prisma/schema.prisma`, `prisma/schema/*.prisma` |
738
- | Drizzle | `drizzle/schema.ts`, `src/db/schema.ts`, `drizzle/*.ts` |
739
- | Supabase | `supabase/migrations/*.sql` |
740
- | TypeORM | `src/entities/**/*.ts`, `src/migrations/**/*.ts` |
741
-
742
- Also check if any existing PLAN.md files for this phase already reference these file patterns in `files_modified`.
743
-
744
- **If schema-relevant files detected:**
745
-
746
- Set `SCHEMA_PUSH_REQUIRED=true` and `SCHEMA_ORM={detected_orm}`.
747
-
748
- Determine the push command for the detected ORM:
749
-
750
- | ORM | Push Command | Non-TTY Workaround |
751
- |-----|-------------|-------------------|
752
- | Payload CMS | `npx payload migrate` | `CI=true PAYLOAD_MIGRATING=true npx payload migrate` |
753
- | Prisma | `npx prisma db push` | `npx prisma db push --accept-data-loss` (if destructive) |
754
- | Drizzle | `npx drizzle-kit push` | `npx drizzle-kit push` |
755
- | Supabase | `supabase db push` | Set `SUPABASE_ACCESS_TOKEN` env var |
756
- | TypeORM | `npx typeorm migration:run` | `npx typeorm migration:run -d src/data-source.ts` |
757
-
758
- Inject the following into the planner prompt (step 8) as an additional constraint:
759
-
760
- ```markdown
761
- <schema_push_requirement>
762
- **[BLOCKING] Schema Push Required**
763
-
764
- This phase modifies schema-relevant files ({detected_files}). The planner MUST include
765
- a `[BLOCKING]` task that runs the database schema push command AFTER all schema file
766
- modifications are complete but BEFORE verification.
767
-
768
- - ORM detected: {SCHEMA_ORM}
769
- - Push command: {push_command}
770
- - Non-TTY workaround: {env_hint}
771
- - If push requires interactive prompts that cannot be suppressed, flag the task for
772
- manual intervention with `autonomous: false`
773
-
774
- This task is mandatory — the phase CANNOT pass verification without it. Build and
775
- type checks will pass without the push (types come from config, not the live database),
776
- creating a false-positive verification state.
777
- </schema_push_requirement>
778
- ```
779
-
780
- Display: `Schema files detected ({SCHEMA_ORM}) — [BLOCKING] push task will be injected into plans`
781
-
782
- **If no schema-relevant files detected:** Skip silently to step 6.
783
-
784
690
  ## 6. Check Existing Plans
785
691
 
786
692
  ```bash
@@ -845,14 +751,7 @@ Proceed to Step 7.8 (or Step 8 if pattern mapper is disabled) only if user selec
845
751
 
846
752
  ## 7.8. Spawn gsd-pattern-mapper Agent (Optional)
847
753
 
848
- **Skip if** `workflow.pattern_mapper` is explicitly set to `false` in config.json (absent key = enabled). Also skip if no CONTEXT.md and no RESEARCH.md exist for this phase (nothing to extract file lists from).
849
-
850
- Check config:
851
- ```bash
852
- PATTERN_MAPPER_CFG=$(gsd_run query config-get workflow.pattern_mapper 2>/dev/null || echo "true")
853
- ```
854
-
855
- **If `PATTERN_MAPPER_CFG` is `false`:** Skip to step 8.
754
+ Pattern mapper activation is owned by the `pattern-mapper` capability's `plan:pre` step hook. Read `PLAN_PRE_HOOKS_JSON` and skip if no active step hook has `capId == "pattern-mapper"` and `ref.agent == "gsd-pattern-mapper"`. Also skip if no CONTEXT.md and no RESEARCH.md exist for this phase (nothing to extract file lists from).
856
755
 
857
756
  **If PATTERNS.md already exists** (`PATTERNS_PATH` is non-empty from step 7): Skip to step 8 (use existing).
858
757
 
@@ -865,30 +764,17 @@ Display banner:
865
764
  ◆ Spawning pattern mapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
866
765
  ```
867
766
 
868
- Pattern mapper prompt:
767
+ Use the active `pattern-mapper` hook's `fragment.inline` as the prompt template and substitute the phase fields below before spawning its declared `ref.agent`.
869
768
 
870
769
  ```markdown
871
- <pattern_mapping_context>
872
- **Phase:** {phase_number} - {phase_name}
873
- **Phase directory:** {phase_dir}
874
- **Padded phase:** {padded_phase}
875
-
876
- <files_to_read>
877
- - {context_path} (USER DECISIONS from /gsd:discuss-phase)
878
- - {research_path} (Technical Research)
879
- </files_to_read>
880
-
881
- **Output file:** {phase_dir}/{padded_phase}-PATTERNS.md
882
-
883
- Extract the list of files to be created/modified from CONTEXT.md and RESEARCH.md. For each file, classify by role and data flow, find the closest existing analog in the codebase, extract concrete code excerpts, and produce PATTERNS.md.
884
- </pattern_mapping_context>
770
+ {pattern_mapper_hook.fragment.inline}
885
771
  ```
886
772
 
887
773
  Spawn with:
888
774
  ```
889
775
  Agent(
890
- prompt="{above}",
891
- subagent_type="gsd-pattern-mapper",
776
+ prompt=filled_pattern_mapper_hook_fragment,
777
+ subagent_type=pattern_mapper_hook.ref.agent,
892
778
  model="{researcher_model}",
893
779
  )
894
780
  ```
@@ -906,16 +792,21 @@ PATTERNS_PATH="${PHASE_DIR}/${PADDED_PHASE}-PATTERNS.md"
906
792
 
907
793
  ## 7.9. Regenerate API-SURFACE.md (intel gate)
908
794
 
795
+ > Capability-driven dispatch. Resolves active `plan:pre` step hooks via the capability registry; the intel hook's `when: intel.enabled` condition is evaluated by the registry — no inline config-get needed.
796
+
797
+ Read the active intel step hook from `PLAN_PRE_HOOKS_JSON` where `kind == "step"` and `capId == "intel"`.
798
+
799
+ **If no active intel step hook exists:** `API_SURFACE_PATH` stays empty; skip to step 8. The step-8 planner entry for API Surface is omitted when `API_SURFACE_PATH` is empty.
800
+
801
+ **If an active intel step hook exists:**
909
802
  ```bash
910
- INTEL_CFG=$(gsd_run query config-get intel.enabled 2>/dev/null || echo "false")
911
- # false (absent = false) → API_SURFACE_PATH stays empty; step-8 planner entry omitted
912
- if [ "$INTEL_CFG" = "true" ]; then
913
- gsd_run intel api-surface
914
- API_SURFACE_PATH=".planning/intel/API-SURFACE.md"
915
- echo "✓ API surface regenerated: ${API_SURFACE_PATH}" # injected into step 8 as HINT
916
- fi
803
+ gsd_run intel api-surface
804
+ API_SURFACE_PATH=".planning/intel/API-SURFACE.md"
805
+ echo "✓ API surface regenerated: ${API_SURFACE_PATH}" # injected into step 8 as HINT
917
806
  ```
918
807
 
808
+ Continue to step 8.
809
+
919
810
  ## 8. Spawn gsd-planner Agent
920
811
 
921
812
  Display banner:
@@ -944,11 +835,12 @@ Planner prompt:
944
835
  - {verification_path} (Verification Gaps - if --gaps)
945
836
  - {uat_path} (UAT Gaps - if --gaps)
946
837
  - {reviews_path} (Cross-AI Review Feedback - if --reviews; actionable findings must be incorporated or explicitly deferred/rejected in PLAN.md)
838
+ - {AI_SPEC_PATH} (AI Design Contract — framework and evaluation strategy, if exists)
947
839
  - {UI_SPEC_PATH} (UI Design Contract — visual/interaction specs, if exists)
948
840
  - {SPEC_PATH} (Phase SPEC — carries the ## Edge Coverage section to lift covered/backstop edges from, if exists)
949
841
  - {SPIKE_FINDINGS_PATH} (Spike Findings — validated patterns, constraints, landmines from experiments, if exists)
950
842
  - {SKETCH_FINDINGS_PATH} (Sketch Findings — validated design decisions, CSS patterns, visual direction, if exists)
951
- - {API_SURFACE_PATH} (API Surface — HINT ONLY, if intel.enabled; see <intel_surface_hint> below)
843
+ - {API_SURFACE_PATH} (API Surface — HINT ONLY, when intel capability is active; see <intel_surface_hint> below)
952
844
  ${CONTEXT_WINDOW >= 500000 ? `
953
845
  **Cross-phase context (1M model enrichment):**
954
846
  - CONTEXT.md files from the 3 most recent completed phases (locked decisions — maintain consistency)
@@ -977,19 +869,10 @@ Historical findings already incorporated, explicitly deferred/rejected in PLAN.m
977
869
 
978
870
  **Phase requirement IDs (every ID MUST appear in a plan's `requirements` field):** {phase_req_ids}
979
871
 
980
- **Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
872
+ **Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists — follow project-specific guidelines
981
873
  **Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — read SKILL.md files, plans should account for project skill rules
982
874
 
983
- ${TDD_MODE === 'true' ? `
984
- <tdd_mode_active>
985
- **TDD Mode is ENABLED.** Apply TDD heuristics from @~/.claude/gsd-core/references/tdd.md to all eligible tasks:
986
- - Business logic with defined I/O → type: tdd
987
- - API endpoints with request/response contracts → type: tdd
988
- - Data transformations, validation, algorithms → type: tdd
989
- - UI, config, glue code, CRUD → standard plan (type: execute)
990
- Each TDD plan gets one feature with RED/GREEN/REFACTOR gate sequence.
991
- </tdd_mode_active>
992
- ` : ''}
875
+ {For each active entry in `PLAN_PRE_HOOKS_JSON` where `kind == "contribution"` and `into == "planner"` (in array order): inject the entry's `fragment.inline` verbatim here. This delivers all planner-targeted contributions — including tdd's `<tdd_mode_active>` block (type:tdd heuristics), schema-gate's schema-push detection guidance (if active at plan:pre), and security's threat-model guidance. For the security contribution, also surface the resolved `configValues`: `security_asvs_level` (ASVS enforcement level) and `security_block_on` (severity threshold) so the planner uses the configured values when generating `<threat_model>` blocks. If no active planner contributions exist, omit this block entirely.}
993
876
 
994
877
  **MVP_MODE:** ${MVP_MODE} (when true, follow vertical-slice rules from `~/.claude/gsd-core/references/planner-mvp-mode.md`; when false, ignore MVP guidance entirely.)
995
878
  **WALKING_SKELETON:** ${WALKING_SKELETON} (when true, the first deliverable must be a Walking Skeleton — Read the template at `~/.claude/gsd-core/references/skeleton-template.md` and produce SKELETON.md alongside PLAN.md.)
@@ -1316,7 +1199,7 @@ If an actionable finding remains only in REVIEWS.md and would be invisible to /g
1316
1199
 
1317
1200
  **Phase requirement IDs (MUST ALL be covered):** {phase_req_ids}
1318
1201
 
1319
- **Project instructions:** Read ./CLAUDE.md if exists — verify plans honor project guidelines
1202
+ **Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists — verify plans honor project guidelines
1320
1203
  **Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — verify plans account for project skill rules
1321
1204
  </verification_context>
1322
1205
 
@@ -1682,53 +1565,38 @@ gsd_run query commit "docs(${PADDED_PHASE}): create phase plan" --files "${PHASE
1682
1565
 
1683
1566
  This commits all PLAN.md files for the phase plus the updated STATE.md and ROADMAP.md to version-control the planning artifacts. Skip this step if `commit_docs` is false.
1684
1567
 
1685
- ## 13e. Post-Planning Gap Analysis
1686
-
1687
- After all plans are generated, committed, and the Requirements Coverage Gate (§13)
1688
- has run, emit a single unified gap report covering both REQUIREMENTS.md and the
1689
- CONTEXT.md `<decisions>` section. This is a **proactive, post-hoc report** — it
1690
- does not block phase advancement and does not re-plan. It exists so that any
1691
- requirement or decision that slipped through the per-plan checks is surfaced in
1692
- one place before execution begins.
1568
+ ## 13e. Post-Planning Gap Analysis (plan:post capability gate dispatch)
1693
1569
 
1694
- **Skip if:** `workflow.post_planning_gaps` is `false`. Default is `true`.
1570
+ Proactive, non-blocking coverage report gated on `workflow.post_planning_gaps`
1571
+ (default `true`). Dispatched via the `plan:post` capability gate owned by the
1572
+ `gap-analysis` capability (ADR-857 §53). Reads REQUIREMENTS.md and CONTEXT.md
1573
+ `<decisions>` and cross-references each REQ-ID / D-ID against `${PHASE_DIR}/*-PLAN.md`.
1695
1574
 
1696
1575
  ```bash
1697
- POST_PLANNING_GAPS=$(gsd_run query config-get workflow.post_planning_gaps --default true 2>/dev/null || echo true)
1698
- if [ "$POST_PLANNING_GAPS" = "true" ]; then
1699
- # Scope to this phase's mapped REQ-IDs (#447); null/TBD skips the requirements comparison (CONTEXT.md decisions still reported), mirroring §13.
1700
- gsd_run gap-analysis --phase-dir "${PHASE_DIR}" --phase-req-ids "$(gsd_run query init.plan-phase "$PHASE" --pick phase_req_ids 2>/dev/null || echo TBD)"
1701
- fi
1576
+ PLAN_POST_HOOKS_JSON=$(gsd_run loop render-hooks plan:post --raw)
1577
+ PHASE_REQ_IDS=$(gsd_run query init.plan-phase "$PHASE" --pick phase_req_ids 2>/dev/null || echo TBD)
1702
1578
  ```
1703
1579
 
1704
- (`gsd-tools.cjs gap-analysis` reads `.planning/REQUIREMENTS.md`, `${PHASE_DIR}/CONTEXT.md`,
1705
- and `${PHASE_DIR}/*-PLAN.md`, then prints a markdown table with one row per
1706
- REQ-ID and D-ID. Word-boundary matching prevents `REQ-1` from being mistaken for
1707
- `REQ-10`.)
1580
+ Read the `activeHooks` array from `PLAN_POST_HOOKS_JSON` in-context. If the
1581
+ `gap-analysis` gate hook is absent (capability inactive), skip this step.
1708
1582
 
1709
- **Output format (deterministic; sorted REQUIREMENTS.md → CONTEXT.md, then natural
1710
- sort within source):**
1583
+ **For each active entry where `kind == "gate"`** (process in array order):
1711
1584
 
1585
+ ```bash
1586
+ GATE_RESULT=$(gsd_run check ${hook.check.query} "${PHASE_DIR}" "${PHASE_REQ_IDS}" --raw)
1587
+ CHECK_EXIT=$?
1712
1588
  ```
1713
- ## Post-Planning Gap Analysis
1714
1589
 
1715
- | Source | Item | Status |
1716
- |--------|------|--------|
1717
- | REQUIREMENTS.md | REQ-01 | ✓ Covered |
1718
- | REQUIREMENTS.md | REQ-02 | ✗ Not covered |
1719
- | CONTEXT.md | D-01 | ✓ Covered |
1720
- | CONTEXT.md | D-02 | ✗ Not covered |
1721
-
1722
- ⚠ N items not covered by any plan
1723
- ```
1590
+ **Step 1 — did the CHECK COMMAND itself succeed?**
1591
+ If the check command failed (non-zero `CHECK_EXIT`, empty output, or unparseable JSON):
1592
+ - `onError == "halt"` → halt and surface command error.
1593
+ - `onError == "skip"` → log a warning and continue to the next hook.
1724
1594
 
1725
- **Skip-gracefully behavior:**
1726
- - REQUIREMENTS.md missing → CONTEXT-only report.
1727
- - CONTEXT.md missing → REQUIREMENTS-only report.
1728
- - Both missing or `<decisions>` block missing → "No requirements or decisions to check" line, no error.
1595
+ **Step 2 — read `GATE_RESULT.block` (boolean).** Only reached when command succeeded.
1729
1596
 
1730
- This step is non-blocking. If items are reported as not covered, the user may
1731
- re-run `/gsd:plan-phase --gaps` to add plans, or proceed to execute-phase as-is.
1597
+ - If `hook.blocking == true` and `GATE_RESULT.block == true`: halt. (gap-analysis is always `blocking: false` so this branch is informational only.)
1598
+ - If `hook.blocking == false` (advisory): if `GATE_RESULT.block == true` or non-empty `table`/`summary`, output the gap table and continue. Advisory gates never block phase completion.
1599
+ - If `hook.blocking == true` and `GATE_RESULT.block == false`: continue silently.
1732
1600
 
1733
1601
  ## 14. Present Final Status
1734
1602
 
@@ -414,10 +414,12 @@ Then list paths for each generated artifact:
414
414
  ```
415
415
  Artifacts:
416
416
  ✓ /gsd-dev-preferences $HOME/.claude/skills/gsd-dev-preferences/SKILL.md
417
- ✓ CLAUDE.md section ./CLAUDE.md
417
+ ✓ CLAUDE.md section <resolved claude_md_path, default ./.claude/CLAUDE.md>
418
418
  ✓ Global CLAUDE.md $HOME/.claude/CLAUDE.md
419
419
  ```
420
420
 
421
+ (Show the `claude_md_path` actually returned by the command — it defaults to `./.claude/CLAUDE.md` but may be overridden by config or `--output`.)
422
+
421
423
  (Only show artifacts that were actually generated.)
422
424
 
423
425
  **Clean up temp files:**
@@ -271,6 +271,19 @@ Resume testing: `/gsd:verify-work {phase} ${GSD_WS}` — retest specific phase
271
271
 
272
272
  This is a WARNING, not a blocker — routing proceeds normally. The debt is visible so the user can make an informed choice.
273
273
 
274
+ **Step 1.7: Check verification status for the current phase**
275
+
276
+ A phase whose verification ended `gaps_found` or `human_needed` is NOT complete, even when every PLAN.md has a matching SUMMARY.md. The count-based status (`roadmap.analyze`) only sees plans/summaries, so without this check such a phase is reported complete and routing skips straight to the next phase. When the phase appears count-complete (`summaries = plans AND plans > 0`), consult the verification report (the same `verification.status` gate `ship` and `execute-phase` use, from #651):
277
+
278
+ ```bash
279
+ PHASE_DIR=".planning/phases/[current-phase-dir]"
280
+ VERIFICATION=$(gsd_run query verification.status "${PHASE_DIR}" 2>/dev/null)
281
+ VERIFICATION_STATUS=$(printf '%s' "$VERIFICATION" | jq -r '.status' 2>/dev/null || echo "")
282
+ VERIFICATION_NEXT_ACTION=$(printf '%s' "$VERIFICATION" | jq -r '.next_action' 2>/dev/null || echo "")
283
+ ```
284
+
285
+ Track: `verification_status` — the `.status` field (`passed | gaps_found | human_needed | missing | unknown`). The query already handles a missing VERIFICATION.md (returns `missing`) and unexpected values, so no per-status file probing is needed. `passed`, `missing` (not yet verified), and `unknown` route as complete (Step 3) — `missing` with an advisory that the phase is unverified; `gaps_found` and `human_needed` route back to close the verification debt (Step 2).
286
+
274
287
  **Step 2: Route based on counts**
275
288
 
276
289
  | Condition | Meaning | Action |
@@ -278,9 +291,13 @@ This is a WARNING, not a blocker — routing proceeds normally. The debt is visi
278
291
  | uat_partial > 0 | UAT testing incomplete | Go to **Route E.2** |
279
292
  | uat_with_gaps > 0 | UAT gaps need fix plans | Go to **Route E** |
280
293
  | summaries < plans | Unexecuted plans exist | Go to **Route A** |
281
- | summaries = plans AND plans > 0 | Phase complete | Go to Step 3 |
294
+ | summaries = plans AND plans > 0 AND verification_status = gaps_found | Phase executed; verification found gaps | Go to **Route V.gaps** |
295
+ | summaries = plans AND plans > 0 AND verification_status = human_needed | Phase executed; awaiting human verification | Go to **Route V.human** |
296
+ | summaries = plans AND plans > 0 | Phase complete (verification passed, missing, or n/a) | Go to Step 3 |
282
297
  | plans = 0 | Phase not yet planned | Go to **Route B** |
283
298
 
299
+ Rows are evaluated top to bottom; the first matching row wins. The two `verification_status` rows must precede the general `summaries = plans` row so a non-`passed` verification is not reported as complete.
300
+
284
301
  ---
285
302
 
286
303
  **Route A: Unexecuted plan exists**
@@ -431,6 +448,46 @@ UAT.md exists with `status: partial` — testing session ended before all items
431
448
 
432
449
  ---
433
450
 
451
+ **Route V.gaps: verification found gaps (gaps_found)**
452
+
453
+ VERIFICATION.md exists with `status: gaps_found` — verification identified gaps that need fix plans. The phase is NOT complete.
454
+
455
+ ```
456
+ ---
457
+
458
+ ## ⚠ Verification Gaps Found
459
+
460
+ **{phase_num}-VERIFICATION.md** reports `gaps_found`. ${VERIFICATION_NEXT_ACTION}
461
+
462
+ `/clear` then:
463
+
464
+ `/gsd:plan-phase {phase} --gaps ${GSD_WS}`
465
+
466
+ ---
467
+ ```
468
+
469
+ ---
470
+
471
+ **Route V.human: human verification required (human_needed)**
472
+
473
+ VERIFICATION.md exists with `status: human_needed` — automated checks passed but manual verification items remain. The phase is NOT complete until they are resolved.
474
+
475
+ ```
476
+ ---
477
+
478
+ ## Human Verification Required
479
+
480
+ **{phase_num}-VERIFICATION.md** reports `human_needed`. ${VERIFICATION_NEXT_ACTION}
481
+
482
+ `/clear` then:
483
+
484
+ `/gsd:verify-work {phase} ${GSD_WS}` — resume human verification
485
+
486
+ ---
487
+ ```
488
+
489
+ ---
490
+
434
491
  **Step 3: Check milestone status (only when phase complete)**
435
492
 
436
493
  Read ROADMAP.md and identify:
@@ -409,7 +409,7 @@ Agent(
409
409
  <files_to_read>
410
410
  - .planning/STATE.md (Project state — what's already built)
411
411
  - .planning/PROJECT.md (Project context)
412
- - ./CLAUDE.md (if exists — project-specific guidelines)
412
+ - ./CLAUDE.md or ./.claude/CLAUDE.md (if exists — project-specific guidelines)
413
413
  ${DISCUSS_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-CONTEXT.md (User decisions — research should align with these)' : ''}
414
414
  </files_to_read>
415
415
 
@@ -468,7 +468,7 @@ Agent(
468
468
 
469
469
  <files_to_read>
470
470
  - .planning/STATE.md (Project State)
471
- - ./CLAUDE.md (if exists — follow project-specific guidelines)
471
+ - ./CLAUDE.md or ./.claude/CLAUDE.md (if exists — follow project-specific guidelines)
472
472
  ${DISCUSS_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-CONTEXT.md (User decisions — locked, do not revisit)' : ''}
473
473
  ${RESEARCH_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-RESEARCH.md (Research findings — use to inform implementation choices)' : ''}
474
474
  </files_to_read>
@@ -684,7 +684,7 @@ ORCHESTRATOR build-time embed (NOT a sub-agent runtime step): before this dispat
684
684
  <files_to_read>
685
685
  - ${QUICK_DIR}/${quick_id}-PLAN.md (Plan)
686
686
  - .planning/STATE.md (Project state)
687
- - ./CLAUDE.md (Project instructions, if exists)
687
+ - ./CLAUDE.md or ./.claude/CLAUDE.md (Project instructions, if exists)
688
688
  - .claude/skills/ or .agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation)
689
689
  </files_to_read>
690
690
 
@@ -776,11 +776,14 @@ Note: For quick tasks producing multiple plans (rare), spawn executors in parall
776
776
 
777
777
  Skip this step entirely if `$FULL_MODE` is false.
778
778
 
779
- **Config gate:**
779
+ **Capability gate:**
780
780
  ```bash
781
- CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true")
781
+ EXECUTE_POST_HOOKS_JSON=$(gsd_run loop render-hooks execute:post --raw)
782
782
  ```
783
- If `"false"`, skip with message "Code review skipped (workflow.code_review=false)".
783
+
784
+ Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
785
+
786
+ If no active code-review step hook exists, skip with message "Code review skipped (code-review capability inactive)".
784
787
 
785
788
  **Scope files from executor's commits:**
786
789
  ```bash