* test(#2971): failing-first suite for the pr-branch planning-path filter Binds the not-yet-built planning.pr_strict mode and the corrected filter recipe for /gsd-pr-branch across six layers: pure classification and forbidden-path predicates, real-git fixtures that run the cherry-pick filter loop end to end, config-key registration through the real CLI and both manifests, the executed worktree-materialization claim the issue's triage asked to establish, fast-check properties over arbitrary path sets, and a drift guard over the shipped workflow. Two live defects in today's shipped recipe are pinned as regressions, both reproduced empirically first: `git rm -r --cached` stages a deletion of any .planning/ path the target branch already tracks, so the generated PR removes the base branch's planning files; and the same command leaves the cherry-picked file untracked on disk, so a second commit touching that path aborts the pick with "untracked working tree files would be overwritten" and every remaining commit is silently dropped. The test helper parses the canonical path lists out of gsd-core/workflows/pr-branch.md rather than restating them, so the workflow stays the single source of truth and the suite cannot drift from what ships. Refs #2971 * feat(#2971): strict planning filter mode for /gsd-pr-branch Adds planning.pr_strict — a boolean, default false, that selects what /gsd-pr-branch means by "filtered". Default mode is unchanged: structural planning state survives into the PR branch and the nine transient subdirectories do not. Strict mode drops every .planning/ path, structural files included, and carries a commit over only when it touches at least one file outside .planning/. Strict mode is what makes planning.commit_docs: true safe for a project that versions its planning tree locally but publishes none of it. The alternative posture, commit_docs: false, silently costs parallel executor isolation — a worktree is checked out from a commit, so an untracked or ignored .planning/ is simply absent inside it and the executor has no PLAN.md to read. That claim is now established by an executed fixture rather than inherited. The two path lists are declared once and both projections derived from them, so create_pr_branch and verify can no longer disagree about what the filter promised. verify previously counted every .planning/ path against a documented success criterion of zero while create_pr_branch was specified to preserve five structural files, so a correct run reported itself as failed on every phase that touched STATE.md — which is every phase. It now asserts against the active mode, and names the .planning/ paths default mode deliberately keeps rather than trading a wrong signal for silence. Two verified defects in the same recipe are fixed alongside, because strict mode would have amplified both. `git rm -r --cached` staged a deletion for any .planning/ path the target branch already tracked, so the generated PR removed the base branch's planning files — under strict mode that would have been the entire tree. The same command left the picked file untracked on disk, so a second commit touching that path aborted the cherry-pick with "untracked working tree files would be overwritten" and every remaining commit was silently dropped. Both were reproduced against real git before being fixed. The filter now forces excluded paths back to what the PR branch's HEAD carries, in the index and the working tree; a conflict outside the filter halts instead of being improvised past; a commit left empty by filtering is skipped rather than failing. A clean-working-tree precondition makes the worktree half safe. Closes #2971 * fix(#2971): unwind the checkout on a conflict halt, and test the real recipe Two review findings, both fixed in place. The isolated adversarial pass found that the conflict-outside-the-filter branch exited while leaving the user checked out on the half-built PR branch with cherry-pick state still live — this loop runs in the user's own working directory, so stranding them there is a real cost even though it is not a vulnerability. The branch now aborts the pick, returns to the original branch, removes the partial PR branch, and says so before exiting. The standards pass found the L2 fixtures executed a hand-written mirror of the cherry-pick filter recipe rather than the recipe itself, so a reordering in the workflow would not have been caught — and the order is load-bearing, since restoring a path from HEAD before removing it inverts the filter. The helper now extracts the canonical loop from the shipped workflow and the fixtures execute that verbatim, which also gives the conflict-halt unwind above real coverage. The drift guard additionally pins the two commands' relative order and asserts the workflow carries exactly one canonical loop. Also records the publication gate in the CONTEXT.md glossary next to the commit gate it is distinct from. Refs #2971 * fix(#2971): make the conflict-halt unwind actually unwind, and use the colon slash form The remote matrix caught two defects in the previous commit. The halt path claimed to restore the original branch but did not. `git cherry-pick --abort` does not apply to a single `--no-commit` pick with no sequencer file, and the fallback left the unmerged index in place, which makes `git checkout` refuse — a failure the `2>/dev/null || true` then swallowed, so the user was told they had been restored while still sitting on the half-built PR branch. The unwind now drops sequencer state, hard-resets the disposable PR branch to clear the unmerged index, and only claims a restore when the checkout actually succeeded; when it does not, it says where the user is and gives them the two commands to finish it by hand. Verified against real git: exit 1, the conflict named, HEAD back on the original branch, the partial branch gone, a clean tree and no CHERRY_PICK_HEAD. Two runtime-loaded source artifacts used the retired `/gsd-<cmd>` hyphen form, which names a command no runtime registers. The canonical authoring token for workflows and references is `/gsd:<cmd>`; docs keep the hyphen form, so the documentation added in this branch is unaffected. The comment in src/config.cts moves to the colon form too, since it propagates into the generated lib. Refs #2971 * docs(#2971): backfill PR number into the changeset fragments (#3720) --------- Co-authored-by: sim <sim@local>
490 lines
32 KiB
Markdown
490 lines
32 KiB
Markdown
<planning_config>
|
||
|
||
Configuration options for `.planning/` directory behavior.
|
||
|
||
<config_schema>
|
||
```json
|
||
"planning": {
|
||
"commit_docs": true,
|
||
"pr_strict": false,
|
||
"search_gitignored": false
|
||
},
|
||
"git": {
|
||
"branching_strategy": "none",
|
||
"base_branch": null,
|
||
"phase_branch_template": "gsd/phase-{phase}-{slug}",
|
||
"milestone_branch_template": "gsd/{milestone}-{slug}",
|
||
"quick_branch_template": null
|
||
},
|
||
"manager": {
|
||
"flags": {
|
||
"discuss": "",
|
||
"plan": "",
|
||
"execute": ""
|
||
}
|
||
}
|
||
```
|
||
|
||
| Option | Default | Description |
|
||
|--------|---------|-------------|
|
||
| `commit_docs` | `true` | Whether to commit planning artifacts to git |
|
||
| `pr_strict` | `false` | Filter mode for `/gsd:pr-branch`. `false` keeps structural planning state (STATE.md, ROADMAP.md, MILESTONES.md, PROJECT.md, REQUIREMENTS.md, milestones/) in the PR branch; `true` drops every `.planning/` path |
|
||
| `search_gitignored` | `false` | Add `--no-ignore` to broad rg searches |
|
||
| `git.branching_strategy` | `"none"` | Git branching approach: `"none"`, `"phase"`, or `"milestone"` |
|
||
| `git.base_branch` | `null` (auto-detect) | Target branch for PRs and merges (e.g. `"master"`, `"develop"`). When `null`, auto-detects from `git symbolic-ref refs/remotes/origin/HEAD`, falling back to `"main"`. |
|
||
| `git.create_tag` | `true` | Create git tags on milestone completion |
|
||
| `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy |
|
||
| `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy |
|
||
| `git.quick_branch_template` | `null` | Optional branch template for quick-task runs |
|
||
| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. Note: if your branch is ahead of `origin/HEAD` (a diverged milestone or feature branch), GSD auto-degrades to sequential and prints a warning; set `worktree.baseRef:"head"` in `.claude/settings.local.json` to restore parallel execution. See the branch-divergence note below. |
|
||
| `workflow.subagent_timeout` | `300000` | Timeout in milliseconds for parallel subagent tasks (e.g. codebase mapping). Increase for large codebases or slower models. Default: 300000 (5 minutes). |
|
||
| `workflow.test_command` | `null` | Custom shell command run as the regression/test gate by execute-phase, audit-fix, and post-merge-gate. When unset, GSD auto-detects (Makefile / package.json / Cargo.toml / go.mod / pyproject.toml). Example: `npm test`. |
|
||
| `workflow.build_command` | `null` | Custom shell command run as the build gate by the post-merge gate. When unset, the build step is skipped/auto-detected. Example: `npm run build`. |
|
||
| `workflow.inline_plan_threshold` | `2` | Plans with this many tasks or fewer execute inline (Pattern C) instead of spawning a subagent. Avoids ~14K token spawn overhead for small plans. Set to `0` to always spawn subagents. |
|
||
| `manager.flags.discuss` | `""` | Flags passed to `/gsd:discuss-phase` when dispatched from manager (e.g. `"--auto --analyze"`) |
|
||
| `manager.flags.plan` | `""` | Flags passed to plan workflow when dispatched from manager |
|
||
| `manager.flags.execute` | `""` | Flags passed to execute workflow when dispatched from manager |
|
||
| `response_language` | `null` | Language for user-facing questions and prompts across all phases/subagents (e.g. `"Portuguese"`, `"Japanese"`, `"Spanish"`). When set, all spawned agents include a directive to respond in this language. |
|
||
</config_schema>
|
||
|
||
<commit_docs_behavior>
|
||
|
||
**When `commit_docs: true` (default):**
|
||
- Planning files committed normally
|
||
- SUMMARY.md, STATE.md, ROADMAP.md tracked in git
|
||
- Full history of planning decisions preserved
|
||
|
||
**When `commit_docs: false`:**
|
||
- Skip all `git add`/`git commit` for `.planning/` files
|
||
- User must add `.planning/` to `.gitignore`
|
||
- Useful for: OSS contributions, client projects, keeping planning private
|
||
|
||
**Using `gsd-tools query` (preferred):**
|
||
|
||
```bash
|
||
# Commit with automatic commit_docs + gitignore checks:
|
||
gsd-tools query commit "docs: update state" --files .planning/STATE.md
|
||
|
||
# Load config via state load (returns JSON):
|
||
INIT=$(gsd-tools query state.load)
|
||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||
# commit_docs is available in the JSON output
|
||
|
||
# Or use init commands which include commit_docs:
|
||
INIT=$(gsd-tools query init.execute-phase "1")
|
||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||
# commit_docs is included in all init command outputs
|
||
```
|
||
|
||
**Auto-detection:** If `.planning/` is gitignored, `commit_docs` is automatically `false` regardless of config.json. This prevents git errors when users have `.planning/` in `.gitignore`.
|
||
|
||
**Per-phase override:** `phase_commit_docs.<phase-id>` (e.g. `phase_commit_docs.03`) overrides `commit_docs` for one phase only, and wins over both the explicit config value and gitignore auto-detection — see `docs/CONFIGURATION.md#per-phase-override-phase_commit_docs` for the full precedence chain and examples.
|
||
|
||
**Commit via CLI (handles checks automatically):**
|
||
|
||
```bash
|
||
gsd-tools query commit "docs: update state" --files .planning/STATE.md
|
||
```
|
||
|
||
The CLI checks `commit_docs` config and gitignore status internally — no manual conditionals needed.
|
||
|
||
</commit_docs_behavior>
|
||
|
||
<search_behavior>
|
||
|
||
**When `search_gitignored: false` (default):**
|
||
- Standard rg behavior (respects .gitignore)
|
||
- Direct path searches work: `rg "pattern" .planning/` finds files
|
||
- Broad searches skip gitignored: `rg "pattern"` skips `.planning/`
|
||
|
||
**When `search_gitignored: true`:**
|
||
- Add `--no-ignore` to broad rg searches that should include `.planning/`
|
||
- Only needed when searching entire repo and expecting `.planning/` matches
|
||
|
||
**Note:** Most GSD operations use direct file reads or explicit paths, which work regardless of gitignore status.
|
||
|
||
</search_behavior>
|
||
|
||
<setup_uncommitted_mode>
|
||
|
||
To use uncommitted mode:
|
||
|
||
1. **Set config:**
|
||
```json
|
||
"planning": {
|
||
"commit_docs": false,
|
||
"search_gitignored": true
|
||
}
|
||
```
|
||
|
||
2. **Add to .gitignore:**
|
||
```
|
||
.planning/
|
||
```
|
||
|
||
3. **Existing tracked files:** If `.planning/` was previously tracked:
|
||
```bash
|
||
git rm -r --cached .planning/
|
||
git commit -m "chore: stop tracking planning docs"
|
||
```
|
||
|
||
4. **Branch merges:** When using `branching_strategy: phase` or `milestone`, the `complete-milestone` workflow automatically strips `.planning/` files from staging before merge commits when `commit_docs: false`.
|
||
|
||
</setup_uncommitted_mode>
|
||
|
||
<branching_strategy_behavior>
|
||
|
||
**Branching Strategies:**
|
||
|
||
| Strategy | When branch created | Branch scope | Merge point |
|
||
|----------|---------------------|--------------|-------------|
|
||
| `none` | Never | N/A | N/A |
|
||
| `phase` | At `execute-phase` start | Single phase | User merges after phase |
|
||
| `milestone` | At first `execute-phase` of milestone | Entire milestone | At `complete-milestone` |
|
||
|
||
**When `git.branching_strategy: "none"` (default):**
|
||
- All work commits to current branch
|
||
- Standard GSD behavior
|
||
|
||
**When `git.branching_strategy: "phase"`:**
|
||
- `execute-phase` creates/switches to a branch before execution
|
||
- Branch name from `phase_branch_template` (e.g., `gsd/phase-03-authentication`)
|
||
- All plan commits go to that branch
|
||
- User merges branches manually after phase completion
|
||
- `complete-milestone` offers to merge all phase branches
|
||
|
||
**When `git.branching_strategy: "milestone"`:**
|
||
- First `execute-phase` of milestone creates the milestone branch
|
||
- Branch name from `milestone_branch_template` (e.g., `gsd/v1.0-mvp`)
|
||
- All phases in milestone commit to same branch
|
||
- `complete-milestone` offers to merge milestone branch to main
|
||
|
||
**Template variables:**
|
||
|
||
| Variable | Available in | Description |
|
||
|----------|--------------|-------------|
|
||
| `{phase}` | phase_branch_template | Zero-padded phase number (e.g., "03") |
|
||
| `{slug}` | Both | Lowercase, hyphenated name |
|
||
| `{milestone}` | milestone_branch_template | Milestone version (e.g., "v1.0") |
|
||
|
||
**Checking the config:**
|
||
|
||
Use `init execute-phase` which returns all config as JSON:
|
||
```bash
|
||
INIT=$(gsd-tools query init.execute-phase "1")
|
||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||
# JSON output includes: branching_strategy, phase_branch_template, milestone_branch_template
|
||
```
|
||
|
||
Or use `state load` for the config values:
|
||
```bash
|
||
INIT=$(gsd-tools query state.load)
|
||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||
# Parse branching_strategy, phase_branch_template, milestone_branch_template from JSON
|
||
```
|
||
|
||
**Branch creation:**
|
||
|
||
```bash
|
||
# For phase strategy
|
||
if [ "$BRANCHING_STRATEGY" = "phase" ]; then
|
||
PHASE_SLUG=$(echo "$PHASE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
||
BRANCH_NAME=$(echo "$PHASE_BRANCH_TEMPLATE" | sed "s/{phase}/$PADDED_PHASE/g" | sed "s/{slug}/$PHASE_SLUG/g")
|
||
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
|
||
fi
|
||
|
||
# For milestone strategy
|
||
if [ "$BRANCHING_STRATEGY" = "milestone" ]; then
|
||
MILESTONE_SLUG=$(echo "$MILESTONE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
||
BRANCH_NAME=$(echo "$MILESTONE_BRANCH_TEMPLATE" | sed "s/{milestone}/$MILESTONE_VERSION/g" | sed "s/{slug}/$MILESTONE_SLUG/g")
|
||
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
|
||
fi
|
||
```
|
||
|
||
**Merge options at complete-milestone:**
|
||
|
||
| Option | Git command | Result |
|
||
|--------|-------------|--------|
|
||
| Squash merge (recommended) | `git merge --squash` | Single clean commit per branch |
|
||
| Merge with history | `git merge --no-ff` | Preserves all individual commits |
|
||
| Delete without merging | `git branch -D` | Discard branch work |
|
||
| Keep branches | (none) | Manual handling later |
|
||
|
||
Squash merge is recommended — keeps main branch history clean while preserving the full development history in the branch (until deleted).
|
||
|
||
**Use cases:**
|
||
|
||
| Strategy | Best for |
|
||
|----------|----------|
|
||
| `none` | Solo development, simple projects |
|
||
| `phase` | Code review per phase, granular rollback, team collaboration |
|
||
| `milestone` | Release branches, staging environments, PR per version |
|
||
|
||
</branching_strategy_behavior>
|
||
|
||
<complete_field_reference>
|
||
|
||
## Complete Field Reference
|
||
|
||
Generated from `CONFIG_DEFAULTS` (configuration.cjs) and `VALID_CONFIG_KEYS` (config-schema.cjs).
|
||
|
||
### Core Fields
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `model_profile` | string | `"balanced"` | `"quality"`, `"balanced"`, `"budget"`, `"adaptive"`, `"inherit"` | Model selection preset for subagents |
|
||
| `mode` | string | `"interactive"` | `"interactive"`, `"yolo"` | Operation mode: `"interactive"` shows gates and confirmations; `"yolo"` runs autonomously without prompts |
|
||
| `granularity` | string | (none) | `"coarse"`, `"standard"`, `"fine"` | Planning depth for phase plans (migrated from deprecated `depth`) |
|
||
| `commit_docs` | boolean | `true` | `true`, `false` | Commit .planning/ artifacts to git (auto-false if .planning/ is gitignored) |
|
||
| `search_gitignored` | boolean | `false` | `true`, `false` | Include gitignored paths in broad rg searches via `--no-ignore` |
|
||
| `phase_naming` | string | `"sequential"` | `"sequential"`, `"custom"` | Phase numbering: auto-increment or arbitrary string IDs |
|
||
| `project_code` | string\|null | `null` | Any short string | Prefix for phase dirs (e.g., `"CK"` produces `CK-01-foundation`) |
|
||
| `response_language` | string\|null | `null` | Any language name | Language for user-facing prompts (e.g., `"Portuguese"`, `"Japanese"`) |
|
||
| `context_window` | number | `200000` | `200000`, `1000000` | Context window size; set `1000000` for 1M-context models |
|
||
| `resolve_model_ids` | boolean\|string | `false` | `false`, `true`, `"omit"` | Map model aliases to full Claude IDs; `"omit"` returns empty string |
|
||
| `context` | string\|null | `null` | `"dev"`, `"research"`, `"review"` | Execution context profile that adjusts agent behavior: `"dev"` for development tasks, `"research"` for investigation/exploration, `"review"` for code review workflows |
|
||
| `review.models.<cli>` | string\|null | `null` | Any model ID string | Per-CLI model override for /gsd:review (e.g., `review.models.gemini`). Falls back to CLI default when null. |
|
||
|
||
### Workflow Fields
|
||
|
||
Set via `workflow.*` namespace in config.json (e.g., `"workflow": { "research": true }`).
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `workflow.research` | boolean | `true` | `true`, `false` | Run research agent before planning |
|
||
| `workflow.plan_check` | boolean | `true` | `true`, `false` | Run plan-checker agent to validate plans. _Alias:_ `plan_checker` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.plan_check` is the canonical namespaced form. |
|
||
| `workflow.verifier` | boolean | `true` | `true`, `false` | Run verifier agent after execution |
|
||
| `workflow.nyquist_validation` | boolean | `true` | `true`, `false` | Enable Nyquist-inspired validation gates |
|
||
| `workflow.auto_prune_state` | boolean | `false` | `true`, `false` | Automatically prune old STATE.md entries on phase completion (keeps 3 most recent phases) |
|
||
| `workflow.auto_advance` | boolean | `false` | `true`, `false` | Auto-advance to next phase after completion |
|
||
| `workflow.node_repair` | boolean | `true` | `true`, `false` | Attempt automatic repair of failed plan nodes |
|
||
| `workflow.node_repair_budget` | number | `2` | Any positive integer | Max repair retries per failed node |
|
||
| `workflow.smart_zone_tokens` | number | `100000` | Any positive integer | Smart-zone token budget for phase-effort estimation (#2630, ADR-2629). A phase whose estimate exceeds this is flagged with a split recommendation — advisory only, never a block. A *policy default*, not a benchmark constant: degradation begins before the advertised context window is full, but the effective ceiling is model- and task-dependent, so the calibration loop corrects it per project. _Alias:_ `smart_zone_tokens` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.smart_zone_tokens` is the canonical namespaced form. |
|
||
| `workflow.ai_integration_phase` | boolean | `true` | `true`, `false` | Run /gsd:ai-integration-phase before planning AI system phases |
|
||
| `workflow.api_coverage_gate` | boolean | `true` | `true`, `false` | Require an explicit API-coverage decision (full-by-default, opt-out-not-opt-in) before a phase that integrates an external API/SDK/service can seal. At plan:pre prompts a COVERAGE.md matrix; at verify:pre a blocking gate fails the seal unless the matrix exists with every non-integrated capability an explicit, reasoned opt-out (#1562) |
|
||
| `workflow.ui_phase` | boolean | `true` | `true`, `false` | Generate UI-SPEC.md for frontend phases |
|
||
| `workflow.ui_safety_gate` | boolean | `true` | `true`, `false` | Require safety gate approval for UI changes |
|
||
| `workflow.text_mode` | boolean | `false` | `true`, `false` | Use plain-text numbered lists instead of AskUserQuestion menus |
|
||
| `workflow.research_before_questions` | boolean | `false` | `true`, `false` | Run research before interactive questions in discuss phase |
|
||
| `workflow.discuss_mode` | string | `"discuss"` | `"discuss"`, `"assumptions"` | Default mode for discuss-phase: `"discuss"` runs interactive questioning; `"assumptions"` analyzes codebase and surfaces assumptions instead |
|
||
| `workflow.skip_discuss` | boolean | `false` | `true`, `false` | Skip discuss phase entirely |
|
||
| `workflow.use_worktrees` | boolean | `true` | `true`, `false` | Run executor agents in isolated git worktrees |
|
||
| `workflow.subagent_timeout` | number | `300000` | Any positive integer (ms) | Timeout for parallel subagent tasks (default: 5 minutes) |
|
||
| `workflow.test_command` | string\|null | `null` | Any shell command | Regression/test gate command run by execute-phase, audit-fix, and post-merge-gate. Unset → GSD auto-detects (Makefile / package.json / Cargo.toml / go.mod / pyproject.toml). |
|
||
| `workflow.build_command` | string\|null | `null` | Any shell command | Build gate command run by the post-merge gate. Unset → build step auto-detected/skipped. |
|
||
| `workflow.mvp_mode` | boolean | `false` | `true`, `false` | Persist the MVP-mode flag in config so every phase defaults to MVP framing without requiring `--mvp` on the CLI. Resolved via the chain: `--mvp` CLI flag → ROADMAP.md `**Mode:** mvp` field → this config value → `false`. When `true`, the planner, executor, verifier, and discovery surfaces (progress, stats, graphify) all treat the phase as an MVP vertical slice (UI → API → DB) of one user-visible capability. |
|
||
| `workflow.context_guard_mode` | string | `"warn"` | `"auto"`, `"warn"`, `"off"` | Context exhaustion guard mode for `execute-phase`. Before each wave, the orchestrator self-assesses context pressure using degradation signals from `context-budget.md`. `"warn"` (default): emit a warning and recommend `/gsd:pause-work` when POOR tier is detected. `"auto"`: automatically invoke `/gsd:pause-work` before the next wave when POOR tier is detected. `"off"`: disable the guard. The guard is heuristic — no programmatic context-% API exists. |
|
||
| `workflow.plan_chunked` | boolean | `false` | `true`, `false` | Enable chunked planning mode. When `true`, the plan-phase orchestrator splits the single long-lived planner Task into a short outline Task followed by N short per-plan Tasks (~3–5 min each). Each plan is committed individually for crash resilience. Particularly useful on Windows where long-lived Tasks may hang on stdio. Also activated by the `--chunked` flag. |
|
||
| `workflow.specless_probe_fallback` | boolean | `true` | `true`, `false` | Gate the SPEC-less probe fallback in `plan-phase`. When `true` (default), a phase that did not supply a `## Edge Coverage` / `## Prohibitions` SPEC section (header absent or present-but-empty) runs the existing probe protocol — the deterministic `edge-probe.cjs` for edges and an in-planner LLM recall pass for prohibitions — and authors the resulting predicates into PLAN.md `must_haves` (section-level precedence: a SPEC-supplied section is never re-run or overwritten). When `false`, the fallback is skipped but the skip is recorded: plan-phase emits a visible "probe fallback disabled" marker, never a silent skip. |
|
||
| `workflow.code_review_command` | string\|null | `null` | Any shell command | External code-review command integrated into `/gsd:ship`. The diff is piped to the command via stdin; the command must output JSON with a `verdict` field (`"APPROVED"` or `"REVISE"`). Non-zero exit or `"REVISE"` verdict blocks the ship workflow. When unset, the built-in review flow runs. Example: `my-review-tool --review`. |
|
||
| `workflow.inline_plan_threshold` | number | `2` | `0`–`10` | Plans with ≤N tasks execute inline instead of spawning a subagent |
|
||
| `workflow.code_review` | boolean | `true` | `true`, `false` | Enable built-in code review step in the ship workflow |
|
||
| `workflow.code_review_depth` | string | `"standard"` | `"quick"`, `"standard"`, `"deep"` | Depth level for code review analysis in the ship workflow |
|
||
| `workflow.code_review_depth_overrides` | array | `[]` | Array of `{paths, depth}` rule objects | Ordered path-scoped depth rules for `/gsd:code-review` (#2554). Each rule's `paths` are matched against the review's changed-file set by whole-segment directory-path prefix (`src/auth` matches `src/auth/token.ts`, never `src/authfoo/x.ts`); matching is case-sensitive. Glob syntax (`*`, `?`) is a configuration error. One matched file escalates the entire review — depth is not applied per file. Resolution order: `--depth=` flag → strongest matching rule → `workflow.code_review_depth` → `standard`. A malformed rule halts the review with a typed error rather than falling back silently. |
|
||
| `workflow._auto_chain_active` | boolean | `false` | `true`, `false` | Internal: tracks whether autonomous chaining is active |
|
||
| `workflow.security_enforcement` | boolean | `true` | `true`, `false` | Enable threat-model-anchored security verification via `/gsd:secure-phase`. When `false`, security checks are skipped entirely |
|
||
| `workflow.security_asvs_level` | number | `1` | `1`, `2`, `3` | OWASP ASVS verification level. Level 1 = opportunistic, Level 2 = standard, Level 3 = comprehensive. Scales both planner threat-disposition rigor (which threats must be mitigated vs. accepted) and auditor verification depth (grep-level → boundary-placement check → full data-flow trace). See `gsd-core/references/security-asvs-levels.md`. |
|
||
| `workflow.security_block_on` | string | `"high"` | `"critical"`, `"high"`, `"medium"`, `"low"`, `"none"` | Minimum threat severity that blocks phase advancement. The auditor counts only open threats at or above this severity toward the blocking gate (SECURITY.md `threats_open`); `none` disables severity blocking. |
|
||
| `workflow.post_planning_gaps` | boolean | `true` | `true`, `false` | Post-planning gap report (#2493). After plans are generated, scans REQUIREMENTS.md and CONTEXT.md `<decisions>` against all PLAN.md files and emits a unified `Source \| Item \| Status` table. Non-blocking. Set to `false` to skip Step 13e of plan-phase. _Alias:_ `post_planning_gaps` is the flat-key form used in `CONFIG_DEFAULTS`; `workflow.post_planning_gaps` is the canonical namespaced form. |
|
||
|
||
### Ship Fields
|
||
|
||
Set via `ship.*` namespace in config.json. These fields affect `/gsd:ship` PRD-style pull request body composition only.
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `ship.pr_body_sections` | array | `[]` | Array of section objects | Append-only project-specific PR body sections. Each entry has `heading`, optional `enabled`, and one or more of `source`, `template`, or `fallback`. Disabled entries remain in onboarding config but do not render. Core sections remain required and cannot be removed or replaced. |
|
||
|
||
### Git Fields
|
||
|
||
Set via `git.*` namespace (e.g., `"git": { "branching_strategy": "phase" }`).
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `git.branching_strategy` | string | `"none"` | `"none"`, `"phase"`, `"milestone"` | Git branching approach for phase/milestone isolation |
|
||
| `git.base_branch` | string\|null | `null` (auto-detect) | Any branch name | Target branch for PRs and merges; auto-detects from `origin/HEAD` when `null` |
|
||
| `git.create_tag` | boolean | `true` | `true`, `false` | Create git tags on milestone completion |
|
||
| `git.phase_branch_template` | string | `"gsd/phase-{phase}-{slug}"` | Template with `{phase}`, `{slug}` | Branch naming template for `phase` strategy |
|
||
| `git.milestone_branch_template` | string | `"gsd/{milestone}-{slug}"` | Template with `{milestone}`, `{slug}` | Branch naming template for `milestone` strategy |
|
||
| `git.quick_branch_template` | string\|null | `null` | Template with `{slug}` | Optional branch template for quick-task runs |
|
||
|
||
### Search & API Fields
|
||
|
||
These toggle external search integrations. Auto-detected at project creation when API keys are present.
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `brave_search` | boolean | `false` | `true`, `false` | Enable Brave web search for research agent (requires `BRAVE_API_KEY`) |
|
||
| `firecrawl` | boolean | `false` | `true`, `false` | Enable Firecrawl page scraping (requires `FIRECRAWL_API_KEY`) |
|
||
| `exa_search` | boolean | `false` | `true`, `false` | Enable Exa semantic search (requires `EXA_API_KEY`) |
|
||
|
||
### Features Fields
|
||
|
||
Set via `features.*` namespace (e.g., `"features": { "thinking_partner": true }`).
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `features.thinking_partner` | boolean | `false` | `true`, `false` | Enable conditional extended thinking at workflow decision points (used by discuss-phase and plan-phase for architectural tradeoff analysis) |
|
||
| `features.global_learnings` | boolean | `false` | `true`, `false` | Enable injection of global learnings from `~/.gsd/knowledge/` into agent prompts |
|
||
|
||
### Hook Fields
|
||
|
||
Set via `hooks.*` namespace (e.g., `"hooks": { "context_warnings": true }`).
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `hooks.context_warnings` | boolean | `true` | `true`, `false` | Show warnings when context budget is exceeded |
|
||
|
||
### Learnings Fields
|
||
|
||
Set via `learnings.*` namespace (e.g., `"learnings": { "max_inject": 5 }`). Used together with `features.global_learnings`.
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `learnings.max_inject` | number | `10` | Any positive integer | Maximum number of global learning entries to inject into agent prompts per session |
|
||
|
||
### Intel Fields
|
||
|
||
Set via `intel.*` namespace (e.g., `"intel": { "enabled": true }`). Controls the queryable codebase intelligence system consumed by `/gsd:map-codebase --query`.
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `intel.enabled` | boolean | `false` | `true`, `false` | Enable queryable codebase intelligence system. When `true`, `/gsd:map-codebase --query` builds and queries a JSON index in `.planning/intel/`. |
|
||
|
||
### Manager Fields
|
||
|
||
Set via `manager.*` namespace (e.g., `"manager": { "flags": { "discuss": "--auto" } }`).
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `manager.flags.discuss` | string | `""` | Any CLI flags string | Flags passed to `/gsd:discuss-phase` from manager (e.g., `"--auto --analyze"`) |
|
||
| `manager.flags.plan` | string | `""` | Any CLI flags string | Flags passed to plan workflow from manager |
|
||
| `manager.flags.execute` | string | `""` | Any CLI flags string | Flags passed to execute workflow from manager |
|
||
|
||
### Advanced Fields
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `parallelization` | boolean\|object | `true` | `true`, `false`, `{ "enabled": true }` | Enable parallel wave execution; object form allows additional sub-keys |
|
||
| `model_overrides` | object\|null | `null` | `{ "<agent-type>": "<model-id>" }` | Override model selection per agent type |
|
||
| `agent_skills` | object | `{}` | `{ "<agent-type>": "<skill-set>" }` or `{ "<agent-type>": ["<skill-set>", "<skill-set>", ...] }` | Assign skill sets to specific agent types. Each value is a single skill-set path (string) or an array of skill-set paths — the array form assigns multiple skill sets to one agent type. Paths cannot be comma-joined into one string; each path must be its own array element |
|
||
| `sub_repos` | array | `[]` | Array of relative path strings | Child directories with independent `.git` repos (auto-detected) |
|
||
|
||
### Planning Fields
|
||
|
||
These can be set at top level or nested under `planning.*` (e.g., `"planning": { "commit_docs": false }`). Both forms are equivalent; top-level takes precedence if both exist.
|
||
|
||
| Key | Type | Default | Allowed Values | Description |
|
||
|-----|------|---------|----------------|-------------|
|
||
| `planning.commit_docs` | boolean | `true` | `true`, `false` | Alias for top-level `commit_docs` |
|
||
| `planning.search_gitignored` | boolean | `false` | `true`, `false` | Alias for top-level `search_gitignored` |
|
||
|
||
---
|
||
|
||
## Field Interactions
|
||
|
||
Several config fields affect each other or trigger special behavior:
|
||
|
||
1. **`commit_docs` resolution chain** -- Four tiers, highest wins: (1) `phase_commit_docs.<phase-id>` for the phase being committed, (2) an explicit `commit_docs` (or `planning.commit_docs`) value in config.json, (3) `.gitignore` auto-detection (`.planning/` in `.gitignore` resolves to `false`), (4) the manifest default (`true`). Precedence: per-phase → explicit config → gitignore auto-detect → default.
|
||
|
||
2. **`branching_strategy` controls branch templates** -- The `phase_branch_template` and `milestone_branch_template` fields are only used when `branching_strategy` is set to `"phase"` or `"milestone"` respectively. When `branching_strategy` is `"none"`, all template fields are ignored.
|
||
|
||
3. **`context_window` threshold triggers** -- When `context_window >= 500000`, workflows enable adaptive context enrichment: full-body reads of prior phase SUMMARYs, cross-phase context injection in plan-phase, and deeper read depth for anti-pattern references. Below 500000, only frontmatter and summaries are read.
|
||
|
||
4. **`parallelization` polymorphism** -- Accepts both a simple boolean and an object with an `enabled` field. `loadConfig()` normalizes either form to a boolean. `{ "enabled": true }` is equivalent to `true`.
|
||
|
||
5. **Search API keys and flags** -- `brave_search`, `firecrawl`, and `exa_search` are auto-set to `true` during project creation if the corresponding API key is detected (environment variable or `~/.gsd/<name>_api_key` file). Setting them to `true` without the API key has no effect.
|
||
|
||
6. **`planning.*` and top-level equivalence** -- `planning.commit_docs` and `commit_docs` are equivalent; `planning.search_gitignored` and `search_gitignored` are equivalent. If both are set, the top-level value takes precedence.
|
||
|
||
7. **`depth` to `granularity` migration** -- The deprecated `depth` key (`quick`/`standard`/`comprehensive`) is automatically migrated to `granularity` (`coarse`/`standard`/`fine`) on config load and persisted back to disk.
|
||
|
||
8. **`sub_repos` auto-sync** -- On every config load, GSD scans for child directories with `.git` and updates the `sub_repos` array if the filesystem has changed. Legacy `multiRepo: true` is automatically migrated to a detected `sub_repos` array.
|
||
|
||
9. **`workflow.use_worktrees` and branch divergence** -- When `use_worktrees` is `true` (default), executor worktrees are forked from `origin/HEAD` -- by the host's own harness on `dispatch.isolation: harness-worktree` runtimes (Claude Code, Cursor), or by GSD itself on `orchestrator-worktree` runtimes (Codex, OpenCode, Kimi, Kimi Code). The divergence behavior below is identical either way, because the fork base is a property of the repository rather than of whoever creates the worktree. If your current branch has commits that `origin/HEAD` does not (for example an unmerged milestone or feature branch), GSD automatically degrades to sequential execution for that run and prints a one-line `⚠ Worktree base mismatch` warning. To restore parallel execution permanently, set `worktree.baseRef:"head"` in `.claude/settings.local.json` (run `node gsd-tools.cjs worktree set-baseref`). This makes the harness fork worktrees from the live HEAD instead of `origin/HEAD`. Both fresh installs and upgrades of GSD Core set this automatically (no-clobber) when `use_worktrees` is enabled; you can also run the command manually at any time. Setting `workflow.use_worktrees: false` is the alternative if worktrees are not needed at all. On a runtime whose declared `dispatch.isolation` is `none`, an explicit `true` is a config the execution workflows fail closed on; `/gsd:health` reports it as warning `W025` and `/gsd:settings` offers to repair it (#2486).
|
||
|
||
---
|
||
|
||
## Example Configurations
|
||
|
||
### Minimal -- Solo Developer
|
||
|
||
```json
|
||
{
|
||
"model_profile": "balanced",
|
||
"commit_docs": true,
|
||
"workflow": {
|
||
"research": true,
|
||
"plan_check": true,
|
||
"verifier": true,
|
||
"use_worktrees": false
|
||
}
|
||
}
|
||
```
|
||
|
||
### Team Project with Branching
|
||
|
||
```json
|
||
{
|
||
"model_profile": "quality",
|
||
"commit_docs": true,
|
||
"project_code": "APP",
|
||
"git": {
|
||
"branching_strategy": "phase",
|
||
"base_branch": "develop",
|
||
"phase_branch_template": "gsd/phase-{phase}-{slug}"
|
||
},
|
||
"workflow": {
|
||
"research": true,
|
||
"plan_check": true,
|
||
"verifier": true,
|
||
"nyquist_validation": true,
|
||
"use_worktrees": true,
|
||
"discuss_mode": "discuss"
|
||
},
|
||
"manager": {
|
||
"flags": {
|
||
"discuss": "",
|
||
"plan": "",
|
||
"execute": ""
|
||
}
|
||
},
|
||
"response_language": "English"
|
||
}
|
||
```
|
||
|
||
### Large Codebase -- 1M Context with Extended Timeouts
|
||
|
||
```json
|
||
{
|
||
"model_profile": "quality",
|
||
"context_window": 1000000,
|
||
"commit_docs": true,
|
||
"project_code": "MEGA",
|
||
"phase_naming": "sequential",
|
||
"git": {
|
||
"branching_strategy": "milestone",
|
||
"milestone_branch_template": "gsd/{milestone}-{slug}"
|
||
},
|
||
"workflow": {
|
||
"research": true,
|
||
"plan_check": true,
|
||
"verifier": true,
|
||
"nyquist_validation": true,
|
||
"subagent_timeout": 600000,
|
||
"use_worktrees": true,
|
||
"node_repair": true,
|
||
"node_repair_budget": 3,
|
||
"auto_advance": true
|
||
},
|
||
"brave_search": true,
|
||
"hooks": {
|
||
"context_warnings": true
|
||
}
|
||
}
|
||
```
|
||
|
||
</complete_field_reference>
|
||
|
||
</planning_config>
|