Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions agents/gsd-codebase-mapper.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,19 @@ Based on focus, determine which documents you'll write:
- `arch` → ARCHITECTURE.md, STRUCTURE.md
- `quality` → CONVENTIONS.md, TESTING.md
- `concerns` → CONCERNS.md

**Optional `--paths` scope hint (#2003):**
The prompt may include a line of the form:

```
--paths <p1>,<p2>,...
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

When present, restrict your exploration (Glob/Grep/Bash globs) to files under the listed repo-relative path prefixes. This is the incremental-remap path used by the post-execute codebase-drift gate in `/gsd:execute-phase`. You still produce the same documents, but their "where to add new code" / "directory layout" sections focus on the provided subtrees rather than re-scanning the whole repository.

**Path validation:** Reject any `--paths` value containing `..`, starting with `/`, or containing shell metacharacters (`;`, `` ` ``, `$`, `&`, `|`, `<`, `>`). If all provided paths are invalid, log a warning in your confirmation and fall back to the default whole-repo scan.

If no `--paths` hint is provided, behave exactly as before.
</step>

<step name="explore_codebase">
Expand Down
12 changes: 10 additions & 2 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,18 +343,26 @@ GSD uses a multi-agent architecture where thin orchestrators (workflow files) sp

| Property | Value |
|----------|-------|
| **Spawned by** | `/gsd-map-codebase` |
| **Spawned by** | `/gsd-map-codebase`, post-execute drift gate in `/gsd:execute-phase` |
| **Parallelism** | 4 instances (tech, architecture, quality, concerns) |
| **Tools** | Read, Bash, Grep, Glob, Write |
| **Model (balanced)** | Haiku |
| **Color** | Cyan |
| **Produces** | `.planning/codebase/*.md` (7 documents) |
| **Produces** | `.planning/codebase/*.md` (7 documents, with `last_mapped_commit` frontmatter) |

**Key behaviors:**
- Read-only exploration + structured output
- Writes documents directly to disk
- No reasoning required — pattern extraction from file contents

