Files
msd-core/docs/AGENTS.md
Dennis Alexis Valin Dittrich 18c899def5 enhance(#4209): optional external source reviewer lanes for /gsd:code-review (#4323)
* test(01-01): define reviewer-support trait contract

Add failing coverage for step.supportsReviewerLanes (#4209 DISP-02):
validator rejects non-boolean values with an exact field path, accepts
missing/true/false, and the real code-review capability.json steps
must declare supportsReviewerLanes: true. Add loop-resolver projection
coverage proving the trait reaches activeHooks verbatim for a
provider-neutral synthetic step (not code-review-specific), and that
omitted/false values stay inert (no key on the active hook).

All 8 new assertions fail today: the validator has no such field, and
loop-resolver has nothing to project. RED before GREEN.

* feat(01-01): declare reviewer-capable steps

Add step.supportsReviewerLanes (#4209 DISP-02): a strict optional
boolean opt-in trait, step-scoped (not capability-wide). Only a
literal true validates and projects; false/omitted stay inert (no
key on the projected active hook), and every non-boolean type fails
capability-validator.cjs with an exact field-path error.

Opt both existing code-review steps (execute:post, execute:wave:post)
into the trait in capabilities/code-review/capability.json. Project
the validated field through src/loop-resolver.cts into activeHooks
so a provider-neutral generic interpreter can read it without any
code-review-specific knowledge. Document the field in
docs/reference/capability-manifest.md and regenerate
gsd-core/bin/lib/capability-registry.cjs via the generator (never
hand-edited).

Makes all 8 RED assertions from the prior commit pass.

* test(01-02): define shared reviewer dispatch

- Add tests/reviewer-step-dispatch.test.cjs covering dispatchReviewerLanes:
  inert when the supportsReviewerLanes trait is off or nothing is selected,
  exactly-once plan/invoke per selected lane, duplicate-alias dedup, the
  bounded metadata-only source-review prompt (repo root, paths+baseSha,
  depth, four fixed prohibitions), and capability-neutral reuse via a
  second synthetic step context.
- RED: module under test (src/reviewer-step-dispatch.cts) does not exist
  yet, so require() fails and every assertion is unreached.

* feat(01-02): dispatch reviewers for opted-in steps

- Add src/reviewer-step-dispatch.cts: dispatchReviewerLanes(input, deps),
  ONE interpreter for a step's supportsReviewerLanes trait. Reuses
  resolveReviewerSelection for selection and resolveLanePlan for planning
  (both already-existing, pure building blocks); invocation is the one
  required, caller-injected seam (deps.invoke) since runLane needs
  OS-aware spawn plumbing this module does not own.
- trait !== true, or a selection resolving to zero lanes, dispatches
  nothing (zero plan/invoke calls). Each selected lane is planned and
  invoked exactly once, in the selector's deduped/sorted order.
- buildSourceReviewPrompt assembles a metadata-only bounded prompt
  (repo root, canonical paths + base SHA, depth, four fixed
  prohibitions) — never file contents — written once per dispatch and
  shared across every invoked lane.
- GREEN: tests/reviewer-step-dispatch.test.cjs now passes.

* test(01-02): define reviewer dispatch failures

- Extend tests/reviewer-step-dispatch.test.cjs with the fail-closed
  matrix: an explicitly requested lane the selector could not resolve
  still lets the OTHER resolved lane run, but the aggregate result must
  never read as a clean success (and 'every explicit lane unavailable'
  must be distinguishable from the plain no-flags-passed inert case);
  request-level validation (path traversal, absolute paths outside
  repoRoot, empty/non-string paths, missing depth/base SHA) halts the
  whole dispatch before any lane is planned or invoked; a per-lane
  prompt-budget overflow hard-fails only that lane before invoke while
  its sibling still runs.
- RED: src/reviewer-step-dispatch.cts does not yet implement any of
  these guards, so 9 of the new assertions fail against the current
  (Task 1) implementation.

* fix(01-02): fail closed in reviewer dispatch

- src/reviewer-step-dispatch.cts: add the fail-closed guards the prior
  commit deliberately left out. An explicitly requested lane the
  selector could not resolve no longer lets the aggregate read as a
  clean success — lanes that DID resolve still run and keep their
  results (never narrow the requested set), but selection.errors now
  flips the aggregate ok to false, and 'every explicit lane
  unavailable' is now distinguishable (SELECTION_FAILED) from the
  plain no-flags-passed inert case (NO_LANES_SELECTED).
- Add request-level validation (validatePaths, depth/baseSha presence)
  that halts the WHOLE dispatch before any lane is planned or invoked:
  path traversal, absolute paths outside repoRoot, empty/non-string
  paths, and missing provenance are all rejected up front.
- Add per-lane prompt-budget enforcement (resolveBudget, mirroring
  gsd-tools.cjs's budgetFor convention including budget 0 = unbounded):
  a lane whose resolved budget the prompt exceeds hard-fails before
  invoke runs for it, without cancelling a sibling lane already
  planned.
- Document the supportsReviewerLanes trait and its dispatch-step
  interpreter in gsd-core/references/loop-hook-dispatch.md.
- GREEN: all 19 tests in tests/reviewer-step-dispatch.test.cjs pass;
  no regressions in the review-lane/reviewer-selection/prompt-budget
  suites (356 passing).

* test(01-03): define optional source reviewer flow

RED: assert code-review.md dispatches roster-derived reviewer-lane flags
through a single review-lane dispatch-step call (DISP-01..05), that the
no-flag path stays byte-for-behavior unchanged (COMP-01), and that
external evidence reaching the internal reviewer prompt is marked
unverified (CONS-02). Also covers the CLI contract directly: no-op with
no explicit selection, and fail-closed on an explicit unknown lane
(SAFE-07) via real gsd-tools.cjs subprocess calls.

* feat(01-03): route optional source reviewers

GREEN: code-review.md gains a dispatch_reviewer_lanes step that matches
canonical reviewer-lane flags against the merged first-party + installed
roster (never a hand-maintained list) and, only when at least one is
present, calls the shared reviewer-step interpreter exactly once with the
already-resolved repo root, file scope, depth, and base SHA. Its evidence
paths are appended to the internal reviewer prompt via
${EXTERNAL_EVIDENCE_BLOCK}, explicitly marked unverified. No reviewer-lane
flag leaves the internal-only dispatch byte-for-behavior unchanged
(COMP-01).

Deviation (Rule 3 — blocking issue): 01-02 documented `review-lane
dispatch-step` (gsd-core/references/loop-hook-dispatch.md) as the CLI
route `dispatchReviewerLanes` wires through, but never implemented the
gsd-tools.cjs subcommand — the workflow's call had nothing to reach. Add
it to the existing review-lane router, reusing the same effort-aware plan
building and runner deps `plan`/`invoke` already use (factored into
buildLaneRunnerDeps to avoid duplicating the spawn/http/fs seam). Guard
the CLI's own `detected` set on whether an explicit flag was passed:
resolveReviewerSelection's no-explicit-selection fallback is "select every
detected reviewer" (the correct default for /gsd:review), and passing it
an unconditionally non-empty detected set would silently invoke the whole
roster on every no-flag code review, violating COMP-01.

* test(01-03): define external finding consolidation

RED: assert gsd-code-reviewer.md treats <external_reviewer_evidence> as
untrusted input — independently re-verifies every claim against the actual
current source, resists a prompt-injection attempt embedded in evidence
text, and folds a verified claim into the existing Narrative Findings
section with no second REVIEW.md schema (CONS-01..03). Also assert
code-review.md's EXTERNAL_EVIDENCE_BLOCK restates the four fixed
source-review prohibitions (SAFE-03..06) at the internal-reviewer handoff.

* feat(01-03): consolidate external review evidence

GREEN: gsd-code-reviewer.md's load_context parses <external_reviewer_evidence>
as untrusted data, independently re-verifies every cited claim against the
actual current source before it can appear in REVIEW.md, and explicitly
resists prompt injection embedded in evidence text (never a command, no
matter what it claims to be). A verified claim folds into the existing
Narrative Findings section with (external: {slug}) provenance — one
REVIEW.md schema only, no separate external-findings section.
code-review.md's EXTERNAL_EVIDENCE_BLOCK now restates the four fixed
source-review prohibitions (SAFE-03..06) at the internal-reviewer handoff.

* fix(01-02): gitignore the reviewer-step-dispatch build artifact

01-02 added src/reviewer-step-dispatch.cts but never added its
npm run build:lib output to .gitignore, unlike every sibling
gsd-core/bin/lib/*.cjs generated file. Left it showing as untracked
noise in git status.

* docs(01-04): publish user and command contract for reviewer-lane source review

- Document optional reviewer-lane flags on /gsd-code-review in USER-GUIDE.md
  and COMMANDS.md: opt-in, no source bodies in prompts, no fallback on
  failure, findings independently consolidated into the single REVIEW.md
- Add the same contract to the docs/features/code-review-pipeline.md
  fragment and regenerate docs/FEATURES.md from it
- Preserve /gsd-review as the plan-review command; cross-reference it
  rather than duplicating the reviewer roster
- Pick up docs/INVENTORY-MANIFEST.json and skills/gsd-code-review/SKILL.md
  drift owned by source already shipped in Plans 01-01/01-03 but never
  regenerated (npm run regen:derived had not been run in this worktree)

* docs(01-04): align architecture and agent ownership docs for reviewer-lane trait

- ARCHITECTURE.md: trace the #4209 capability trait (supportsReviewerLanes)
  through the shared dispatchReviewerLanes interpreter to the existing
  review-lane plan/invoke machinery, ending at gsd-code-reviewer as the
  sole REVIEW.md consolidator
- AGENTS.md: document gsd-code-reviewer's full-context verification scope
  and its treatment of external reviewer evidence as unverified input
- No new diagram, abstraction, or config key; docs/CONFIGURATION.md is
  unchanged since the feature adds no setting or default

* fix(01-02): eslint-ignore the reviewer-step-dispatch build artifact

Same gap as the earlier .gitignore fix: 01-02 added
src/reviewer-step-dispatch.cts but never added its generated
gsd-core/bin/lib/reviewer-step-dispatch.cjs output to
eslint.config.mjs's ignore list like every sibling generated file,
so tsc's emitted __importDefault CommonJS-interop var tripped
no-var.

* fix(01-04): add the reviewer-step-dispatch.cjs roster row to docs/INVENTORY.md

01-04 regenerated docs/INVENTORY-MANIFEST.json (which now lists
cli_modules/reviewer-step-dispatch.cjs) but the hand-written roster
row in docs/INVENTORY.md — required by design, since a role sentence
cannot be generated — was never added.

* fix(01-01): update the code-review capability-step fixture for supportsReviewerLanes

refactor-trigger-cli.test.cjs's preservesCodeReviewHookShapeAlongsideRefactorHook
strict-deep-equals the code-review step's exact shape at execute:post; 01-01 added
supportsReviewerLanes: true to that step and this fixture was not updated.

* chore(01-03): acknowledge emitted-doc growth for code-review.md and gsd-code-reviewer.md

Both files grew as a direct, intended consequence of wiring optional
reviewer lanes into /gsd:code-review (the new dispatch_reviewer_lanes
step and the untrusted-evidence consolidation contract) — not
incidental drift.

Emitted-Drift-Ack-Growth: code-review.md — new dispatch_reviewer_lanes step and EXTERNAL_EVIDENCE_BLOCK wiring for optional reviewer lanes (#4209)
Emitted-Drift-Ack-Growth: gsd-code-reviewer.md — untrusted external-evidence consolidation contract for optional reviewer lanes (#4209)

* test(01-05): define WR-01/WR-02 reliability contract for dispatchReviewerLanes

From internal code review: dispatched must be false when zero lanes
actually reached plan(), and a throwing plan()/invoke() for one lane
must not discard results already collected for a sibling lane —
matching the fail-closed pattern gsd-tools.cjs already uses for the
same resolveLanePlan call (#2494/#2605/#1698/#1936/#2073/#2176/#2589/#2794).

Refs: gsd-core-dks.16, gsd-core-dks.17

* fix(01-05): close WR-01/WR-02/IN-01/IN-02 from internal review

- WR-01: dispatched now tracks whether any lane actually reached
  plan(), not results.length — an unresolvable selected slug no
  longer reports dispatched:true.
- WR-02: plan()/writePromptFile()/invoke() wrapped per-lane so a
  throw for one lane can never discard results already collected
  for a sibling lane, matching the same guard gsd-tools.cjs already
  has around the identical resolveLanePlan call.
- IN-01: documents the intentional budget===0-is-unbounded
  convention (#2797) the caller already relies on.
- IN-02: review-lane dispatch-step no longer blocks indefinitely on
  an un-piped interactive TTY; fails closed to empty paths instead.

Refs: gsd-core-dks.16, gsd-core-dks.17

* docs(01-05): add changeset fragment for PR #17

* fix(01-03): allowlist prompt-injection-scan false positive on the untrusted-evidence contract

agents/gsd-code-reviewer.md's untrusted-evidence section and its
pinning regression test both quote injection phrases as the exact
attack they defend against/detect — same
DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as the existing
allowlist entries, not an actual injection vector.

* test(01-05): extend WR-02 coverage to writePromptFile/invoke throws; DIFF_BASE-empty skip

From CodeRabbit review: WR-02's earlier fix only wrapped plan() —
writePromptFile()/deps.invoke() still ran unguarded, so a throw
there still aborted every later selected lane. Also covers the
dispatch_reviewer_lanes DIFF_BASE-empty-provenance gap (explicit
lanes silently not running when no prior review and no phase-start
commit exist).

* fix(01-05): skip dispatch_reviewer_lanes with a clear warning when DIFF_BASE cannot be resolved

Previously an explicit reviewer-lane request with no prior review and
no resolvable phase-start commit reached dispatch-step with an empty
--base-sha, which fails closed via missing_provenance — correct, but
silent about why explicitly requested lanes didn't run. Now skip
dispatch entirely in that case with a stderr warning naming the
actual cause.

* fix(01-05): wrap writePromptFile/invoke in the same per-lane try/catch as plan()

WR-02's original fix only guarded plan() — a throw from
writePromptFile() or deps.invoke() still aborted the whole dispatch,
discarding results already collected for lanes processed earlier in
the loop. CodeRabbit caught the gap; WR-02b/WR-02c pin it.

* fix(01-05): WR-02b mock must throw only on the first writePromptFile() call

The committed mock threw unconditionally, so codex's retry also threw and
failed for the same reason as claude's — the test could not distinguish
'sibling still runs' from 'sibling also breaks'. Gate the throw to the
first call, matching WR-02/WR-02c's single-failure intent.

* fix(#4209): close review findings from adversarial + critical-code-reviewer pass

Two independent reviews (agy adversarial review, Opus critical-code-reviewer +
ponytail) found 6 Blocking and 7 Required issues in the reviewer-lane dispatch
wiring around dispatchReviewerLanes. All 13 tracked in gsd-core-dks.18-30 and
fixed here:

- dispatch-step's reducer silently swallowed whole-dispatch rejections
  (invalid paths, missing provenance, etc); it now checks parsed.ok/reason.
- spawn_reviewer recomputed its own stale DIFF_BASE, diverging from the
  LAST_REVIEW_COMMIT-aware value dispatch_reviewer_lanes uses on re-review;
  now shares the single compute_file_scope derivation.
- the external reviewer prompt had no actual review request or citation
  requirement, only prohibitions; added both.
- removed the supportsReviewerLanes trait plumbing (capability registry,
  validator, loop-resolver, docs, tests) — it was never consulted by the
  real dispatch path, which gates on explicit CLI flags instead.
- flag-resolution require() was a fragile cwd-relative literal that failed
  silently on non-vendored installs; now resolves via GSD_TOOLS's own
  directory and warns instead of swallowing failure.
- reducer didn't unwrap the @file: overflow protocol for large payloads.
- deduplicated resolveBudget/budgetFor into one resolveLaneBudget.
- lane artifacts now write to a mktemp run dir instead of $PHASE_DIR, so a
  second dispatch can't overwrite prior evidence.
- validatePaths rejects control characters, closing a markdown-injection
  vector into the external prompt via crafted filenames.
- reworded the one line that tripped prompt-injection-scan.sh instead of
  allowlisting the whole production prompt file.
- fixed a stale docstring range and a dispatched-field ordering bug.
- added 3 integration tests executing the actual reducer against synthetic
  dispatch-step JSON, replacing markdown-substring-only assertions.

771/771 tests pass across every touched suite; tsc --noEmit clean.

* fix(#4209): wire supportsReviewerLanes as the maintainer's required reusable trait

The maintainer's approval on issue #4209 explicitly redirected implementation
shape: reviewer-lane dispatch must be a reusable capability/step-dispatch
trait ("supportsReviewerLanes"), not code-review.md hand-wiring the call
itself. My previous commit (e2558326) deleted that trait entirely after
finding it declared-but-never-consulted, which was backwards — the fix was to
wire it, not remove it.

Restores the trait (capability.json, generated registry, validator,
loop-resolver.cts, docs, tests) and wires it for real: dispatch_reviewer_lanes
now resolves its own active hook via `gsd_run loop render-hooks` for the
configured workflow.code_review_point and only proceeds to CLI-flag matching
when supportsReviewerLanes reads true. Explicit flags no longer bypass the
trait; a matching flag with the trait false resolves zero slugs (proven by a
new integration test executing the real fence with both trait states).

Emitted-Drift-Ack-Growth: gsd-core/workflows/code-review.md — the
dispatch_reviewer_lanes step grows a trait-resolution fence (#4209 maintainer
redirect requires the capability layer, not the workflow, own the opt-in
decision).

* fix(#4209): dispatch-step self-verifies the reviewer-lane trait via --cap-id/--point

Both an agy adversarial review and an Opus critical-code-reviewer pass
independently found the same gap in my previous commit (9b2c3773d): the trait
check I wired into code-review.md only protected code-review's OWN
invocation — gsd-tools.cjs's dispatch-step handler still hardcoded
`trait: true` unconditionally, so a second capability declaring
supportsReviewerLanes would get zero enforcement from the shared CLI unless
it correctly re-implemented the ~15-line render-hooks scrape itself. That is
exactly the "each workflow.md hand-wiring the call" the maintainer's redirect
said to eliminate.

Moves the trait check into dispatch-step itself: given --cap-id/--point, it
self-invokes `loop render-hooks <point>` (relocating the one subprocess
code-review.md used to spawn for this, not adding a new one) and derives the
real trait from that capId's active hook, rather than trusting a
caller-passed boolean. code-review.md now only passes
--cap-id code-review --point "$CODE_REVIEW_POINT" and no longer resolves or
gates on the trait itself — the ~20-line scrape it previously carried is
gone. Any other capability opts into the identical enforcement by declaring
the trait and passing the same two flags.

Replaced the two tests that stipulated SUPPORTS_REVIEWER_LANES as an input
variable (they proved a bash branch honors a variable, not that the variable
reflects the real capability manifest) with three integration tests that
invoke the real dispatch-step CLI against the real first-party capability
registry: the real code-review trait resolves true, an unknown --cap-id
resolves false (trait_not_enabled, fail-closed), and omitting
--cap-id/--point entirely resolves false (no context means no opt-in).

Also: reject \x7f/U+2028/U+2029 in validatePaths' control-character check
(agy-F1 was incomplete), and delete the promptWritten per-lane coupling
flag — the prompt write is idempotent, so writing it once per lane instead
of gating on "did any lane write it yet" removes a latent bug where a
deps.plan override that ever varies promptPath per lane would silently skip
writing for a later lane.

Emitted-Drift-Ack-Growth: gsd-core/workflows/code-review.md — net line count
drops (the trait scrape moved into dispatch-step), but the file still grew
this session across multiple commits; acknowledging per the growth-tracking
convention.

* fix(#4209): remove per-run token waste from the shipped prompts

Runtime prompt content, not session tokens: two real, per-invocation token
costs in the code that ships.

1. agents/gsd-code-reviewer.md's critical_rules restated nearly all of
   load_context step 5's ~180-word untrusted-evidence contract in ~90 more
   words, breaking this section's own established terse one-liner style
   (every other rule here is 1-2 sentences). This prompt loads fresh on
   every /gsd:code-review invocation. Shrunk to a one-line cross-reference,
   matching how write_review's own reference to step 5 already does it.

2. buildSourceReviewPrompt repeated the base SHA on every single file line
   even though it is identical for every file and already stated once at
   the top of the prompt — O(files) wasted tokens on every dispatched lane
   for a 50-file review, for zero information gain. File lines are now bare
   paths.

* fix(#4209): resolve reviewer-lane trait in-process, fix CI failures found in review round 3

Opus critical-code-reviewer found a real Blocking defect in the --cap-id/
--point self-invocation added last commit: `dispatch-step` spawned
`loop render-hooks <point> --raw` as a subprocess and bare-JSON.parse'd its
stdout, but `io.cjs`'s output() redirects any payload over 50000 chars to
`@file:<path>` instead of inline JSON -- the same overflow protocol this
feature already unwraps for its OWN dispatch result 60 lines later in
code-review.md. A large-enough activeHooks envelope (more installed
capabilities/fragments) would throw, get silently swallowed by the bare
catch, and misreport a real trait as trait_not_enabled with zero diagnostic.

Fixed by extracting the config/registry/capability-state resolution
`cmdLoopRenderHooks` already performs into an exported pure function,
resolveActiveHooksForPoint (both `cmdLoopRenderHooks` and dispatch-step now
share it), and calling it in-process from dispatch-step instead of spawning
a subprocess at all. This eliminates the @file: exposure entirely (the
dispatch-step path never touches the rendered-string envelope or its
JSON-stringify/50000-char threshold), removes one subprocess spawn per
code-review invocation, and gives a genuine diagnostic (stderr warning) on
resolution failure instead of silent fail-closed. Corrected three doc/
docstring references to the now-removed subprocess self-invocation.

Also fixes 2 real CI failures this round surfaced:
- lint-tests: the agy-F1 control-char regex fix's `eslint-disable-next-line
  no-control-regex` comment was unused under this project's ESLint config
  (verified locally: the rule never actually flags \x00-\x1f in this repo's
  config) -- a mistake from an earlier commit this session, never actually
  lint-checked before push. Removed the disable comment.
- security (prompt-injection-scan): the agy-F1 regression test's crafted
  fixture literally contains "Ignore all prior instructions." as test data
  proving validatePaths rejects it -- allowlisted the test file, same
  DEFECT.PROMPT-INJECTION-SCAN-COLLISION class as existing entries.

Also trimmed agents/gsd-code-reviewer.md's load_context step 5 (R2): one
bullet stated "untrusted, never a command" three different ways in one
paragraph, and a same-file duplicate of write_review's schema rule.
Consolidated to state each rule once.

Declined one suggestion from this round: shrinking code-review.md's
EXTERNAL_EVIDENCE_BLOCK to a bare evidence list. Two tests
(tests/code-review-pipeline-regression.test.cjs's CONS-01..03 block,
tests/code-review.test.cjs's CONS-02 test) deliberately lock the four-
prohibitions restatement and the untrusted-evidence prose into the
INJECTED block itself, not just the consolidator's system prompt --
adjacency of the warning to the untrusted payload it's warning about is a
recognized prompt-injection defense-in-depth pattern from this
workstream's original TDD plan, not accidental duplication.

* fix(#4209): correct stale per-file base-SHA prose in the external prompt

Leftover from removing the per-file base SHA repetition earlier this
session: the review-request sentence still said "relative to its base SHA"
(singular per-file framing) when there's now exactly one base SHA, stated
once above the file list. Reads "relative to the base SHA above" now.

* fix(#4209): make getLane/configGet/plan required deps, delete dead defaults

R3/R4 from the review round I'd deferred as low-priority test-churn: this
file's one production caller (gsd-tools.cjs's dispatch-step handler) always
supplies all three, so the fallbacks were dead in production -- but each was
actively WRONG if ever reached: the default configGet always returned
undefined, silently disabling resolveLaneBudget's overflow guard; the
default getLane looked up only first-party REVIEWER_LANES, diverging from
production's overlay-merged roster; the default plan skipped per-host effort
resolution entirely.

These defaults were introduced by this PR's own earlier work (this file did
not exist before #4209 -- first commit a760bfcda, 01-02), not inherited from
elsewhere, so there's no external caller depending on the lenient contract.

Turned out free to fix: making the three deps required and deleting
defaultGetLane/defaultPlan needed zero test changes -- every existing test
that actually reaches the per-lane loop already supplies getLane/plan
explicitly, and configGet's only real dependent (the budget-overflow tests)
already supplies it too. 788/788 tests pass unchanged, tsc/lint clean.

* fix(#4209): define depth semantics for the external reviewer lane

Verified this was a real bug, not a match to existing convention as I'd
claimed when declining the suggestion earlier this session: the internal
gsd-code-reviewer agent's own system prompt carries a full <depth_levels>
block defining what quick/standard/deep mean and do (agents/gsd-code-
reviewer.md:68-99). The external reviewer lane has no access to that
persona at all -- it only ever sees buildSourceReviewPrompt's bounded text,
which sent the bare depth label with zero definition to a third-party CLI
with no other source of truth for what "standard" means.

Added depthMeaning(), condensed from the internal reviewer's own
<depth_levels> definitions so the two stay consistent, and interpolated it
into the review-request sentence. 150/150 tests pass, tsc/lint clean.

* fix(#4209): merge dispatch_reviewer_lanes' split fences into one shell invocation

CR-01 (Opus critical-code-reviewer, confirmed by direct execution): the
roster-matching fence set EXPLICIT_JOINED/EXPLICIT_REVIEWER_SLUGS, and a
SEPARATE later fence read them via ${#EXPLICIT_REVIEWER_SLUGS[@]} to decide
whether to dispatch at all. This file's own documented rule (its
depth-resolution guard, stated explicitly a few hundred lines earlier) is
that a guard and the extraction it protects must run as one shell
control-flow decision, because markdown-fenced blocks do not share shell
state -- this step violated its own file's rule for the entire feature's
gating condition.

Merged the roster-resolution fence and the dispatch-decision fence into one
continuous bash block, removing the intervening prose that split them.
Fixed the stderr-based failure detection in the same edit (RQ-01: checking
whether stderr is non-empty misfires on any benign Node warning; now checks
the actual exit status of the roster-resolution command).

Verified by extracting the merged fence and executing it standalone, driving
both branches: --codex resolves EXPLICIT_JOINED=codex, SLUGS_COUNT=1, and a
real dispatch-step call succeeds; no flags resolves EXPLICIT_JOINED empty,
SLUGS_COUNT=0, dispatch-step never invoked (COMP-01). 141/141 workflow tests
pass, tsc/lint clean.

* fix(#4209): depthMeaning accuracy, injection defense on all embedded fields, hoisted prompt write

Batch of Required/Suggestion fixes from the Opus critical-code-reviewer +
writing-for-agents pass:

- CR-02/CR-03: depthMeaning() dropped real categories from quick (empty catch
  blocks, commented-out code) and deep (error propagation, state mutation
  consistency, circular dependencies) relative to the real <depth_levels>
  block, and had zero test coverage. Restored full accuracy and added tests
  that read the real agents/gsd-code-reviewer.md file directly, so drift
  between the two can't recur silently. Unrecognised depth now normalizes to
  standard's definition, matching that agent's own documented rule, instead
  of rendering an undefined bare label.

- RQ-04: depth/baseSha/repoRoot/runDir land in the same markdown prompt
  `paths` does, but weren't checked for control characters like paths were
  (agy-F1's original finding). Hoisted CONTROL_CHAR to module scope and
  applied it to all four fields at the same provenance-check boundary.
  runDir previously had zero validation at all.

- S1: deleted the dead `identity` parameter on `invoke` -- the one production
  caller already ignores it, no test read it by name.

- S2: hoisted the shared prompt write above the per-lane loop -- promptPath
  is derived from runDir alone (constant across lanes by construction), so
  writing it once is both correct and cheaper than the per-lane write R1
  introduced earlier this session. Discovered and fixed a real regression
  from the naive version of this hoist: an unguarded throw would have
  escaped dispatchReviewerLanes as an uncaught exception instead of a clean
  per-lane failure. Added a new PROMPT_WRITE_FAILED whole-dispatch reason,
  matching the existing validatePaths/MISSING_PROVENANCE halt pattern, with
  a dedicated regression test.

- S3: moved `planned = true` past the budget-overflow gate, so `dispatched`
  only reports true once a lane has cleared BOTH plan and budget checks.

- S5: relayed gsd-code-reviewer.md's own "performance issues are out of
  scope unless also correctness issues" policy into the external-lane
  prompt, which previously had no such guidance and could return findings
  the internal reviewer's own contract excludes.

- RQ-05 (partial): shrunk this file's own header docstring's restatement of
  the trait-reuse architecture to a pointer at
  gsd-core/references/loop-hook-dispatch.md, the canonical home.

234/234 tests pass across the full reviewer-lane test suite, tsc/lint clean.

* fix(#4209): dedupe roster-merge logic, consolidate trait architecture prose, add step completion criterion

RQ-02: added a `review-lane explicit-from-argv` subcommand that reuses the
SAME merged-roster logic (`laneBySlug`) `dispatch-step`/`plan`/`invoke`
already share. code-review.md's ~18-line inline `node -e` reimplementing
`loadRegistry`+`mergeReviewerLanes` (a rename-only copy of the block in
gsd-tools.cjs) is now a single call to this subcommand -- the exact
violation code-review-flags.cjs's own header warns against ("this is the
canonical flag-parsing surface -- do not replicate inline bash parsing").

RQ-03: an empty --cap-id XOR --point now warns distinctly from the
legitimate no-context opt-out (both absent) -- a caller that named a
capability without its point was silently indistinguishable from a correct
opt-out. Also hardened the CODE_REVIEW_POINT config-get fallback: it only
ever fires when the config-get COMMAND ITSELF fails (config-get already
resolves the manifest's own schema default in the normal case), but that
failure was previously silent.

RQ-05/W-01/W-12/W-13: the "supportsReviewerLanes is a reusable trait
resolved inside dispatch-step" explanation was restated in full in 5
places across this session's own review cycles. Consolidated to ONE
canonical statement in gsd-core/references/loop-hook-dispatch.md; the other
4 (this file's own header, gsd-tools.cjs's comment, docs/ARCHITECTURE.md,
code-review.md's step-opening comment) now point at it instead.

W-05/W-06: loop-hook-dispatch.md described "false or non-boolean" as two
inert cases when capability-validator.cjs already rejects non-boolean at
load -- restated as the two cases that actually reach this code. Removed a
"do not hand-roll trait resolution" prohibition whose target no longer
exists once the positive description precedes it.

W-04: deleted a no-op sentence in agents/gsd-code-reviewer.md ("missing
block means proceed as normal") -- an absent optional block already means
proceed as normal without being told.

W-08/W-09: replaced longhand "zero selection/plan/invoke calls" and the
made-up compound "byte-for-behavior [un]changed" with the token this
session's own docs already coined for this concept (inert) and the word
that means what byte-for-behavior was reaching for (unchanged).

W-10: dispatch_reviewer_lanes had no completion criterion -- added one
sentence naming the checkable end state (EXTERNAL_EVIDENCE_BLOCK is set,
either populated or empty). This exact sentence would have caught the
cross-fence bug fixed two commits ago at authoring time.

Declined from this round, with reasoning: W-02/W-03 (trim the
untrusted-evidence restatement in EXTERNAL_EVIDENCE_BLOCK/critical_rules) --
two tests deliberately lock this as intentional adjacency-based
prompt-injection defense-in-depth, not accidental duplication (see this
branch's own earlier commit). S4 (wrap LANE_RUN_DIR in a creation-site
`trap ... EXIT`) -- would fire at the end of the CREATING fence, before
spawn_reviewer's agent ever reads the evidence files, given this file's own
documented fenced-block execution model; the existing named cross-reference
between creation and cleanup already satisfies the co-location concern
without introducing that regression.

853/853 tests pass across the full reviewer-lane test suite, tsc/lint clean.

* fix(#4209): merge CODE_REVIEW_POINT into dispatch_reviewer_lanes' one fence, stop test from spawning real codex

Round-5 review (agy) found the same cross-fence-split bug CR-01 already fixed
for EXPLICIT_JOINED/EXPLICIT_REVIEWER_SLUGS: CODE_REVIEW_POINT's config-get
fallback lived in an earlier, separate fence from the fence that consumes it
via --point, split only by prose (not a guard, per this step's own documented
rule). Merged into the single continuous fence and added a structural test
asserting exactly one bash fence in the step.

The new end-to-end regression test for this used --codex, which drives the
fence's real `review-lane dispatch-step` call and, with the codex binary
present on PATH, spawns the real external CLI — which then blocks on
interactive auth with no stdin (BL-01). Stubbed gsd_run for
`review-lane dispatch-step` only (captures argv instead of executing),
keeping the real config-get/explicit-from-argv calls the test is actually
about.

* fix(#4209): split control-char vs missing provenance reason, realpath-check path escapes, stale comment

Round-5 review (Opus) warning-tier findings:

- WR-04: MISSING_PROVENANCE covered both "field absent" and "field present but
  a control-character injection attempt" — a caller distinguishing a config
  problem from a security event couldn't tell them apart. Split into
  MISSING_PROVENANCE (absent) and INVALID_PROVENANCE (present but invalid).
- WR-05: validatePaths' containment check was lexical only (path.resolve),
  so a symlink whose own path sits inside repoRoot could still point outside
  it. Added an fs.realpathSync check (ENOENT-tolerant — a git-diff path can
  legitimately name a file already deleted in a stale worktree), realpathing
  repoRoot itself too so a symlinked repoRoot (e.g. /tmp on macOS) doesn't
  false-positive-reject its own real children.
- WR-08: a comment in the per-lane loop still said a throwing writePromptFile()
  was caught there — stale since the prompt write was hoisted above the loop
  in an earlier round.

WR-03 (validate depth against the quick/standard/deep enum) was considered
and declined: this dispatcher is deliberately capability-neutral (see the
existing "synthetic step context" test, which passes a non-code-review depth
label on purpose to prove no code-review-specific special-casing exists).
WR-01 (double registry load), WR-02 (trim-vs-hard-fail budget semantics), and
WR-07 (reason omitted on the aggregate return) were verified against source
and are not bugs — see review notes.

* docs(#4209): document LANE_RUN_DIR's early-exit trade-off as accepted, not a gap

Round-5 review (Opus, BL-03) flagged that an early exit between
dispatch_reviewer_lanes and commit_review leaks the run-scoped temp dir. A
trap-based cleanup was considered and rejected: if a step genuinely runs as
a separate process, a trap set at creation time would fire at the end of
that SAME fence, deleting the directory before spawn_reviewer/commit_review
ever read it — worse than the leak it would fix.

review.md's own gather_context/cleanup pair for the identical resource class
(a run-scoped reviewer temp dir) already makes and documents this exact
trade-off: cleanup runs only on a documented success path, and a leftover
$TMPDIR entry is explicitly called cheaper than destroyed evidence. Recording
that precedent here so this isn't re-raised as a live gap in a future review.

* fix(#4209): register the WR-05 symlink-escape test's synthetic docs/ path

reviewer-step-dispatch.test.cjs's "capability-neutral reuse" fixture passes
paths: ['docs/spec.md'] as a synthetic, never-read path proving the
dispatcher has no code-review-specific special-casing. lint-docs-guard-
registration correctly flagged this as an unregistered docs/ path reference —
add the docs-guard-exempt marker and its pinned baseline entry, the same
pattern every other synthetic docs/ literal in this test suite already uses.

* fix(#4209): backfill changeset pr: field with the real upstream PR number

changeset-lint's fail_pr_field_drift caught the fragment still pointing at
the fork PR (17) instead of the upstream one (open-gsd/gsd-core#4323) this
branch is now also open against.

* docs(#4209): amend ADR-2782 for the supportsReviewerLanes step-trait seam

trek-e's review (2026-09-07, gsd-core#4323) found a real ADR gap: every
decision in ADR-2782 (D1-D9) and every prior dated amendment governs the
`role: "reviewer"` capability body and its one consumer, /gsd:review. This
PR's actual new seam - a `supportsReviewerLanes: true` trait on an ordinary
feature capability's `steps[]` entry, projected through loop-resolver.cts
and resolved in-process via resolveActiveHooksForPoint - is a different
capability axis (steps/gates/contributions) that the ADR's own scope note
explicitly places out of reach. Per docs/contributor-standards.md's
"Amending an accepted ADR", an in-place dated section is the established,
lighter-weight path for an addition that stays within the ADR's existing
decisions - used twice already in this same file - so this appends a third
dated entry documenting the new seam, its consumer, and why it reuses the
existing D1-D9-governed plan/invoke machinery rather than adding a second
one. No decision is reversed; no new Amends/Amended-by pair is needed since
the steps/gates/contributions axis already carries reciprocal links to
ADR-857 and ADR-894.

* fix(#4209): close two test-quality gaps trek-e's review found

Minor 1: validatePaths (a path-shape parser guarding the prompt-
injection/path-traversal trust boundary) had only example-based coverage,
violating ADR-456's rule that parsers/budget limits carry at least one
fast-check property test. Adds three: safe-segment paths are never
rejected, a single leading "../" always escapes the one-segment repoRoot,
and a control character anywhere is always rejected - one property per
rejection reason validatePaths owns.

Minor 2: the budget-overflow check (`estimatedTokens > budget`) was only
ever exercised far below budget or at budget:0 (unbounded), never at the
exact threshold crossing where a `>` vs `>=` off-by-one would hide. Adds
three exact-boundary tests using the real estimateTokens/
buildSourceReviewPrompt the module calls internally, so the resolved
token count is exact rather than approximated: budget == estimate (must
pass), budget == estimate - 1 (must fail), budget == estimate + 1 (must
pass).

Also extracts okPlan()'s fixture timeoutMs into a named constant -
local/no-adhoc-timeout-literal (#4446) landed on next after this branch
was authored and flagged the pre-existing literal on rebase; it is fixture
data for a synthetic plan object dispatchReviewerLanes never waits on, a
distinct class from tests/helpers/timeouts.cjs's real subprocess norms.

* fix(#4209): update docs-guard-registration baseline for the new ADR citation

reviewer-step-dispatch.test.cjs's new fast-check property tests cite
docs/adr/456-test-rigor-architecture.md in a justifying comment (never a
real read). lint-docs-guard-registration fingerprints every docs/ path
string an exempted test file mentions and fails on drift so a human
re-confirms the exemption still holds - re-confirmed, and the baseline is
updated to match.

* fix(#4209): point changeset pr: field at the fork PR for CI validation

changeset-lint's fail_pr_field_drift check compares the fragment's pr:
field against the PR the CI run is actually attached to (GITHUB_EVENT_PATH),
not a fixed target. Rehearsing this branch on fork PR
davdittrich/gsd-core#17 needs pr: 17 to pass that check; the prior commit's
pr: 4323 (the real open-gsd upstream PR number) is correct for that PR but
fails here. Backfill to 4323 happens again, as the last commit, immediately
before the approved push to open-gsd#4323 - never leaving pr: 17 on the
branch that ships upstream.

* fix(#4209): reject promptChannel:none lanes from source-review dispatch

CodeRabbit found a real scope mismatch: coderabbit's lane declares
promptChannel: 'none' and reviews the working tree on its own terms,
fed nothing (review.md:367). Silently dispatching it through
dispatchReviewerLanes would ignore the bounded paths/depth/baseSha scope
buildSourceReviewPrompt promises and let the lane review whatever it
independently sees fit, violating this interpreter's own scoped,
metadata-only contract. Reject before plan()/invoke(), same as an
unresolved slug.

* fix(#4209): scope CONS-02 test to the evidence-block line, not the whole file

CodeRabbit found the whole-file match on workflowContent would still
pass if UNVERIFIED and re-open/reopen appeared in two unrelated parts
of this 1000+-line workflow, proving nothing about the actual evidence
block's contract. Line-filtered via splitLines (not a bare-\n regex
spanning readFileSync content) so this stays CRLF-portable and passes
local/no-unbounded-quantifier and local/no-crlf-fragile-split.

* fix(#4209): guard DISPATCH_JSON substitution and capture its stderr

CodeRabbit found the dispatch-step command substitution unguarded: a
non-zero exit could leave DISPATCH_JSON empty (or halt the step under
errexit with no warning), and the downstream reducer would only ever
report the generic unparseable_dispatch_output reason, discarding the
command's own diagnostic. Guarded like the existing CODE_REVIEW_POINT/
EXPLICIT_JOINED calls above it: capture stderr to a temp file, surface
it in a warning on failure, and fall back to a parseable dispatch_
command_failed JSON stub so the reducer's existing reason-reporting
path still fires.

* docs(#4209): fix byte-for-behavior wording and missing colon, regenerate

CodeRabbit found "byte-for-behavior" should read "byte-for-byte" (the
established repo term for output-identical unchanged behavior) and a
missing colon after the bold "Optional external reviewer lanes (#4209)"
lead-in in docs/features/code-review-pipeline.md. Fixed in the two
hand-authored sources (commands/gsd/code-review.md, docs/features/
code-review-pipeline.md) and regenerated the two derived projections
(skills/gsd-code-review/SKILL.md via gen-plugin-skills.cjs, docs/
FEATURES.md via gen-features.cjs) so they stay in sync.

* fix(#4209): drop the fabricated DISPATCH_JSON fallback stub (Windows CI)

The prior fix's fallback `DISPATCH_JSON='{"ok":false,...}'` embeds
double-quoted JSON keys inside a single-quoted shell literal. That
extra quote density, inside an already quote-heavy ~8KB driver string,
passed bash -n and the full local suite on Linux but broke Windows
Git-Bash: `dispatch_reviewer_lanes computes CODE_REVIEW_POINT ... end
to end (#4209 round 5)` failed on two Windows CI shards with `bash -c:
unexpected EOF while looking for matching '''` — a Windows argv-to-
command-line re-quoting edge case, reproducible on rerun, not a flake.
Root-caused via gh api job logs plus a byte-identical local
reconstruction of the test's own driver script.

Fix: drop the fabricated stub. The downstream node -e reducer already
falls back to reason `unparseable_dispatch_output` on any JSON.parse
failure, so an empty/partial DISPATCH_JSON on command failure is still
handled correctly, with zero new quoting risk.

* revert(#4209): drop the DISPATCH_JSON stderr-guard nitpick (Windows CI)

Two materially different mechanisms for the same CodeRabbit Nitpick
("Trivial | Quick win") both broke Windows Git-Bash reproducibly:
a single-quoted JSON-literal fallback ("bash -c: unexpected EOF ...
matching '''") and, after removing that, a plain `head -1 "$VAR"`
inside a nested command substitution ("unexpected EOF ... matching
'"'"). Both passed bash -n and the full local suite on Linux every
time; both failed the SAME test deterministically on Windows CI. Two
attempts at the same class of fix (nested-quote construction near
this exact step) is the retry limit - reverting to the original,
already-shipped, Windows-verified unguarded form rather than
continuing to guess at a third quoting mechanism for a Trivial-
severity nitpick. Logged as bug-221/bug-222 in .wolf/buglog.json for
anyone attempting this again: the fix belongs outside this specific
markdown-fence-driver test harness (e.g., a real .sh helper script)
if it's worth doing at all.

* fix(#4209): backfill changeset pr: field to the real upstream PR before push

Fork validation (davdittrich/gsd-core#17) needed pr: 17 to satisfy
changeset-lint's PR-number check while rehearsing there; this is the
last commit before the approved push to the real upstream PR
(open-gsd/gsd-core#4323), so the field points at that PR number again.

---------

Co-authored-by: Test <test@test.com>
Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
2026-09-07 22:52:33 -04:00

46 KiB
Raw Blame History

GSD Agent Reference

Full role cards for 22 primary agents plus concise stubs for 12 advanced/specialized agents (34 shipped agents total). The agents/ directory and docs/INVENTORY.md are the authoritative roster; see Architecture for context.


Overview

GSD uses a multi-agent architecture where thin orchestrators (workflow files) spawn specialized agents with fresh context windows. Each agent has a focused role, limited tool access, and produces specific artifacts.

Required reading (#3423): the canonical spawn-block tag is <required_reading> on BOTH sides — orchestrators emit it, and gating agents enforce it ("you MUST use the Read tool to load every file listed there before performing any other actions"). The legacy <files_to_read> emit-tag is retired and banned repo-wide by tests/agent-required-reading-consistency.test.cjs, because a mismatched pair silently disarms the enforcement clause.

Agent Categories

The table below covers the 22 primary agents detailed in this section. Thirteen additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater, doc-classifier, doc-synthesizer, mempalace-curator) have concise stubs in the Advanced and Specialized Agents section below. For the authoritative 35-agent roster, see docs/INVENTORY.md and the agents/ directory.

Category Count Agents
Researchers 3 project-researcher, phase-researcher, ui-researcher
Analyzers 2 assumptions-analyzer, advisor-researcher
Synthesizers 1 research-synthesizer
Planners 1 planner
Roadmappers 1 roadmapper
Executors 1 executor
Checkers 3 plan-checker, integration-checker, ui-checker
Verifiers 2 verifier, dom-verifier
Auditors 3 nyquist-auditor, ui-auditor, security-auditor
Mappers 1 codebase-mapper
Debuggers 1 debugger
Doc Writers 2 doc-writer, doc-verifier
Profilers 1 user-profiler

Agent Details

gsd-project-researcher

Role: Researches domain ecosystem before roadmap creation.

Property Value
Spawned by /gsd-new-project, /gsd-new-milestone
Parallelism 4 instances (stack, features, architecture, pitfalls)
Tools Read, Write, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__, mcp__plugin_context7_context7__, mcp__firecrawl__, mcp__exa__, mcp__tavily__, mcp__ref__, mcp__jina__, mcp__perplexity__
Model (balanced) Sonnet
Color Cyan
Produces .planning/research/STACK.md, FEATURES.md, ARCHITECTURE.md, PITFALLS.md

Capabilities:

  • Web search for current ecosystem information
  • Context7 MCP integration for library documentation
  • Writes research documents directly to disk (reduces orchestrator context load)

gsd-phase-researcher

Role: Researches how to implement a specific phase before planning.

Property Value
Spawned by /gsd-plan-phase
Parallelism 4 instances (same focus areas as project researcher)
Tools Read, Write, Edit, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__, mcp__plugin_context7_context7__, mcp__firecrawl__, mcp__exa__, mcp__tavily__, mcp__ref__, mcp__jina__, mcp__perplexity__
Model (balanced) Sonnet
Color Cyan
Produces {phase}-RESEARCH.md

Capabilities:

  • Reads CONTEXT.md to focus research on user's decisions
  • Investigates implementation patterns for the specific phase domain
  • Detects test infrastructure for Nyquist validation mapping
  • Tags in-repo discrete values (enums, schema unions, error codes, status constants, paths) [VERIFIED] only after reading the source-of-truth file that run, citing path and line range, and quoting the values verbatim
  • Refuses [VERIFIED] for a compatibility claim resting on missing metadata (no python_requires, no engines field, no per-version classifier, no changelog entry, no matching support-matrix row) — an absence constrains no version, and an enumerated allow-list that stops short of the target is still an absence, so only a positive falsification attempt with its failing output pasted earns the tag; anything less stays [ASSUMED]

gsd-ui-researcher

Role: Produces UI design contracts for frontend phases.

Property Value
Spawned by /gsd-ui-phase
Parallelism Single instance
Tools Read, Write, Edit, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__, mcp__plugin_context7_context7__, mcp__firecrawl__, mcp__exa__, mcp__tavily__, mcp__ref__, mcp__jina__*
Model (balanced) Sonnet
Color Purple
Produces {phase}-UI-SPEC.md

Capabilities:

  • Detects design system state (shadcn components.json, Tailwind config, existing tokens)
  • Offers shadcn initialization for React/Next.js/Vite projects
  • Asks only unanswered design contract questions
  • Enforces registry safety gate for third-party components
  • Enumerates the component inventory rather than recalling it (#2845): the UI-SPEC's ## Component Inventory carries a provenance line — the command that enumerated it, the count it returned, the resolved <package>@<version>, and the date — or, when nothing can enumerate it, a Could not enumerate: <reason> record in the same slot

gsd-assumptions-analyzer

Role: Deeply analyzes codebase for a phase and returns structured assumptions with evidence, confidence levels, and consequences if wrong.

Property Value
Spawned by discuss-phase-assumptions workflow (when workflow.discuss_mode = 'assumptions')
Parallelism Single instance
Tools Read, Bash, Grep, Glob, Skill
Model (balanced) Sonnet
Color Cyan
Produces Structured assumptions with decision statements, evidence file paths, confidence levels

Key behaviors:

  • Reads ROADMAP.md phase description and prior CONTEXT.md files
  • Searches codebase for files related to the phase (components, patterns, similar features)
  • Reads 5-15 most relevant source files to form evidence-based assumptions
  • Classifies confidence: Confident (clear from code), Likely (reasonable inference), Unclear (could go multiple ways)
  • Flags topics that need external research (library compatibility, ecosystem best practices)
  • Output calibrated by tier: full_maturity (3-5 areas), standard (3-4), minimal_decisive (2-3)

gsd-advisor-researcher

Role: Researches a single gray area decision during discuss-phase advisor mode and returns a structured comparison table.

Property Value
Spawned by discuss-phase workflow (when ADVISOR_MODE = true)
Parallelism Multiple instances (one per gray area)
Tools Read, Bash, Grep, Glob, Skill, WebSearch, WebFetch, mcp__context7__, mcp__plugin_context7_context7__
Model (balanced) Sonnet
Color Cyan
Produces 5-column comparison table (Option / Pros / Cons / Complexity / Recommendation) with rationale paragraph

Key behaviors:

  • Researches a single assigned gray area using Claude's knowledge, Context7, and web search
  • Produces genuinely viable options — no padding with filler alternatives
  • Complexity column uses impact surface + risk (never time estimates)
  • Recommendations are conditional ("Rec if X", "Rec if Y") — never single-winner ranking
  • Output calibrated by tier: full_maturity (3-5 options with maturity signals), standard (2-4), minimal_decisive (2 options, decisive recommendation)

gsd-research-synthesizer

Role: Combines outputs from parallel researchers into a unified summary.

Property Value
Spawned by /gsd-new-project (after 4 researchers complete)
Parallelism Single instance (sequential after researchers)
Tools Read, Write, Bash, Skill
Model (balanced) Sonnet
Color Purple
Produces .planning/research/SUMMARY.md

gsd-planner

Role: Creates executable phase plans with task breakdown, dependency analysis, and goal-backward verification.

Property Value
Spawned by /gsd-plan-phase, /gsd-quick
Parallelism Single instance
Tools Read, Write, Edit, Bash, Glob, Grep, Skill, WebFetch, mcp__context7__, mcp__plugin_context7_context7__
Model (balanced) Opus
Color Green
Produces {phase}-{N}-PLAN.md files

Key behaviors:

  • Reads PROJECT.md, REQUIREMENTS.md, CONTEXT.md, RESEARCH.md
  • Creates 2-3 atomic task plans sized for single context windows
  • Uses XML structure with <task> elements
  • Emits a <fails_when> sibling for every runnable <automated> verify command, naming what output constitutes failure (#3172)
  • Includes read_first and acceptance_criteria sections
  • Groups plans into dependency waves
  • Performs reachability check to validate plan steps reference accessible files and APIs (v1.32)
  • Enforces a comment-text discipline HARD GATE at plan-write time (verify.plan-structure): a literal that an acceptance criterion negative-greps for (grep -c 'LIT' file == 0) must not appear verbatim in an <action> body; violations fail plan creation. Use <!-- planner-discipline-allow: LIT --> to allowlist a legitimate occurrence. (#429)

gsd-roadmapper

Role: Creates project roadmaps with phase breakdown and requirement mapping.

Property Value
Spawned by /gsd-new-project
Parallelism Single instance
Tools Read, Write, Bash, Glob, Grep, Skill
Model (balanced) Sonnet
Color Purple
Produces ROADMAP.md

Key behaviors:

  • Maps requirements to phases (traceability)
  • Derives success criteria from requirements
  • Respects granularity setting for phase count
  • Validates coverage (every v1 requirement mapped to a phase)

gsd-executor

Role: Executes GSD plans with atomic commits, deviation handling, and checkpoint protocols.

Property Value
Spawned by /gsd-execute-phase, /gsd-quick
Parallelism Multiple (parallel within waves, sequential across waves)
Tools Read, Write, Edit, Bash, Grep, Glob, Skill, mcp__context7__, mcp__plugin_context7_context7__
Model (balanced) Sonnet
Color Yellow
Produces Code changes, git commits, {phase}-{N}-SUMMARY.md

Key behaviors:

  • Fresh 200K context window per plan
  • Follows XML task instructions precisely
  • Atomic git commit per completed task
  • Handles task types: auto, tracer, checkpoint (human-verify, decision, human-action)
  • Tracer feedback gate: after a tracer slice, verifies it end-to-end before expansion tasks — autonomous runs halt on failure; interactive runs honor workflow.human_verify_mode (under the end-of-phase default an automated-only <verify> continues with no checkpoint; otherwise a human-verify checkpoint is emitted, #3299)
  • Reports deviations from plan in SUMMARY.md
  • Invokes node repair on verification failure

gsd-plan-checker

Role: Verifies plans will achieve phase goals before execution.

Property Value
Spawned by /gsd-plan-phase (verification loop, max 3 iterations)
Parallelism Single instance (iterative)
Tools Read, Bash, Glob, Grep, Skill
Disallowed Tools Write, Edit, MultiEdit
Model (balanced) Sonnet
Color Green
Produces PASS/FAIL verdict with specific feedback

Verification Dimensions — labels match the agent's own ## Dimension <N> headings:

# Dimension
1 Requirement coverage
2 Task completeness
3 Dependency correctness
3b Undeclared / temporal coupling — advisory; flags same-wave plan pairs coupled through shared mutable state or execution order with no depends_on between them
4 Key links planned
5 Scope sanity
6 Verification derivation
7 Context compliance (when CONTEXT.md exists)
7b Scope reduction detection
7c Architectural tier compliance (when RESEARCH.md defines a responsibility map)
8 Nyquist compliance (when enabled) — checks 8a-8e cover automated-verify presence, feedback latency, sampling continuity and Wave 0 completeness; check 8f blocks a runnable <automated> command with no stated <fails_when> failing direction (#3172)
9 Cross-plan data contracts
10 CLAUDE.md compliance
11 Research resolution
12 Pattern compliance

Three further dimensions carry no number: Verify Command Format Sanity, Verify Command Path Resolvability, and Numeric/Factual Claim Authority.


gsd-integration-checker

Role: Verifies cross-phase integration and end-to-end flows.

Property Value
Spawned by /gsd-audit-milestone
Parallelism Single instance
Tools Read, Bash, Grep, Glob, Skill
Disallowed Tools Write, Edit, MultiEdit
Model (balanced) Sonnet
Color Blue
Produces Integration verification report

gsd-ui-checker

Role: Validates UI-SPEC.md design contracts against quality dimensions.

Property Value
Spawned by /gsd-ui-phase (validation loop, max 2 iterations)
Parallelism Single instance
Tools Read, Bash, Glob, Grep, Skill
Disallowed Tools Write, Edit, MultiEdit
Model (balanced) Sonnet
Color Cyan
Produces BLOCK/FLAG/PASS verdict

Verification Dimensions — labels match the agent's own ## Dimension <N> headings:

# Dimension
1 Copywriting
2 Visuals
3 Color
4 Typography
5 Spacing
6 Registry Safety
7 Inventory Provenance

Key behaviors:

  • Inventory provenance (#2845): a UI-SPEC whose component inventory carries no provenance line is reported as a defect, and the inventory is downgraded from a closed allowlist to a non-exhaustive list of known-good components — so an executor is never blocked from something the spec merely failed to mention. A spec with no inventory at all PASSes, which is what keeps every UI-SPEC written before the dimension existed validating unchanged. The checker never executes the recorded command; it reads the spec as a document. Limits, because the dimension is narrower than it reads: the line makes an inventory's origin falsifiable, not verified — nothing re-runs the command or compares the count, so a fabricated line passes; the rule is agent-applied like the other six, not a schema check; and "never executes the recorded command" is an instruction rather than a capability boundary, since the checker holds a Bash grant it needs for the agent-skills bootstrap. See Security model → Trade-offs and limits and How to design a UI phase.
  • Adversarial stance / "The Auditor" (#1578): applies explicit BLOCK/FLAG/PASS tiers and an anti-capitulation rule that resists author-framing pressure while still allowing self-correction when the prior dimension application was mistaken. Persona effects are strongest on Sonnet-class reasoning and unvalidated on budget/Haiku-class routing; the criteria and evidence remain authoritative.

gsd-verifier

Role: Verifies phase goal achievement through goal-backward analysis.

Property Value
Spawned by /gsd-execute-phase (after all executors complete)
Parallelism Single instance
Tools Read, Write, Bash, Grep, Glob, Skill
Disallowed Tools Edit, MultiEdit
Model (balanced) Sonnet
Color Green
Produces {phase}-VERIFICATION.md

Key behaviors:

  • Checks codebase against phase goals, not just task completion

  • PASS/FAIL with specific evidence

  • Logs issues for /gsd-verify-work to address

  • Milestone scope filtering: gaps addressed in later phases are marked as "deferred", not reported as failures (v1.32)

  • Test quality audit (v1.32): verifies that tests prove what they claim by checking for disabled/skipped tests on requirements, circular test patterns (system generating its own expected values), assertion strength (existence vs. value vs. behavioral), and expected value provenance. Blockers from test quality audit override an otherwise passing verification

  • Runs the full workspace test suite at most once per verification — proves a test exists by enumeration and that it passes via a single named test, never re-running the whole suite per must-have.

  • Behavior-dependent calibration (#966): a must-have that asserts a state transition or a cancellation/cleanup/ordering invariant is marked ⚠️ PRESENT_BEHAVIOR_UNVERIFIED (not VERIFIED) when no test exercises it — excluded from the verified_truths score, counted in the behavior_unverified frontmatter field, and routed to human verification, so a clean N/N certifies behavioral evidence rather than mere symbol presence.

  • Coincidental-reliance advisory (#1955): a truth that reaches ✓ VERIFIED is additionally asked why it holds. When the recorded evidence shows the truth holding for an incidental reason — undeclared-precondition, incidental-ordering, or fixture-only — the verdict is qualified as ✓ VERIFIED (coincidental-reliance) and the truth is listed in the coincidental_reliance_items frontmatter field with what to harden. This is advisory: the base ✓ VERIFIED token is unchanged, the truth still counts toward verified_truths, the overall status is unaffected, and no human-verification item is emitted — a passing phase still passes. It classifies evidence the verifier already gathered rather than asking it to rate its own confidence — but it is honestly an endogenous check, and gsd-core/references/honest-verifier.md records that endogenous gates are measurably weaker than the exogenous backstop tag it routes on. Advisory status is the consequence, not a coincidence: a miss costs exactly today's behaviour (a plain ✓ VERIFIED) and a false positive costs one line of prose, never a failed phase, so a weaker mechanism is affordable here in a way it would not be on a pass/fail axis. Its precision is unmeasured. It complements the two existing axes: PRESENT_BEHAVIOR_UNVERIFIED is no behavioral evidence, insufficient_spec is an under-specified truth, and this is evidence that exists and passes for the wrong reason.

    The advisory is carried by two surfaces. agents/gsd-verifier.md (Step 3, sub-step 5c) holds the detection rule, and the verifier's eagerly-imported gsd-core/references/verifier-phase-gates.md points at the canonical report template @~/.claude/gsd-core/templates/verification-report.md, whose ## Guidelines carry the same instruction. (The former third surface, the retired verify-phase workflow, was deleted as an orphan in #1892 — every verification path is subagent-shaped today.)

  • Convergence evidence gate (#3304): during re-verification (after a /gsd-plan-phase --gaps cycle), Step 7's anti-pattern scan re-runs at full, unbounded scope — by design — but a 🛑 Blocker it finds no longer auto-reverts a completed gap-closure round on its own judgment alone. A blocker other than the self-evidencing debt-marker check (TBD/FIXME/XXX) blocks unconditionally only if it is a carried-forward gap from the prior VERIFICATION.md or its file was git-modified since the prior pass (a regression, fail-closed toward blocking when history is unresolvable); otherwise it predates the gap-closure round unflagged and needs deterministic evidence — a named test run red, or another concrete reproducible artifact — to stay blocking. Unevidenced, it downgrades to the advisory: frontmatter list and the report's "Advisory (New Scope, Unevidenced)" section instead of setting status: gaps_found. Full algorithm in gsd-core/references/verifier-evidence-gate.md.


gsd-nyquist-auditor

Role: Fills Nyquist validation gaps by generating tests.

Property Value
Spawned by /gsd-validate-phase
Parallelism Single instance
Tools Read, Write, Edit, Bash, Glob, Grep, Skill
Model (balanced) Sonnet
Color Purple
Produces Test files, updated VALIDATION.md

Key behaviors:

  • Never modifies implementation code — only test files
  • Max 3 attempts per gap
  • Flags implementation bugs as escalations for user

gsd-ui-auditor

Role: Retroactive 6-pillar visual audit of implemented frontend code.

Property Value
Spawned by /gsd-ui-review
Parallelism Single instance
Tools Read, Write, Bash, Grep, Glob, Skill
Disallowed Tools Edit, MultiEdit
Model (balanced) Sonnet
Color Pink
Produces {phase}-UI-REVIEW.md with scores

6 Audit Pillars (scored 1-4):

  1. Copywriting
  2. Visuals
  3. Color
  4. Typography
  5. Spacing
  6. Experience Design

gsd-dom-verifier

Role: Observes a live DOM and reports which of a wave's stated UI acceptance criteria hold. Additive — never blocks.

Property Value
Spawned by live-dom-uat capability step at execute:wave:post
Parallelism One per wave
Tools Read, Write, Glob, Grep, mcp__chrome-devtools__, mcp__claude-in-chrome__
Disallowed Tools Edit, Bash, the Playwright MCP family
Model (balanced) Sonnet
Color Cyan
Produces {phase}-DOM-VERIFY.md
Gated by workflow.live_dom_uat (default false)

This is the only GSD agent carrying browser MCP tools. gsd-executor is deliberately not widened — for a first-party agent the static tools: list is the only control that exists (ADR-1244 D2, ADR-857 D4). It carries no Bash: it does not start dev servers or shell out.

Outcome codes (nothing_to_report and could_not_look are never conflated):

outcome reason Meaning
verified ok Criteria existed and were observed
nothing_to_report no_criteria The wave stated no UI acceptance criteria
could_not_look no_browser_mcp No browser MCP answered
could_not_look profile_locked Another instance holds the browser profile
could_not_look target_unreachable Nothing serving the target

Reference: Enable live-DOM verification · Explanation


gsd-codebase-mapper

Role: Explores codebase and writes structured analysis documents.

Property Value
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, Skill
Model (balanced) Haiku
Color Cyan
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

Role: Investigates bugs using scientific method with persistent state.

Property Value
Spawned by /gsd-debug, /gsd-verify-work (for failures)
Parallelism Single instance (interactive)
Tools Read, Write, Edit, Bash, Grep, Glob, Skill, WebSearch
Model (balanced) Sonnet
Color Orange
Produces .planning/debug/*.md, knowledge-base updates

Debug Session Lifecycle: gathering → investigating → fixing → verifying → awaiting_human_verify → resolved

Key behaviors:

  • Tracks hypotheses, evidence, and eliminated theories
  • State persists across context resets
  • Requires human verification before marking resolved
  • Runs a multi-signal fix-acceptance guardrail (mutation check, no-op/deletion detector, adjacent tests, revert-and-reconfirm) before accepting a fix; degrades gracefully when Stryker or a test suite is absent
  • Ranks suspect code by Ochiai suspiciousness from test pass/fail coverage (spectrum-based fault localization) before forming hypotheses; skips cleanly when no coverage exists
  • Branches root-cause analysis across ≥2 Ishikawa categories and applies an AND-gate check before committing root_cause (guards against 5-Whys single-cause bias); root_cause may hold a set when the AND-gate fires
  • Classifies each failure as Bohrbug / Heisenbug-Mandelbug / Concurrency at Phase 1.75 and routes the investigation technique accordingly (routes Bohrbugs to SBFL+bisect, Heisenbugs to record-replay/stability with SBFL skipped, Concurrency to the atomicity/order/deadlock checklist)
  • Hardens regression tests via PBT shrinking (minimized counterexample as the seed), explicit oracle classification (specified/derived/metamorphic/implicit), and boundary neighbors around the fixed equivalence class
  • Emits a blameless-postmortem Prevention block at resolution (branching 5-Whys, why-wasn't-this-caught, a concrete recurrence guard) and records why_not_caught + recurrence_guard in the knowledge base so the same bug class is prevented, not just fixed
  • Recalls prior resolved sessions semantically via MemPalace at Phase 0 (top-k meaning-similar), catching same-root-cause/different-wording cases keyword overlap misses; falls back to keyword matching when MemPalace is absent
  • Appends to persistent knowledge base on resolution
  • Consults knowledge base on new sessions

gsd-user-profiler

Role: Analyzes session messages across 8 behavioral dimensions to produce a scored developer profile.

Property Value
Spawned by /gsd-profile-user
Parallelism Single instance
Tools Read
Model (balanced) Sonnet
Color Purple
Produces USER-PROFILE.md, CLAUDE.md profile section

Behavioral Dimensions: Communication style, decision patterns, debugging approach, UX preferences, vendor choices, frustration triggers, learning style, explanation depth.

Key behaviors:

  • Read-only agent — analyzes extracted session data, does not modify files
  • Produces scored dimensions with confidence levels and evidence citations
  • Questionnaire fallback when session history is unavailable

gsd-doc-writer

Role: Writes and updates project documentation. Spawned with a doc_assignment block specifying doc type, mode, and project context.

Property Value
Spawned by /gsd-docs-update
Parallelism Multiple instances (one per doc type)
Tools Read, Bash, Grep, Glob, Write, Edit, Skill
Model (balanced) Sonnet
Color Purple
Produces Project documentation files (README, architecture, API docs, etc.)

Key behaviors:

  • Supports modes: create, update, supplement, fix
  • Handles doc types: readme, architecture, getting_started, development, testing, api, configuration, deployment, contributing, custom
  • Monorepo-aware: can generate per-package READMEs
  • Fix mode accepts failure objects from gsd-doc-verifier for targeted corrections
  • Writes directly to disk — does not return content to orchestrator

gsd-doc-verifier

Role: Verifies factual claims in generated documentation against the live codebase.

Property Value
Spawned by /gsd-docs-update (after doc-writer completes)
Parallelism Multiple instances (one per doc file)
Tools Read, Write, Bash, Grep, Glob
Disallowed Tools Edit, MultiEdit
Model (balanced) Sonnet
Color Orange
Produces Structured JSON verification results per doc

Key behaviors:

  • Extracts checkable claims (file paths, function names, CLI commands, config keys)
  • Verifies each claim against filesystem using tools only — no assumptions
  • Writes structured JSON result file for orchestrator to process
  • Failed claims feed back to doc-writer in fix mode

gsd-security-auditor

Role: Verifies threat mitigations from PLAN.md threat model exist in implemented code.

Property Value
Spawned by /gsd-secure-phase
Parallelism Single instance
Tools Read, Bash, Glob, Grep, Skill
Model (balanced) Sonnet
Color Red
Produces Structured verdict (SECURED / OPEN_THREATS / ESCALATE) — orchestrator writes {phase}-SECURITY.md (#2119)

Key behaviors:

  • Verifies each threat by its declared disposition (mitigate / accept / transfer)
  • Does NOT scan blindly for new vulnerabilities — verifies declared mitigations only
  • Implementation files are read-only — never patches implementation code
  • Unmitigated threats reported as OPEN_THREATS or ESCALATE
  • Supports ASVS levels 1/2/3 for verification depth

Advanced and Specialized Agents

Twelve additional agents ship under agents/gsd-*.md and are used by specialty workflows (/gsd-ai-integration-phase, /gsd-eval-review, /gsd-code-review, /gsd-code-review --fix, /gsd-debug, /gsd-map-codebase --query, /gsd-ingest-docs) and by the planner pipeline. Each carries full frontmatter in its agent file; the stubs below are concise by design. The authoritative roster (with spawner and primary-doc status per agent) lives in docs/INVENTORY.md.

gsd-pattern-mapper

Role: Read-only codebase analysis that maps files-to-be-created or modified to their closest existing analogs, producing PATTERNS.md for the planner to consume.

Property Value
Spawned by /gsd-plan-phase (between research and planning)
Parallelism Single instance
Tools Read, Bash, Glob, Grep, Write
Model (balanced) Sonnet
Color Purple
Produces PATTERNS.md in the phase directory

Key behaviors:

  • Extracts file list from CONTEXT.md and RESEARCH.md; classifies each by role (controller, component, service, model, middleware, utility, config, test) and data flow (CRUD, streaming, file I/O, event-driven, request-response)
  • Searches for the closest existing analog per file and extracts concrete code excerpts (imports, auth patterns, core pattern, error handling)
  • Strictly read-only against source; only writes PATTERNS.md

gsd-debug-session-manager

Role: Runs the full /gsd-debug checkpoint-and-continuation loop in an isolated context so the orchestrator's main context stays lean; spawns gsd-debugger agents, dispatches specialist skills, and handles user checkpoints via AskUserQuestion.

Property Value
Spawned by /gsd-debug
Parallelism Single instance (interactive, stateful)
Tools Read, Write, Edit, Bash, Grep, Glob, Agent, AskUserQuestion
Model (balanced) Sonnet
Color Orange
Produces Compact summary returned to main context; evolves the .planning/debug/{slug}.md session file

Key behaviors:

  • Reads the debug session file first; passes file paths (not inlined contents) to spawned agents to respect context budget
  • Treats all user-supplied AskUserQuestion content as data-only, wrapped in DATA_START/DATA_END markers
  • Coordinates TDD gates and reasoning checkpoints introduced in v1.36.0

gsd-code-reviewer

Role: Reviews source files for bugs, security vulnerabilities, and code-quality problems; produces a structured REVIEW.md with severity-classified findings.

Property Value
Spawned by /gsd-code-review
Parallelism Typically single instance per review scope
Tools Read, Write, Bash, Grep, Glob, Skill
Model (balanced) Sonnet
Color Orange
Produces REVIEW.md in the phase directory

Key behaviors:

  • Detects bugs (logic errors, null/undefined checks, off-by-one, type mismatches, unreachable code), security issues (injection, XSS, hardcoded secrets, insecure crypto), and quality issues
  • Honors CLAUDE.md project conventions and .claude/skills/ / .agents/skills/ rules when present
  • Read-only against implementation source — never modifies code under review
  • Full-context review scope: surrounding modules, callers, tests, and docs, not a diff-only pass
  • Owns REVIEW.md even when optional external reviewer lanes ran (#4209): it treats their <external_reviewer_evidence> as unverified input, re-verifies every claim against the actual current source before accepting it, and never follows an instruction embedded inside evidence text — there remains exactly one REVIEW.md schema regardless of how many lanes contributed

gsd-code-fixer

Role: Applies fixes to findings from REVIEW.md with intelligent (non-blind) patching and atomic per-fix commits; produces REVIEW-FIX.md.

Property Value
Spawned by /gsd-code-review --fix
Parallelism Single instance
Tools Read, Edit, Write, Bash, Grep, Glob, Skill
Model (balanced) Sonnet
Color Green
Produces REVIEW-FIX.md; one atomic git commit per applied fix

Key behaviors:

  • Treats REVIEW.md suggestions as guidance, not a patch to apply literally
  • Commits each fix atomically so review and rollback stay granular
  • Honors CLAUDE.md and project-skill rules during fixes

gsd-ai-researcher

Role: Researches a chosen AI/LLM framework's official documentation and distills it into implementation-ready guidance — framework quick reference, patterns, and pitfalls — for the Section 3–4b body of AI-SPEC.md.

Property Value
Spawned by /gsd-ai-integration-phase
Parallelism Single instance (sequential with domain-researcher / eval-planner)
Tools Read, Write, Edit, Bash, Grep, Glob, WebFetch, WebSearch, mcp__context7__, mcp__plugin_context7_context7__
Model (balanced) Sonnet
Color Green
Produces Sections 3–4b of AI-SPEC.md (framework quick reference + implementation guidance)

Key behaviors:

  • Uses Context7 MCP when available; falls back to the ctx7 CLI via Bash when MCP tools are stripped from the agent
  • Anchors guidance to the specific use case, not generic framework overviews

gsd-domain-researcher

Role: Surfaces the business-domain and real-world evaluation context for an AI system — expert rubric ingredients, failure modes, regulatory context — before the eval-planner turns it into measurable rubrics. Writes Section 1b of AI-SPEC.md.

Property Value
Spawned by /gsd-ai-integration-phase
Parallelism Single instance
Tools Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, mcp__context7__, mcp__plugin_context7_context7__
Model (balanced) Sonnet
Color Purple
Produces Section 1b of AI-SPEC.md

Key behaviors:

  • Researches the domain, not the technical framework — its output feeds the eval-planner downstream
  • Produces rubric ingredients that downstream evaluators can turn into measurable criteria

gsd-eval-planner

Role: Designs the structured evaluation strategy for an AI phase — failure modes, eval dimensions with rubrics, tooling, reference dataset, guardrails, production monitoring. Writes Sections 5–7 of AI-SPEC.md.

Property Value
Spawned by /gsd-ai-integration-phase
Parallelism Single instance (sequential after domain-researcher)
Tools Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion
Model (balanced) Sonnet
Color Orange
Produces Sections 5–7 of AI-SPEC.md (Evaluation Strategy, Guardrails, Production Monitoring)

Required reading: gsd-core/references/ai-evals.md (evaluation framework).

Key behaviors:

  • Turns domain-researcher rubric ingredients into measurable, tooled evaluation criteria
  • Does not re-derive domain context — reads Section 1 and 1b of AI-SPEC.md as established input

gsd-eval-auditor

Role: Retroactive audit of an implemented AI phase's evaluation coverage against its planned AI-SPEC.md eval strategy. Scores each eval dimension COVERED / PARTIAL / MISSING and produces EVAL-REVIEW.md.

Property Value
Spawned by /gsd-eval-review
Parallelism Single instance
Tools Read, Write, Bash, Grep, Glob, Skill
Disallowed Tools Edit, MultiEdit
Model (balanced) Sonnet
Color Red
Produces EVAL-REVIEW.md with dimension scores, findings, and remediation guidance

Required reading: gsd-core/references/ai-evals.md.

Key behaviors:

  • Compares the implemented codebase against the planned eval strategy — never re-plans
  • Reads implementation files incrementally to respect context budget

gsd-framework-selector

Role: Interactive decision-matrix agent that runs a ≤6-question interview, scores candidate AI/LLM frameworks, and returns a ranked recommendation with rationale.

Property Value
Spawned by /gsd-ai-integration-phase
Parallelism Single instance (interactive)
Tools Read, Bash, Grep, Glob, WebSearch, AskUserQuestion
Model (balanced) Sonnet
Color Cyan
Produces Scored ranked recommendation (structured return to orchestrator)

Required reading: gsd-core/references/ai-frameworks.md (decision matrix).

Key behaviors:

  • Scans package.json, pyproject.toml, requirements*.txt for existing AI libraries before the interview to avoid recommending a rejected framework
  • Asks only what the codebase scan and CONTEXT.md have not already answered

gsd-intel-updater

Role: Reads project source and writes structured intel (JSON + Markdown) into .planning/intel/, building a queryable codebase knowledge base that other agents use instead of performing expensive fresh exploration.

Property Value
Spawned by /gsd-map-codebase --query (refresh / update flows)
Parallelism Single instance
Tools Read, Write, Bash, Glob, Grep
Model (balanced) Sonnet
Color Cyan
Produces .planning/intel/*.json (and companion Markdown) consumed by gsd-tools query intel

Key behaviors:

  • Writes current state only — no temporal language, every claim references an actual file path
  • Uses Glob / Read / Grep for cross-platform correctness; Bash is reserved for gsd-tools query intel CLI calls

gsd-doc-classifier

Role: Classifies a single planning document as ADR, PRD, SPEC, DOC, or UNKNOWN. Extracts title, scope summary, and cross-references. Writes a JSON classification file used by gsd-doc-synthesizer to build a consolidated context.

Property Value
Spawned by /gsd-ingest-docs (parallel fan-out over the doc corpus)
Parallelism One instance per input document
Tools Read, Write, Grep, Glob
Model (balanced) Haiku
Color Yellow
Produces One JSON classification file per input doc (type, title, scope, refs)

Key behaviors:

  • Single-doc scope — never synthesizes or resolves conflicts (that is the synthesizer's job)
  • Heuristic-first classification; returns UNKNOWN when the doc lacks type signals rather than guessing
  • Extraction discipline (#1578): few-shot input→output exemplars plus a terminal schema restatement; marks a field absent rather than fabricating a value when the doc lacks the signal.

gsd-doc-synthesizer

Role: Synthesizes classified planning docs into a single consolidated context. Applies precedence rules, detects cross-reference cycles, enforces LOCKED-vs-LOCKED hard-blocks, and writes INGEST-CONFLICTS.md with three buckets (auto-resolved, competing-variants, unresolved-blockers).

Property Value
Spawned by /gsd-ingest-docs (after classifier fan-in)
Parallelism Single instance
Tools Read, Write, Grep, Glob, Bash
Model (balanced) Sonnet
Color Orange
Produces Consolidated context for .planning/ plus INGEST-CONFLICTS.md report

Key behaviors:

  • Hard-blocks on LOCKED-vs-LOCKED ADR contradictions instead of silently picking a winner
  • Follows the references/doc-conflict-engine.md contract so /gsd-import and /gsd-ingest-docs produce consistent conflict reports
  • Extraction discipline (#1578): few-shot exemplars plus a terminal schema restatement and a mark-absent (no-fabrication) rule for missing fields.

gsd-mempalace-curator

Role: Ship-time memory curation — writes per-agent diary entries, proposes and creates cross-project tunnels, runs wing-scoped sync pruning, and mirrors extract-learnings output into MemPalace's temporal knowledge graph with provenance.

Property Value
Spawned by MemPalace capability at ship:post (when mempalace.enabled = true); diary/tunnels/KG-mirror are then refined by their own toggles
Parallelism Single instance
Tools Read, Bash, Grep, Glob
Model (balanced) Sonnet
Produces Diary entry in MemPalace, wing tunnel proposals, KG provenance records

Key behaviors:

  • Best-effort only — every operation is onError: skip; a MemPalace failure never halts the loop
  • Wing-scoped sync pruning (mempalace sync --wing <wing> --apply) — never runs a global prune
  • Cross-project tunnel proposals when mempalace.cross_project_tunnels = true
  • Mirrors extract-learnings decisions, lessons, patterns, and surprises into the KG with source_drawer_id provenance
  • Requires MemPalace MCP server or CLI to be reachable; writes a skip-notice stub when unavailable

Agent Tool Permissions Summary

Scope: this table covers the 22 primary agents only. The 13 advanced/specialized agents listed above carry their own tool surfaces in their agents/gsd-*.md frontmatter (summarized in the per-agent stubs above and in docs/INVENTORY.md).

Agent Read Write Edit Bash Grep Glob WebSearch WebFetch MCP
project-researcher ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
phase-researcher ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
ui-researcher ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
assumptions-analyzer ✓ ✓ ✓ ✓
advisor-researcher ✓ ✓ ✓ ✓ ✓ ✓ ✓
research-synthesizer ✓ ✓ ✓
planner ✓ ✓ ✓ ✓ ✓ ✓ ✓
roadmapper ✓ ✓ ✓ ✓ ✓
executor ✓ ✓ ✓ ✓ ✓ ✓
plan-checker ✓ ✓ ✓ ✓
integration-checker ✓ ✓ ✓ ✓
ui-checker ✓ ✓ ✓ ✓
verifier ✓ ✓ ✓ ✓ ✓
nyquist-auditor ✓ ✓ ✓ ✓ ✓ ✓
ui-auditor ✓ ✓ ✓ ✓ ✓
codebase-mapper ✓ ✓ ✓ ✓ ✓
debugger ✓ ✓ ✓ ✓ ✓ ✓ ✓
user-profiler ✓
doc-writer ✓ ✓ ✓ ✓ ✓
doc-verifier ✓ ✓ ✓ ✓ ✓
security-auditor ✓ ✓ ✓ ✓ ✓ ✓

Principle of Least Privilege:

  • Checkers are read-only (no Write/Edit) — they evaluate, never modify
  • Researchers have web access — they need current ecosystem information
  • Executors have Edit — they modify code but not web access
  • Mappers have Write — they write analysis documents but not Edit (no code changes)

Completion Contracts (machine-enforced)

Every agent's return contract is declared in gsd-core/references/agent-contracts.md's Agent Registry table — (Agent, Completion Markers, Consumed by, Kind) — and enforced by npm run check:contract-drift (part of lint:ci).

The Kind column records how a caller actually detects the agent's completion:

Kind Detection mechanism
sentinel-match Exact-case string match against a declared marker (by a workflow, command, or another agent)
artifact+query The agent writes a file; the caller reads or queries that artifact
structured-return The agent returns parseable sections/JSON inline; the caller reads the return text

When you add an agent or change what it returns, update its registry row in the same change — a stale row is a build failure, not a documentation cleanup for later. Markers are extracted fence-aware (a heading inside a fenced block is the emitted template; the same words outside a fence are prose documentation), producer scope includes @-included gsd-core/references/** files, and consumers are matched exact-case (a case-insensitive hit is reported as a collision, never accepted). A marker that is deliberately emitted but matched by nothing carries an (unconsumed: <reason>) annotation — an auditable exemption that waives only the consumer requirement.

The same check also enforces the read-tag pairing: whenever a declared consumer emits <required_reading>, the producing agent's instructions must reference the gate (directly or via an @-included reference) — and the retired <files_to_read> vocabulary may not reappear under workflows/, commands/, or agents/.

For acting on a specific finding, see How to resolve a contract-drift finding.