**`--paths <p1,p2,...>` scope hint (#2003):**
Accepts an optional `--paths` directive in its prompt. When present, the
mapper restricts Glob/Grep/Bash exploration to the listed repo-relative path
prefixes — this is the incremental-remap path used by the post-execute
codebase-drift gate. Path values that contain `..`, start with `/`, or
include shell metacharacters are rejected. Without the hint, the mapper
runs its default whole-repo scan.

---

### gsd-debugger
Expand Down
28 changes: 26 additions & 2 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ Equivalent paths for other runtimes:
│ ├── ARCHITECTURE.md
│ └── PITFALLS.md
├── codebase/ # Brownfield mapping (from /gsd-map-codebase)
│ ├── STACK.md
│ ├── ARCHITECTURE.md
│ ├── STACK.md # YAML frontmatter carries `last_mapped_commit`
│ ├── ARCHITECTURE.md # for the post-execute drift gate (#2003)
│ ├── CONVENTIONS.md
│ ├── CONCERNS.md
│ ├── STRUCTURE.md
Expand Down Expand Up @@ -502,6 +502,30 @@ Equivalent paths for other runtimes:
└── continue-here.md # Context handoff (from pause-work)
```

### Post-Execute Codebase Drift Gate (#2003)

After the last wave of `/gsd:execute-phase` commits, the workflow runs a
non-blocking `codebase_drift_gate` step (between `schema_drift_gate` and
`verify_phase_goal`). It compares the diff `last_mapped_commit..HEAD`
against `.planning/codebase/STRUCTURE.md` and counts four kinds of
structural elements:

1. New directories outside mapped paths
2. New barrel exports at `(packages|apps)/<name>/src/index.*`
3. New migration files
4. New route modules under `routes/` or `api/`

If the count meets `workflow.drift_threshold` (default 3), the gate either
**warns** (default) with the suggested `/gsd:map-codebase --paths …` command,
or **auto-remaps** (`workflow.drift_action = auto-remap`) by spawning
`gsd-codebase-mapper` scoped to the affected paths. Any error in detection
or remap is logged and the phase continues — drift detection cannot fail
verification.

`last_mapped_commit` lives in YAML frontmatter at the top of each
`.planning/codebase/*.md` file; `bin/lib/drift.cjs` provides
`readMappedCommit` and `writeMappedCommit` round-trip helpers.

---

## Installer Architecture
Expand Down
2 changes: 2 additions & 0 deletions docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin
| `workflow.pattern_mapper` | boolean | `true` | Run the `gsd-pattern-mapper` agent between research and planning to map new files to existing codebase analogs |
| `workflow.subagent_timeout` | number | `600` | Timeout in seconds for individual subagent invocations. Increase for long-running research or execution phases |
| `workflow.inline_plan_threshold` | number | `3` | Maximum number of tasks in a phase before the planner generates a separate PLAN.md file instead of inlining tasks in the prompt |
| `workflow.drift_threshold` | number | `3` | Minimum number of new structural elements (new directories, barrel exports, migrations, route modules) introduced during a phase before the post-execute codebase-drift gate takes action. See [#2003](https://github.com/gsd-build/get-shit-done/issues/2003). Added in v1.39 |
| `workflow.drift_action` | string | `warn` | What to do when `workflow.drift_threshold` is exceeded after `/gsd:execute-phase`. `warn` prints a message suggesting `/gsd:map-codebase --paths …`; `auto-remap` spawns `gsd-codebase-mapper` scoped to the affected paths. Added in v1.39 |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix command name formatting in the new drift-action docs.

The new row uses : command syntax, which is inconsistent with the rest of the docs and likely to mislead copy/paste usage.

✏️ Suggested doc fix
-| `workflow.drift_action` | string | `warn` | What to do when `workflow.drift_threshold` is exceeded after `/gsd:execute-phase`. `warn` prints a message suggesting `/gsd:map-codebase --paths …`; `auto-remap` spawns `gsd-codebase-mapper` scoped to the affected paths. Added in v1.39 |
+| `workflow.drift_action` | string | `warn` | What to do when `workflow.drift_threshold` is exceeded after `/gsd-execute-phase`. `warn` prints a message suggesting `/gsd-map-codebase --paths …`; `auto-remap` spawns `gsd-codebase-mapper` scoped to the affected paths. Added in v1.39 |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| `workflow.drift_action` | string | `warn` | What to do when `workflow.drift_threshold` is exceeded after `/gsd:execute-phase`. `warn` prints a message suggesting `/gsd:map-codebase --paths …`; `auto-remap` spawns `gsd-codebase-mapper` scoped to the affected paths. Added in v1.39 |
| `workflow.drift_action` | string | `warn` | What to do when `workflow.drift_threshold` is exceeded after `/gsd-execute-phase`. `warn` prints a message suggesting `/gsd-map-codebase --paths …`; `auto-remap` spawns `gsd-codebase-mapper` scoped to the affected paths. Added in v1.39 |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/CONFIGURATION.md` at line 170, The docs row for workflow.drift_action
uses colon-style command tokens `/gsd:execute-phase` and `/gsd:map-codebase`
which is inconsistent with the rest of the guide; update those tokens to the
standard space-separated command format (e.g., `/gsd execute-phase` and `/gsd
map-codebase --paths …`) and keep them in inline code/backticks so the config
key workflow.drift_action and related workflow.drift_threshold text matches the
repo's existing command formatting.


### Recommended Presets

Expand Down
39 changes: 39 additions & 0 deletions docs/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,45 @@
| `TESTING.md` | Test infrastructure, coverage, patterns |
| `INTEGRATIONS.md` | External services, APIs, third-party dependencies |

**Incremental remap — `--paths` (#2003):** The mapper accepts an optional
`--paths <p1,p2,...>` scope hint. When provided, it restricts exploration
to the listed repo-relative prefixes instead of scanning the whole tree.
This is the pathway used by the post-execute codebase-drift gate to refresh
only the subtrees the phase actually changed. Each produced document carries
`last_mapped_commit` in its YAML frontmatter so drift can be measured
against the mapping point, not HEAD.

### 27a. Post-Execute Codebase Drift Detection

**Introduced by:** #2003
**Trigger:** Runs automatically at the end of every `/gsd:execute-phase`
**Configuration:**
- `workflow.drift_threshold` (integer, default `3`) — minimum new
structural elements before the gate acts.
- `workflow.drift_action` (`warn` | `auto-remap`, default `warn`) —
warn-only or spawn `gsd-codebase-mapper` with `--paths` scoped to
affected subtrees.

**What counts as drift:**
- New directory outside mapped paths
- New barrel export at `(packages|apps)/*/src/index.*`
- New migration file (supabase/prisma/drizzle/src/migrations/…)
- New route module under `routes/` or `api/`

**Non-blocking guarantee:** any internal failure (missing STRUCTURE.md,
git errors, mapper spawn failure) logs a single line and the phase
continues. Drift detection cannot fail verification.

**Requirements:**
- REQ-DRIFT-01: System MUST detect the four drift categories from `git diff
--name-status last_mapped_commit..HEAD`
- REQ-DRIFT-02: Action fires only when element count ≥ `workflow.drift_threshold`
- REQ-DRIFT-03: `warn` action MUST NOT spawn any agent
- REQ-DRIFT-04: `auto-remap` action MUST pass sanitized `--paths` to the mapper
- REQ-DRIFT-05: Detection/remap failure MUST be non-blocking for `/gsd:execute-phase`
- REQ-DRIFT-06: `last_mapped_commit` round-trip through YAML frontmatter
on each `.planning/codebase/*.md` file

---

## Utility Features
Expand Down
5 changes: 3 additions & 2 deletions docs/INVENTORY-MANIFEST.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"generated": "2026-04-20",
"generated": "2026-04-22",
"families": {
"agents": [
"gsd-advisor-researcher",
Expand Down Expand Up @@ -110,11 +110,11 @@
"/gsd-spike",
"/gsd-spike-wrap-up",
"/gsd-stats",
"/gsd-sync-skills",
"/gsd-thread",
"/gsd-ui-phase",
"/gsd-ui-review",
"/gsd-ultraplan-phase",
"/gsd-sync-skills",
"/gsd-undo",
"/gsd-update",
"/gsd-validate-phase",
Expand Down Expand Up @@ -264,6 +264,7 @@
"config.cjs",
"core.cjs",
"docs.cjs",
"drift.cjs",
"frontmatter.cjs",
"graphify.cjs",
"gsd2-import.cjs",
Expand Down
3 changes: 2 additions & 1 deletion docs/INVENTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ The `gsd-planner` agent is decomposed into a core agent plus reference modules t

---

## CLI Modules (26 shipped)
## CLI Modules (27 shipped)

Full listing: `get-shit-done/bin/lib/*.cjs`.

Expand All @@ -367,6 +367,7 @@ Full listing: `get-shit-done/bin/lib/*.cjs`.
| `config.cjs` | `config.json` read/write, section initialization; imports validator from `config-schema.cjs` |
| `core.cjs` | Error handling, output formatting, shared utilities, runtime fallbacks |
| `docs.cjs` | Docs-update workflow init, Markdown scanning, monorepo detection |
| `drift.cjs` | Post-execute codebase structural drift detector (#2003): classifies file changes into new-dir/barrel/migration/route categories and round-trips `last_mapped_commit` frontmatter |
| `frontmatter.cjs` | YAML frontmatter CRUD operations |
| `graphify.cjs` | Knowledge-graph build/query/status/diff for `/gsd-graphify` |
| `gsd2-import.cjs` | External-plan ingest for `/gsd-from-gsd2` |
Expand Down
14 changes: 14 additions & 0 deletions docs/USER-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,20 @@ claude --dangerously-skip-permissions
# (normal phase workflow from here)
```

**Post-execute drift detection (#2003).** After every `/gsd:execute-phase`,
GSD checks whether the phase introduced enough structural change
(new directories, barrel exports, migrations, or route modules) to make
`.planning/codebase/STRUCTURE.md` stale. If it did, the default behavior is
to print a one-shot warning suggesting the exact `/gsd:map-codebase --paths …`
invocation to refresh just the affected subtrees. Flip the behavior with:

```bash
/gsd:settings workflow.drift_action auto-remap # remap automatically
/gsd:settings workflow.drift_threshold 5 # tune sensitivity
```

The gate is non-blocking: any internal failure logs and the phase continues.

### Quick Bug Fix

```bash
Expand Down
5 changes: 4 additions & 1 deletion get-shit-done/bin/gsd-tools.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
* verify artifacts <plan-file> Check must_haves.artifacts
* verify key-links <plan-file> Check must_haves.key_links
* verify schema-drift <phase> [--skip] Detect schema file changes without push
* verify codebase-drift Detect structural drift since last codebase map (#2003)
*
* Template Fill:
* template fill summary --phase N Create pre-filled SUMMARY.md
Expand Down Expand Up @@ -593,8 +594,10 @@ async function runCommand(command, args, cwd, raw, defaultValue) {
} else if (subcommand === 'schema-drift') {
const skipFlag = args.includes('--skip');
verify.cmdVerifySchemaDrift(cwd, args[2], skipFlag, raw);
} else if (subcommand === 'codebase-drift') {
verify.cmdVerifyCodebaseDrift(cwd, raw);
} else {
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links, schema-drift');
error('Unknown verify subcommand. Available: plan-structure, phase-completeness, references, commits, artifacts, key-links, schema-drift, codebase-drift');
}
break;
}
Expand Down
2 changes: 2 additions & 0 deletions get-shit-done/bin/lib/config-schema.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const VALID_CONFIG_KEYS = new Set([
'workflow.security_enforcement',
'workflow.security_asvs_level',
'workflow.security_block_on',
'workflow.drift_threshold',
'workflow.drift_action',
'git.branching_strategy', 'git.base_branch', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template',
'planning.commit_docs', 'planning.search_gitignored', 'planning.sub_repos',
'workflow.cross_ai_execution', 'workflow.cross_ai_command', 'workflow.cross_ai_timeout',
Expand Down
11 changes: 11 additions & 0 deletions get-shit-done/bin/lib/config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,17 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
error(`Invalid context value '${value}'. Valid values: ${VALID_CONTEXT_VALUES.join(', ')}`);
}

// Codebase drift detector (#2003)
const VALID_DRIFT_ACTIONS = ['warn', 'auto-remap'];
if (keyPath === 'workflow.drift_action' && !VALID_DRIFT_ACTIONS.includes(String(parsedValue))) {
error(`Invalid workflow.drift_action '${value}'. Valid values: ${VALID_DRIFT_ACTIONS.join(', ')}`);
}
if (keyPath === 'workflow.drift_threshold') {
if (typeof parsedValue !== 'number' || !Number.isInteger(parsedValue) || parsedValue < 1) {
error(`Invalid workflow.drift_threshold '${value}'. Must be a positive integer.`);
}
}

const setConfigValueResult = setConfigValue(cwd, keyPath, parsedValue);
output(setConfigValueResult, raw, `${keyPath}=${parsedValue}`);
}
Expand Down
Loading
Loading