| name | gaia-add-feature |
| description | Triage and route a fix, enhancement, or feature through only the affected artifacts. Classifies as patch/enhancement/feature and cascades accordingly -- updating PRD, architecture, epics, test plan, threat model, and traceability as needed. Surfaces Val verdicts (PASS/WARNING/CRITICAL) and emits an assessment-doc audit trail. |
| allowed-tools | ["Read","Write","Edit","Grep","Glob","Bash","Agent"] |
| orchestration_class | heavy-procedural |
Orchestration Mode
SESSION_MODE=$(bash "${CLAUDE_PLUGIN_ROOT}/scripts/detect-orchestration-mode.sh")
WARNING_OUTPUT=$(bash "${CLAUDE_PLUGIN_ROOT}/scripts/orchestration-warning.sh" --skill-class heavy-procedural --mode "$SESSION_MODE")
if printf '%s' "$WARNING_OUTPUT" | grep -q '^SURFACE-WARNING: '; then
SENTINEL_PATH=$(printf '%s' "$WARNING_OUTPUT" | sed -n 's/^SURFACE-WARNING: //p' | head -n1)
cat "$SENTINEL_PATH"
fi
Surface contract. When the prelude cats a sentinel file — which happens once per session under Mode A (subagent dispatch) — you MUST mirror that cat'd warning text VERBATIM as the FIRST user-visible text of your response, before any skill-phase output. Claude Code auto-collapses Bash tool-call output, so the warning is invisible to users unless re-emitted as LLM turn text. Skip this step only when the prelude produced no sentinel output (Mode B, repeat invocation in same session, or out-of-scope skill class).
Setup
!${CLAUDE_PLUGIN_ROOT}/skills/gaia-add-feature/scripts/setup.sh
Memory
!${CLAUDE_PLUGIN_ROOT}/scripts/memory-loader.sh pm decision-log
Brain Context
!${CLAUDE_PLUGIN_ROOT}/scripts/brain/brain-reliance-loader.sh gaia-add-feature:cascade-entry
Mission
You are the orchestrator for adding a new feature, enhancement, or patch to
the project. You classify the change scope and cascade updates through
exactly the set of affected artifacts. This skill delegates to sub-workflows
via subagents -- it does not perform direct edits to downstream artifacts.
This skill is the native Claude Code conversion of the legacy add-feature
workflow and is hardened so that
validation gates are no longer swallowed inside subagents. The
classification vocabulary (patch / enhancement / feature), cascade matrix,
and delegation model are preserved verbatim from the legacy workflow.
Critical Rules
- This is an orchestrator -- delegate to sub-workflows via subagents, do
not perform edits directly.
- Context flows forward: PRD diff feeds architecture edit, which feeds test
plan edit, which feeds story creation.
- Intelligently skip steps when not needed -- do not force all
sub-workflows on every change.
- The classification vocabulary is EXACTLY:
patch, enhancement,
feature. Do NOT rename, alias, or refactor these terms -- downstream
triage tooling and historical change requests depend on those exact
strings.
- The cascade matrix (which artifacts are updated per classification) MUST
match the definitions below exactly.
- Validation gates are MANDATORY surfacing points -- never silently consume
Val verdicts inside a subagent. Always parse the structured return schema
and apply the verdict-surfacing contract before continuing the
cascade.
- A CRITICAL verdict from Val HALTS the skill before cascade execution.
This applies in all execution modes (normal and YOLO).
- AskUserQuestion call MUST precede Val dispatch under Auto Mode.
Step 2 entry MUST emit an
AskUserQuestion tool call before
the Agent-tool dispatch to Val. AskUserQuestion is substrate-enforced
under Auto Mode (per the empirical evidence captured in user memory rule
feedback_askuserquestion_under_automode.md, 2026-05-09); this is the
primitive that catches the "auto-mode self-judgment" bypass class. Do
NOT substitute stdout sentinels, Stop hooks, or pause-and-wait scripts
-- they are bypassed under Auto Mode (the gaia-meeting precedent).
- Sentinel checkpoint MUST exist before Step 3. Step 2 MUST
write
.gaia/memory/checkpoints/add-feature-{feature_id}-val-dispatched.json
via the dedicated scripts/write-val-sentinel.sh writer (which delegates
to atomic tempfile + mv and constructs JSON via jq -n, never via
heredoc). finalize.sh validates the sentinel before allowing cascade
completion -- a missing or malformed sentinel HALTs the workflow with
stderr Val gate sentinel missing.*re-invoke from a parent orchestrator thread. This is the primitive that catches the "skipped Step 2 entirely"
bypass class.
- There is NO patch-mode exception to the Val gate. Patch
classification still requires a
dispatched Val subagent and the same verdict-surfacing contract
as enhancement and feature classifications. Self-license patterns of
the form "auto-judge under patch classification", "inline-judge because
the diff is small", or "skip Val for trivial typo fix" are forbidden.
The classification is decided in Step 1; the Val gate runs
unconditionally in Step 2 before any cascade or direct edit.
- No inline Val — Val MUST be dispatched via the main-turn Agent tool.
After dispatch, the skill MUST source
${CLAUDE_PLUGIN_ROOT}/scripts/lib/assert-agent-envelope.sh and invoke
assert_agent_envelope {sentinel_path} against the envelope sentinel
the Val persona writes; on non-zero exit HALT with the
canonical error string. The LLM MUST NOT pass off its own inline review
as a Val outcome, MUST NOT compose a synthetic structured return JSON in
the parent thread, and MUST NOT set status: PASS without a real
Agent-tool dispatch + envelope-assert success. If the Agent tool is not
available in the current context (e.g., running under a fork that did
not allowlist Agent), HALT immediately with the parent-thread
re-invoke message in Step 2 -- do NOT self-judge the Val gate from the
parent thread. The four-layer fail-closed enforcement
(dispatch checkpoint + AskUserQuestion precondition + prose
hardening + bats anti-pattern check) remains intact; the
envelope-assert is a NEW layer on top, not a replacement.
- Dispatch prompt hygiene. The Val dispatch
prompt MUST contain ONLY the raw Step 1 intake fields. The
orchestrator MUST NOT (a) instruct Val on the sentinel JSON shape,
field names, or hash basis — the validator persona's Sentinel-Write
Contract at
plugins/gaia/agents/validator.md is the single source
of truth; (b) pre-load a prior run's findings, verdict, or
recommendations into a re-dispatch prompt — the substrate's
content-integrity guard flags this as forgery and the cascade MUST
HALT; (c) invent an artifact_path value — pass feature_id as the
literal artifact_path so caller and persona hash the same string.
See Step 2b "Dispatch prompt hygiene" block for the full rationale.
Subagent Dispatch Contract
This skill follows the framework-wide Subagent Dispatch Contract.
Every Val invocation is dispatched via the main-turn Agent tool with a
read-only tool allowlist
[Read, Grep, Glob, Bash, Write] (Val needs Write to emit the envelope
sentinel from inside its own execution context per the Sentinel-Write
Contract). Dispatch is pinned to model: claude-opus-4-7 and effort: high
(Val opus pin — validation rigor is the contract).
Envelope-assert step. After the Agent call returns
and BEFORE consuming the Val verdict, the skill MUST source
${CLAUDE_PLUGIN_ROOT}/scripts/lib/assert-agent-envelope.sh and invoke
assert_agent_envelope {sentinel_path} where
{sentinel_path} = .gaia/memory/checkpoints/val-envelope-{sha256(artifact_path) first 16 hex}.json.
On non-zero exit, HALT with the canonical error string
HALT: Val agent envelope assertion failed — sentinel absent, malformed, or forged at {path} —
DO NOT fall through to a self-judged verdict. Closes the regression class
documented in feedback_add_feature_val_gate_fails_open.md.
Sentinel coexistence. Two layered sentinels coexist
post-migration — they answer different questions:
- Dispatch checkpoint
(
.gaia/memory/checkpoints/add-feature-{feature_id}-val-dispatched.json) —
validated by finalize.sh, proves dispatch HAPPENED.
- Envelope sentinel
(
.gaia/memory/checkpoints/val-envelope-{artifact-hash}.json) — validated by
assert_agent_envelope, proves the dispatcher was AUTHENTIC (Val persona).
Both MUST pass for the cascade to proceed. The two sentinel paths are
distinct slugs (add-feature-...val-dispatched.json vs val-envelope-...json)
and do NOT collide.
After Val returns:
- Parse the subagent return using the structured schema:
{ status, summary, artifacts, findings, next }. The status field is
one of PASS, WARNING, CRITICAL. Each entry in findings carries a
severity of CRITICAL, WARNING, or INFO.
- Surface the verdict to the user inline: display
status and
summary, then list every finding with its severity, scope, and
recommended action.
- Halt on CRITICAL -- if
status == "CRITICAL" or any finding has
severity == "CRITICAL", the skill HALTS before cascade execution with
an actionable error message. The user must resolve the finding before
the skill can resume (or abort). No assessment-doc is emitted on a
CRITICAL halt.
- Display WARNING -- findings with
severity == "WARNING" are
displayed inline before proceeding. The skill does NOT halt; warnings
are recorded in the assessment-doc Val Findings Summary section.
- Log INFO -- findings with
severity == "INFO" are written to the
workflow checkpoint and the assessment-doc Val Findings Summary but are
not surfaced inline unless the user requests verbose output.
This contract is enforced uniformly. CRITICAL findings cannot
be auto-dismissed in any execution mode.
YOLO Behavior
This skill conforms to the framework-wide YOLO Mode Contract.
| Behavior | YOLO Action |
|---|
Template-output prompts ([c]/[y]/[e]) | Auto-continue (skip prompt). |
| Severity / filter selection | Auto-accept defaults. |
| Optional confirmation ("Proceed with cascade?") | Auto-confirm. |
| Subagent verdict display (Val review gate) | Auto-display, but a CRITICAL verdict still HALTS. |
| Val gate dispatch under absent Agent tool | HALT -- never auto-judge, never inline-Val. Surface Re-invoke /gaia-add-feature from a parent orchestrator thread error. |
| Open-question indicators (urgency, driver, CR linkage) | HALT -- never auto-skip; require human input. |
| Memory save prompt at end | HALT -- require human input. |
In YOLO mode the Val verdict is auto-displayed but a CRITICAL verdict still
halts the skill -- this is the canonical YOLO/CRITICAL interaction.
Classification Vocabulary
Changes are classified into exactly one of three categories:
| Classification | Scope | Description |
|---|
| patch | Minimal | A one-line typo fix, copy change, or trivial correction. Touches only the directly affected doc. Does NOT cascade to PRD, architecture, epics, test plan, threat model, or traceability. |
| enhancement | Moderate | A story-level change such as a new acceptance criterion on an existing story. Cascades to epics + test plan + traceability. Leaves PRD, architecture, and threat model untouched unless impact is explicitly flagged. |
| feature | Full | A net-new user-visible capability. Full cascade across PRD, architecture, epics, test plan, threat model, and traceability. |
Cascade Matrix
The cascade matrix defines which artifacts are updated for each
classification:
| Artifact | patch | enhancement | feature |
|---|
PRD (.gaia/artifacts/planning-artifacts/prd.md) | -- | -- | YES |
Architecture (.gaia/artifacts/planning-artifacts/architecture.md) | -- | -- | YES |
Epics & Stories (.gaia/artifacts/planning-artifacts/epics-and-stories.md) | -- | YES | YES |
Test Plan (.gaia/artifacts/test-artifacts/test-plan.md) | -- | YES | YES |
Threat Model (.gaia/artifacts/planning-artifacts/threat-model.md) | -- | -- | YES |
Traceability (.gaia/artifacts/test-artifacts/traceability-matrix.md) | -- | YES | YES |
"--" means the artifact is NOT touched for that classification. "YES"
means the artifact IS updated via the appropriate sub-workflow.
Steps
Step 1 -- Capture Feature Scope
- Ask: Describe the new feature, enhancement, or fix you want to add.
- Ask: What is the urgency? Vocabulary: critical / high / medium / low.
- critical -- blocking production or active customer impact.
- high -- important and time-bound, fits next sprint.
- medium -- normal backlog priority.
- low -- nice-to-have, no time pressure.
- Ask: What is the driver? Vocabulary: user-request / bug-report /
tech-debt / opportunity.
- user-request -- explicit ask from a user, customer, or stakeholder.
- bug-report -- defect, regression, or incorrect behaviour.
- tech-debt -- internal quality, maintainability, or refactor.
- opportunity -- new market, capability, or strategic improvement.
- Ask: Is this linked to a change request? If so, provide the CR ID.
- If CR exists: read
.gaia/artifacts/planning-artifacts/change-request-{cr_id}.md
for context (impact analysis, approval status).
- Generate
feature_id in the format AF-{date}-{N} where {date} is the
current date (AF-{YYYY-MM-DD}-{N}) and {N}
is a monotonically increasing integer for that date. To resolve {N},
scan .gaia/artifacts/planning-artifacts/epics-and-stories.md and any prior
.gaia/artifacts/planning-artifacts/assessment-AF-{date}-*.md artifacts; use the
highest existing index for today plus one, or 1 if none exist.
- Classify the change as patch, enhancement, or feature based
on scope analysis.
- Present the scope summary to the user for confirmation before proceeding:
- Feature ID: {feature_id}
- Change: {description}
- Classification: {patch / enhancement / feature}
- Urgency: {critical / high / medium / low}
- Driver: {user-request / bug-report / tech-debt / opportunity}
- CR: {cr_id or "none"}
- Expected cascade: {list of artifacts that will be updated per the
cascade matrix}
Step 1 --from-discovery mode (hydration pre-fill)
When invoked as /gaia-add-feature --from-discovery <board-item-id>, Step 1
pre-fills the intake fields from a graduated discovery board item instead
of prompting the user for each field from scratch:
- Resolve the board item. Invoke
discovery-board.sh graduate --id <board-item-id> --from-discovery to validate graduation eligibility and
emit the hydrated intake fields (description from title, urgency from
priority, driver from source). Reject unknown, terminal, or
non-Evaluated item ids BEFORE any Step 1 hydration -- the resolver
dies with an actionable diagnostic.
- Pre-fill only. The hydrated fields populate the Step 1 intake form
as editable defaults. Classification is RE-DERIVED from scope analysis
-- never accepted from the hydrated payload. All hydrated text is
treated as untrusted data (sanitized, length-capped, control chars
stripped per the discovery-board.sh sanitization helpers).
- Scope-confirmation prompt is PRESERVED. The pre-filled scope
summary is still presented to the user for confirmation before
proceeding to Step 1c. Hydration does NOT bypass the
scope-confirmation prompt -- it is pre-fill only, not auto-confirm.
- Step 1c re-validation is PRESERVED. The re-validation of prereqs
under the captured classification still runs with a real Val dispatch.
Hydration does NOT bypass Step 1c or short-circuit to Step 2.
After /gaia-add-feature completes successfully (backlog row lands),
invoke discovery-board.sh graduate --id <board-item-id> --feature-id <feature_id> to transition the board item to Graduated and stamp the
backlog feature id. A HALT at Step 1c or Step 2 leaves the board item in
Evaluated state, preserving re-entrancy.
Step 1c -- Re-validate prereqs under captured classification
The initial setup.sh invocation ran under the default enhancement classification. Now that Step 1 has captured the actual classification, re-invoke setup.sh so the test-plan / traceability gates fire AGAINST that classification:
!${CLAUDE_PLUGIN_ROOT}/skills/gaia-add-feature/scripts/setup.sh \
--classification "$CLASSIFICATION" \
--feature-id "$FEATURE_ID"
Behaviour by classification:
patch: the test-plan / traceability gates are SKIPPED. The re-invocation is harmless.
enhancement / feature: the test-plan and traceability presence gates fire. If either artifact is missing, setup.sh HALTs with one of:
HALT: test-plan.md is missing — run /gaia-test-design first, then re-invoke /gaia-add-feature {feature_id}
HALT: traceability-matrix.md is missing — run /gaia-trace first, then re-invoke /gaia-add-feature {feature_id}
These HALTs are TERMINAL — the cascade does NOT proceed to Step 2. The user must bootstrap the missing artifact via the named skill, then re-invoke /gaia-add-feature with the feature_id. The path forms validate-gate.sh resolves (flat / strategy / sharded) are owned by validate-gate.sh; this skill does not duplicate that lookup.
Step 2 -- Val Review Gate (mandatory verdict surfacing)
This step is the canonical Val review gate. It restores the validation
gate that previously ran silently inside the cascade subagents and is
hardened with two
fail-closed primitives at the Step 2 boundary: (1) an AskUserQuestion
substrate-enforced halt at gate entry, (2) a sentinel checkpoint JSON
written on Val PASS that finalize.sh validates before cascade completion.
Parent thread invocation required.
Val MUST be dispatched via the main-turn Agent tool. There is NO
patch-mode exception -- patch, enhancement, and
feature classifications all run the Val gate unconditionally.
If the Agent tool is not exposed in the current invocation context
(e.g., the skill itself was spawned under a stripped-down fork without
Agent in the allowlist, or a downstream context stripped the Agent
tool from the inherited toolset), the skill MUST HALT immediately with
the error: Val gate cannot dispatch (Agent tool not exposed). Re-invoke /gaia-add-feature from a parent orchestrator thread.
The HALT message above is the canonical error string -- the parent
orchestrator must re-invoke /gaia-add-feature from a parent orchestrator thread to recover; never inline-judge the Val gate.
Do NOT self-judge the Val gate inline, do NOT compose a synthetic
structured return in the parent thread, do NOT pass off inline review as
a Val outcome. An audit found that LLM under Auto Mode self-licensed
exactly this bypass -- the contract closes it as hard: Val verdicts
originate ONLY from a real Agent-tool dispatch.
Step 2a -- AskUserQuestion precondition (substrate halt)
Before the Agent-tool dispatch to Val, the LLM MUST emit an
AskUserQuestion tool call presenting the cascade plan and the intake
data captured in Step 1. The substrate halts the turn pending user input
under Auto Mode -- this is the empirically-verified primitive
(feedback_askuserquestion_under_automode.md, 2026-05-09) that closes
the "auto-mode self-judgment" bypass class. The user's explicit
acknowledgement is what unblocks the Val dispatch below. Substitute
primitives — output-stream signaling, hook-based interception, or
polling loops in user-space — are bypassed under Auto Mode and must
not replace the substrate-enforced halt (the gaia-meeting precedent).
The AskUserQuestion call is the SOLE interactive boundary primitive at
Step 2 entry. It is required under both interactive and Auto
Mode invocations.
Step 2b -- Val dispatch + sentinel write
Dispatch prompt hygiene. The
Val dispatch prompt MUST contain ONLY the raw intake fields captured in
Step 1 (feature_id, description, classification, urgency,
driver, cr_id, expected cascade). The orchestrator MUST NOT:
-
Override Val's persona Sentinel-Write Contract. Do NOT instruct
Val on the sentinel JSON shape, field names, hash basis, or write
path. The validator persona at plugins/gaia/agents/validator.md
§Sentinel-Write Contract is the single source of truth for the
sentinel; if the caller supplies a custom shape (e.g. a JSON template
pasted into the dispatch prompt), Val will obey the caller and write
a malformed sentinel that fails assert_agent_envelope at the
persona_sig-presence check. A prior incident reproduced this
exactly — first dispatch wrote a sentinel without persona_sig
because the prompt told Val to use a custom {agent, artifact, status, summary, timestamp} shape.
-
Pre-load prior-run findings on re-dispatch. If a first dispatch
fails (malformed sentinel, wrong artifact_path, errored before write,
etc.) and a retry is required, the retry prompt MUST be composed from
the raw intake as if the prior run never happened. Do NOT include the
first run's findings list, verdict, severity tags, or recommendations.
The Claude Code substrate has an active content-integrity guard that
flags re-dispatches whose prompt pre-synthesizes the envelope and asks
the sub-agent to rubber-stamp it; the canonical flag text is
SECURITY WARNING: ...content-integrity violation and bypass of the Val dispatch gate the user's memory explicitly warns about. On a
substrate flag the orchestrator MUST HALT the cascade — never consume
a flagged sentinel as authoritative. Anchored to user memory rule
feedback_val_redispatch_no_preload.md.
-
Pass feature_id as artifact_path. Per the hash-basis
reconciliation above, the dispatch prompt MUST tell Val the
artifact_path for sentinel computation is the literal feature_id
string (AF-YYYY-MM-DD-N). This is the SAME convention validator.md
§Sentinel-Write Contract documents for in-memory intake validation —
the orchestrator does not invent a new value, it forwards feature_id
unchanged as the artifact_path the persona hashes.
These three rules are operator-error vectors verified against an actual
incident (a cascade attempt). Each is
fail-closed: the substrate or assert_agent_envelope will HALT a
non-compliant dispatch — but the friction of recovery is high, so
adhere to the hygiene rules at dispatch time.
-
Spawn a Val subagent via the main-turn Agent tool,
model: claude-opus-4-7, effort: high, and the read-only tool
allowlist [Read, Grep, Glob, Bash, Write] (Val needs Write
to emit the envelope sentinel from inside its own execution context)
(Val opus pin). Pass the intake data captured in
Step 1 (feature_id, description, classification, urgency, driver, CR
linkage, expected cascade). Per the Dispatch prompt hygiene block
above, pass feature_id as the literal artifact_path for sentinel
computation and DO NOT include a sentinel JSON template or any
pre-synthesized findings in the prompt.
-
Envelope-assert step. After the Agent call
returns and BEFORE consuming the Val verdict, source
${CLAUDE_PLUGIN_ROOT}/scripts/lib/assert-agent-envelope.sh and invoke
assert_agent_envelope {sentinel_path} where
{sentinel_path} = .gaia/memory/checkpoints/val-envelope-{sha256(artifact_path) first 16 hex}.json.
For /gaia-add-feature the validation target is an in-memory intake
object, not an on-disk artifact — the orchestrator MUST pass the
feature_id (e.g. AF-YYYY-MM-DD-N) as the literal artifact_path
string to Val so both sides compute the same sha256. The validator
persona's Sentinel-Write Contract (§Sentinel-Write Contract in
plugins/gaia/agents/validator.md) computes the sentinel path as
sha256(artifact_path); passing feature_id as artifact_path keeps
caller and persona in agreement. This is the SINGLE source of truth
for the hash basis — the prior text "sha256(feature_id)" was a
drift defect and is corrected here.
On non-zero exit, HALT with the canonical error string HALT: Val agent envelope assertion failed — sentinel absent, malformed, or forged at {path} — DO NOT fall through to a self-judged verdict. The cascade
MUST NOT proceed without a validated assessment. This closes the
fail-open regression class documented in
feedback_add_feature_val_gate_fails_open.md at the
authenticity layer; the existing dispatch-checkpoint precondition
(validated by finalize.sh) continues to guard the dispatch-happened
layer. See the Subagent Dispatch Contract section above for the
sentinel coexistence rationale and distinct sentinel paths.
-
Non-opus mismatch guard. If a test
fixture or downstream override forces a non-opus model into the dispatch
context, this skill MUST emit the canonical WARNING Val dispatch on non-opus model — forcing opus and force
model: claude-opus-4-7 before invoking Val. Silent degradation is
forbidden.
-
[Val opus-pin contract — see plugins/gaia/agents/validator.md §Val Operations]
-
Val validates the intake against the codebase and ground truth and
returns the structured schema:
{ status, summary, artifacts, findings, next }.
-
Apply the Subagent Dispatch Contract above:
- Display
status and summary inline.
- List every finding with its severity, scope, and recommended action.
- Halt on CRITICAL -- if
status == "CRITICAL" or any finding has
severity == "CRITICAL", HALT the skill before cascade execution
with an actionable error message that includes the finding text and
suggested resolution. Do NOT proceed to Step 3. Do NOT emit an
assessment-doc -- the cascade did not run.
- Display WARNING findings inline; record them for the assessment-doc.
- Log INFO findings to the checkpoint and assessment-doc.
-
In YOLO mode the verdict is auto-displayed (no [c]/[y]/[e] pause) but
a CRITICAL verdict still HALTS. The Step 2a AskUserQuestion
call is NOT bypassed in YOLO mode -- it is the substrate-enforced halt
that protects against silent gate skips.
-
After Val returns a non-CRITICAL verdict (PASS or WARNING), MUST write
the sentinel via scripts/write-val-sentinel.sh:
printf '%s' "$VAL_RETURN_JSON" \
| "${CLAUDE_PLUGIN_ROOT}/skills/gaia-add-feature/scripts/write-val-sentinel.sh" \
--feature-id "$FEATURE_ID"
The writer constructs the sentinel JSON via jq -n (NOT via heredoc /
cat <<EOF), validates the required keys (status enum, summary,
findings array, agent=val), and writes atomically (sibling tempfile +
mv). The sentinel path is
.gaia/memory/checkpoints/add-feature-${FEATURE_ID}-val-dispatched.json.
finalize.sh validates the sentinel before allowing cascade completion;
a missing or malformed sentinel HALTs the skill with stderr matching
Val gate sentinel missing.*re-invoke from a parent orchestrator thread.
-
Only when no CRITICAL findings remain AND the sentinel write succeeded
does the skill proceed to the cascade steps below.
Step 3 -- Execute Cascade (patch)
- If classification is
patch:
- Apply the fix directly to the affected document.
- No cascade -- no downstream artifacts are touched.
- Skip to Step 9 (Emit Assessment-Doc) then Step 10 (Summary).
Step 4 -- Edit PRD (feature only)
- If classification is
feature:
- Delegate to the edit-prd sub-workflow via subagent: add new functional
and non-functional requirements.
- Capture the PRD diff -- identify NEW requirement IDs (FR-, NFR-)
added.
- Capture the cascade classification from edit-prd (architecture
impact: NONE / MINOR / SIGNIFICANT).
- Store:
prd_diff, cascade_to_arch.
- If classification is
enhancement or patch: skip this step.
Step 5 -- Edit Architecture (feature only, if needed)
- If classification is
feature AND cascade_to_arch != NONE:
- Delegate to the edit-architecture sub-workflow via subagent.
- Capture the architecture diff -- new ADRs, changed sections.
- Store:
arch_diff.
- If
cascade_to_arch == NONE: inform the user "No architecture changes
needed" and skip.
- If classification is
enhancement or patch: skip this step.
Step 6 -- Edit Test Plan (enhancement and feature)
- If classification is
enhancement or feature:
- Prereq: the test-plan presence gate fires in
setup.sh via validate-gate.sh test_plan_exists when
--classification=enhancement|feature is passed. Arriving at Step 6
implies the test plan exists at the path validate-gate.sh test_plan_exists
resolves (flat .gaia/artifacts/test-artifacts/test-plan.md OR strategy/ form OR
sharded form). If the gate failed, this skill
has already HALTed with the canonical message HALT: test-plan.md is missing — run /gaia-test-design first, then re-invoke /gaia-add-feature {feature_id} — see Step 1c re-invocation below.
- Delegate to the edit-test-plan sub-workflow via subagent.
- Orchestrator trigger inheritance. When
delegating to
/gaia-edit-test-plan, pass the three inheritance
contract fields as named invocation parameters:
feature_description -- the feature scope captured in Step 1
prd_diff -- the PRD diff captured in Step 4 (empty for
enhancement classification, since Step 4 is skipped -- pass only
when populated)
arch_diff -- the architecture diff captured in Step 5 (empty for
enhancement classification, since Step 5 is skipped -- pass only
when populated)
Pass only the subset that is populated for the current classification.
/gaia-edit-test-plan Step 2 handles the partial-inheritance case by
prompting for missing fields. Do NOT pass empty strings for skipped
fields -- omit them so the downstream three-case branch routes to
PARTIAL rather than FULL with empty values.
- Capture test plan additions (new test case IDs).
- Store:
test_diff.
- If classification is
patch: skip this step.
Step 7 -- Edit Threat Model (feature only)
- If classification is
feature:
- Check if
.gaia/artifacts/planning-artifacts/threat-model.md exists.
- If it exists: update the threat model to account for new attack
surfaces introduced by the feature.
- Store:
threat_model_diff.
- If classification is
enhancement or patch: skip this step.
Step 8 -- Add Feature Stories (enhancement and feature)
Step 8 pre-flight — deterministic parent-epic inference:
Before story-creation logic runs, invoke the advisory parent-epic inference helper to surface a deterministic parent epic when affected_skills can be unambiguously mapped to one open epic:
parent_epic_match=$(bash "${CLAUDE_PLUGIN_ROOT}/skills/gaia-add-feature/scripts/lib/infer-parent-epic.sh" \
--affected-skills "$AFFECTED_SKILLS")
The helper emits exactly one of three modes on stdout (exit 0 always):
deterministic <epic_key> — exactly one open epic in epics-and-stories.md matched the affected_skills list. Parent epic is set to <epic_key> automatically; the LLM does NOT re-judge.
ambiguous: <epic_key_1>,<epic_key_2>,... — two or more open epics matched. The LLM judges among the listed candidates (or files a new epic if none fit).
no-match — zero open epics matched. The LLM falls through to its standard fallback heuristic (typically: file a new epic).
Record the result in the assessment-doc Cascade Plan as parent_epic_match: <mode> [— <details>]. Examples:
parent_epic_match: deterministic — <epic_key>
parent_epic_match: ambiguous — <epic_key_1>,<epic_key_2>
parent_epic_match: no-match
"Open epic" definition (consumed by the helper): an epic detail block in epics-and-stories.md is OPEN unless its body contains (case-insensitive) **Status: closed**, **Status: retired**, or **Status: sunset**.
Empty affected_skills is handled cleanly: the helper emits no-match and exits 0. Cascades with no skill-touching scope proceed normally.
Two modes:
inline-dispatch (legacy default for YOLO): /gaia-add-stories is dispatched as a Skill-to-Skill delegate; story files are materialized in-cascade. Behavior preserved verbatim from earlier cascades.
deferred-seed-brief (new default for non-YOLO): story keys are reserved (allocate next-free Sxxx numbers per epic via next-story-id.sh); a ### Story seed brief for <story_key> subsection is appended to the assessment-doc with proposed AC text (1-5 draft ACs), expected epic (key + name), and dependency notes (hard deps, soft deps, blocks). User dispatches /gaia-create-story <key> as a follow-up.
Default selection:
Run bash $PLUGIN/scripts/yolo-mode.sh is_yolo to detect YOLO state:
- exit 0 (YOLO active) → default mode is
inline-dispatch (legacy preserved; YOLO's "no interrupting" contract requires materializing story files in-cascade).
- exit non-zero (YOLO inactive) → default mode is
deferred-seed-brief (explicit checkpoint between cascade plan and story materialization).
--step-8-mode=<mode> CLI override:
If the orchestrator passed --step-8-mode <inline-dispatch|deferred-seed-brief> (or the inline form --step-8-mode=<mode>), the override takes precedence over the YOLO-derived default. setup.sh validates the value and rejects unknown values with gaia-add-feature: invalid --step-8-mode value (expected inline-dispatch or deferred-seed-brief, got: <value>).
Before/After default selection:
- BEFORE: all cascades used inline-dispatch by default regardless of YOLO state.
/gaia-add-stories was always pulled into the main turn.
- AFTER: YOLO →
inline-dispatch (legacy preserved); non-YOLO → deferred-seed-brief (new default).
- Rationale: the main-turn orchestration model makes inline sub-skill dispatch heavier than under the legacy fork-context model — the main turn now carries both the cascade reasoning AND the story-creation skill's context. The deferred-seed-brief alternative keeps the cascade focused on planning artifacts and defers story-file materialization to a separate user-initiated
/gaia-create-story invocation. A smoke-test surfaced this as a friction point.
Mode dispatch (the actual Step 8 body):
-
If classification is enhancement or feature:
-
If step_8_mode == inline-dispatch: delegate to the add-stories sub-workflow via subagent, passing
feature_description, prd_diff, arch_diff, and cr_id.
-
Capture new story keys and epic assignments.
-
Store: new_stories.
-
Per user rule feedback_priority_flag_never_auto_set.md, stories
created by this skill MUST have priority_flag: null regardless of
urgency. Triage and /gaia-sprint-plan decide priority sequencing.
Memory rule (verbatim — survives context compaction):
Stories produced by /gaia-add-feature MUST have priority_flag: null
by default. Do NOT auto-set priority_flag:
'next-sprint' during triage or cascade, even when:
- The driver is high-urgency.
- All stories are P1.
- The brief classifies the work as technical-debt / regression
remediation.
-
If step_8_mode == deferred-seed-brief: reserve story keys via next-story-id.sh --epic <epic_key> for each proposed story; for each reserved key, append a ### Story seed brief for <story_key> subsection to the assessment-doc containing (a) proposed title, (b) 1-5 draft ACs at planning fidelity (full polish happens in /gaia-create-story), (c) expected epic (key + name), (d) dependency notes (hard deps, soft deps, blocks), (e) a manual-test note (see below). Do NOT call /gaia-add-stories — story-file materialization is deferred to a separate user-initiated /gaia-create-story <key> invocation. Record new_stories as the list of RESERVED keys (not materialized files). The memory rule above (no auto-set of the priority flag) still applies — the user MUST NOT promote a seed-brief story to the elevated-priority value until /gaia-create-story materializes it.
Manual-test note (carry the manual-test signal through the cascade). A feature or enhancement that introduces a user-facing capability needs a manual / functional verification pass, not just automated tests. When the cascaded story touches a user-facing surface (web, server / API, mobile, or desktop platform in the project, or a UI/UX-bearing capability), carry that signal forward so the downstream authoring step opts the story into manual verification:
- inline-dispatch: instruct the add-stories delegate to apply the surface-aware manual-test offer (the create-story authoring step sets
manual_verification: true and fills the ## Manual Test section for a user-facing story).
- deferred-seed-brief: record the manual-test note in the seed brief (one line naming the surface(s) and what a manual run should exercise) so the follow-up
/gaia-create-story carries the offer through. A patch classification introduces no new surface and is not annotated.
-
If classification is patch: skip this step.
Step 8a -- Intake-time dispatch-verb enforcement
For every story produced by Step 8 (classification enhancement or feature), invoke the deterministic intake check BEFORE 8b updates traceability:
for story_path in "${new_story_paths[@]}"; do
!scripts/lib/intake-dispatch-verb-check.sh --story-file "$story_path"
done
The helper sources scripts/lib/dispatch-verb-match.sh and HALTs with the canonical message HALT: dispatch-verb AC #<n> ("<excerpt>") lacks a companion integration-test AC. Add an integration-test AC, OR annotate this AC with <!-- gaia:contract-only: <reason> --> if the dispatch is contract-only. when a story has a dispatch-verb AC without integration coverage and without a contract-only override.
This step MUST run AFTER stories are written by Step 8 (the helper needs the file on disk) and BEFORE Step 8b (traceability would otherwise record stories that fail the drift-prevention contract). The LLM never inlines the taxonomy or re-implements the matcher — SSOT contract.
If classification is patch: skip this step.
Step 8b -- Update Traceability (enhancement and feature)
- If classification is
enhancement or feature:
- Prereq: the traceability-matrix presence gate
fires in
setup.sh via validate-gate.sh traceability_exists when
--classification=enhancement|feature is passed. Arriving at Step 8b
implies the matrix exists at the path validate-gate.sh traceability_exists
resolves (flat / strategy / sharded). If the gate
failed, this skill has already HALTed with the canonical message
HALT: traceability-matrix.md is missing — run /gaia-trace first, then re-invoke /gaia-add-feature {feature_id} — see Step 1c re-invocation.
- Ground the dispatch in the canonical story registry. When delegating
to the traceability sub-workflow, the dispatch prompt MUST pin
epics-and-stories.md as the authoritative source for every story
key → scope mapping, and MUST instruct the sub-agent to key each
story-detail row by looking the story up by its E<N>-S<M> key in
that registry — never by sequentially / positionally numbering the
things being mapped (e.g. one row per service, per requirement, or per
file). Test cases are assigned to the canonical story that owns the
behaviour they exercise. Positional keying silently mis-maps test cases
to the wrong stories and breaks the requirements→tests audit trail.
- Delegate to the traceability sub-workflow via subagent to regenerate
the traceability matrix.
- Verify new FR / NFR IDs, test cases, and stories are linked.
- If classification is
patch: skip this step.
Step 8b-check -- Post-cascade traceability consistency gate (enhancement and feature)
-
If classification is enhancement or feature, AFTER Step 8b has
regenerated the matrix, run the deterministic cross-artifact consistency
check. The add-feature Val gate (Step 2) validates the cascade plan
pre-execution and never sees the regenerated matrix — this step is the
post-execution gate that asserts the matrix the sub-agent just wrote is
consistent with the canonical story registry:
!${CLAUDE_PLUGIN_ROOT}/scripts/validate-traceability-consistency.sh \
--check scope --severity halt --format text
The check is READ-ONLY. It walks every E<N>-S<M> referenced in a
story-detail table row of the traceability matrix and asserts the row's
declared scope is compatible with that key's scope/title in
epics-and-stories.md (header titles + materialized story files). On a
scope mismatch it exits non-zero and the skill MUST HALT with the
canonical message:
HALT: traceability-matrix.md references story keys whose scope is inconsistent with epics-and-stories.md — re-run Step 8b grounding the traceability dispatch in the canonical story registry (see the offending rows above), then re-invoke /gaia-add-feature {feature_id}
Record the gate verdict (PASS / the offending rows) in the assessment-doc
Val Findings Summary section so the audit trail captures it. The default
--check scope gates on mis-keyed story-detail rows (the high-signal
defect signature); invented-key references to retired/orphan epics are
surfaced as advisory and do not block. A caller may run
--check existence or --check all for a stricter audit.
-
If classification is patch: skip this step.
Step 8c -- Re-shard touched documents
Cascade execution may have written to one or more monolith documents:
.gaia/artifacts/planning-artifacts/prd.md, .gaia/artifacts/planning-artifacts/architecture.md,
and/or .gaia/artifacts/planning-artifacts/epics-and-stories.md (and, transitively
via Step 8 sub-workflow, story files and traceability). Once the cascade
finishes, MUST re-shard each touched monolith so the per-section shards
stay aligned with the monolith. This step honours the monolith-vs-shard
sync contract — it is not optional
unless the user passes --monolith-only for an explicit atomic same-PR
edit (e.g., when the cascade and the re-shard will land in the same
commit and the user prefers to invoke /gaia-shard-doc manually at
PR-merge time).
- If
$ARGUMENTS contains --monolith-only: skip this step entirely.
Record reshard: skipped (--monolith-only) in the assessment-doc
Cascade Plan section. The user takes responsibility for re-running
/gaia-shard-doc (or merging shards back to the monolith) before
commit.
- Otherwise, build the touched-monolith set from the prior cascade steps:
- if Step 4 (Edit PRD) ran -> include
.gaia/artifacts/planning-artifacts/prd.md
- if Step 5 (Edit Architecture) ran -> include
.gaia/artifacts/planning-artifacts/architecture.md
- if Step 8 (Add Feature Stories) ran -> include
.gaia/artifacts/planning-artifacts/epics-and-stories.md
- for
patch classification: include only the directly-edited monolith
(no cascade ran)
- For each monolith in the touched set, invoke
/gaia-shard-doc <path>.
/gaia-shard-doc is unchanged in this story — only the cascade
invocation pattern changes.
- After all re-shards return, run
${CLAUDE_PLUGIN_ROOT}/scripts/check-monolith-shard-sync.sh against
the project root. The check is advisory (always exits 0). If it emits
any WARNING lines, surface those WARNINGs to the user and record
them in the assessment-doc Val Findings Summary section so the audit
trail captures the residual drift — they indicate one or more
re-shards did not converge and the user must investigate before
commit.
- Record the per-monolith
reshard: invoked (gaia-shard-doc) decisions
in the assessment-doc Cascade Plan section so the audit trail captures
the invocations.
This step runs in YOLO mode automatically — re-sharding is deterministic
and needs no user prompt. It is purely additive: skills that
did not previously include this step continue to function for backwards
compatibility.
Step 9 -- Emit Assessment-Doc Artifact
This step runs only after the cascade completes successfully and Val
returned no CRITICAL findings in Step 2. If Step 2 halted on CRITICAL,
no assessment-doc is emitted -- the user must resolve the CRITICAL
finding first and re-invoke the skill.
-
Write the assessment-doc to
.gaia/artifacts/planning-artifacts/assessment-{feature_id}.md with the following
sections:
- Header -- feature_id, date, author, classification, urgency,
driver, CR linkage.
- Classification -- the chosen classification (patch / enhancement /
feature) with a one-line scope rationale.
- Affected Artifacts -- the list of artifacts touched per the
cascade matrix for the chosen classification, with the actual diff
summaries captured during the cascade. Skipped artifacts are listed
with "(skipped: classification = {patch|enhancement})" so the audit
trail is explicit.
- Cascade Plan -- a numbered list of the sub-workflows dispatched in
order, with the resulting diff IDs (new FR / NFR IDs, ADR numbers,
test case IDs, story keys) captured at each step. For patch
classification this section reads "(no cascade -- direct edit
applied)".
- Val Findings Summary -- the verdict from Step 2 (PASS / WARNING)
plus the full list of WARNING and INFO findings with their severity,
scope, and recommended action. CRITICAL findings never appear here
because they would have halted the skill before this step.
-
The assessment-doc serves as the audit trail: who proposed what change,
what Val said about it, what artifacts ended up touched, and which
follow-up stories were created. It is written ONLY after the cascade
completes successfully.
-
Before the Finalize block runs, MUST export FEATURE_ID so the
finalize.sh sentinel guard can locate the Val-dispatch
sentinel: export FEATURE_ID="${feature_id}". The guard treats an
unexported FEATURE_ID as a legacy fixture path (skipped) -- production
cascades MUST always export it.
Step 10 -- Summary
References
- Structured subagent return schema
(
status / summary / artifacts / findings / next).
- Native Execution Model via Claude Code Skills + Subagents +
Plugins + Hooks.
- Scripts-over-LLM for Deterministic Operations. The Val gate
and assessment-doc emit are LLM-judgment steps and intentionally do NOT
introduce new scripts.
- Review Gate via sequential subagents.
Val invocations follow this isolation pattern with a read-only tool
allowlist.
- Subagent Dispatch Contract -- Mandatory Verdict Surfacing.
- YOLO Mode Contract -- Consistent Non-Interactive Behavior.
- Add-feature orchestrator with classification vocabulary and
cascade matrix.
- Restore the validation gate inside
/gaia-add-feature.
- Auto-sharding policy; monolith-vs-shard sync contract.
- Static
monolith-shard-sync check.
- Cascade-skill auto-invoke for
/gaia-shard-doc
(Step 8c above + --monolith-only opt-out).
- "Val verdicts originate ONLY
from a real Agent-tool dispatch" hard contract; closes the inline-Val
- auto-judge-in-patch-mode bypass class.
- The
/gaia-add-feature Val-gate fail-open under fork isolation (precedent
for the prose-hardening clauses above).
- Val-dispatch contract hardening: reconciles the hash
basis between SKILL.md and validator.md, adds Dispatch prompt hygiene
prose covering caller-side sentinel-shape override and prior-findings
pre-loading on re-dispatch.
Changelog
- 2026-06-24 —
--from-discovery hydration bridge. Added Step 1 --from-discovery <board-item-id> mode that pre-fills the Step 1 intake fields (description, urgency, driver) from a graduated discovery board item. Classification is re-derived from scope analysis, never accepted from hydration. The scope-confirmation prompt and Step 1c re-validation are explicitly preserved -- hydration is pre-fill only, not bypass. The board item transitions to Graduated only after the backlog row lands; a HALT at Step 1c or Step 2 leaves the item in Evaluated state (re-entrancy preserved). All hydrated fields are sanitized (control chars stripped, length-capped) and artifact paths are confined repo-relative. Coverage: plugins/gaia/tests/discovery-graduate.bats (33 cases covering track auto-detect, per-track bars, fail-closed AI-id validation, hydration behaviour, side-effect ordering).
- 2026-06-10 — Post-cascade traceability consistency gate + traceability-dispatch grounding. Added Step 8b-check, a deterministic post-execution gate (
scripts/validate-traceability-consistency.sh) that runs after Step 8b regenerates the matrix and HALTs when a story-detail row's scope is inconsistent with the canonical story registry (epics-and-stories.md, header titles + materialized story files). Closes the structural gap where the Step 2 Val gate validates only the cascade plan pre-execution and never re-validates the matrix the traceability sub-agent writes. Step 8b prose also gained a grounding clause: the traceability dispatch MUST pin epics-and-stories.md as authoritative and key each story-detail row by looking the story up by its key, never by positional/sequential numbering of the things being mapped (the defect: a sub-agent numbering rows per cloud-service produced an off-by-one that mis-mapped test cases to the wrong stories). The gate defaults to --check scope (gates on mis-keyed rows — the high-signal signature; invented-key references to retired epics are advisory). Sibling to the epic/story-key registry integrity audit (validate-epic-registry.sh) — that asserts key uniqueness + epic non-orphaning; this asserts traceability references are scope-consistent with the registry. Coverage: plugins/gaia/tests/validate-traceability-consistency.bats (13 cases incl. defect reproduction, false-positive guard, file-only-key registration, all three --check modes).
- 2026-05-14 — Deterministic parent-epic inference. Added
scripts/lib/infer-parent-epic.sh — advisory helper that maps comma-separated affected_skills to open epics in .gaia/artifacts/planning-artifacts/epics-and-stories.md. Emits one of three modes on stdout (exit 0 always): deterministic <epic_key> / ambiguous: <key1>,<key2>,... / no-match. Step 8 prose updated with a pre-flight subsection that invokes the helper before story-creation logic; the result is recorded in the assessment-doc Cascade Plan as parent_epic_match: <mode> [— <details>]. Open-epic definition: a detail block is OPEN unless **Status: closed**, **Status: retired**, or **Status: sunset** appears within it. Empty affected_skills cleanly emits no-match. Closes the drift surfaced by a smoke test (LLMs reading a long epics-and-stories.md inconsistently picked between parent-epic candidates).
- 2026-05-14 — Step 8 deferred-seed-brief mode +
step_8_mode Cascade Plan field. Step 8 prose rewritten to document TWO modes: inline-dispatch (legacy default for YOLO, materializes story files in-cascade) and deferred-seed-brief (new default for non-YOLO, reserves story keys + emits ### Story seed brief for <story_key> subsections in the assessment-doc; user dispatches /gaia-create-story <key> as a follow-up). Default selection is YOLO-keyed: YOLO active → inline-dispatch (legacy preserved); YOLO inactive → deferred-seed-brief (new default). setup.sh gained a --step-8-mode <inline-dispatch|deferred-seed-brief> CLI override (and inline form) with canonical rejection stderr gaia-add-feature: invalid --step-8-mode value (expected inline-dispatch or deferred-seed-brief, got: <value>). The Before/After default flip is documented explicitly — reviewers see the policy change, not just a new field. Rationale: the main-turn orchestration model makes inline sub-skill dispatch heavier than under the legacy fork-context model; a smoke-test surfaced this as a friction point.
- 2026-05-14 — Steps 6/8b HALT-or-bootstrap on missing canonical test artifacts.
setup.sh gained two new optional CLI flags (--classification <patch|enhancement|feature>, --feature-id <AF-{date}-{N}>) parsed BEFORE resolve-config so the classification is available when gates fire. Under classification enhancement / feature, setup.sh invokes validate-gate.sh test_plan_exists and validate-gate.sh traceability_exists (extending the existing prd_exists / epics_and_stories_exists consumer pattern). On either gate failure, setup.sh die's with canonical stderr HALT: test-plan.md is missing — run /gaia-test-design first, then re-invoke /gaia-add-feature {feature_id} (or the /gaia-trace mirror). Patch classifications skip both gates. SKILL.md Steps 6 + 8b prose rewritten to document the prereq contract; Step 1c re-invocation added so the classification captured in Step 1 flows back to setup.sh. Closes the drift surfaced by a smoke test (Step 6 silently skipped its Test Plan edit because the artifact did not yet exist on disk).
- 2026-05-14 — Intake-time dispatch-verb enforcement. Added Step 8a between Step 8 (Add Feature Stories) and Step 8b (Update Traceability). The step invokes
scripts/lib/intake-dispatch-verb-check.sh --story-file <path> for every story produced by Step 8. The helper sources scripts/lib/dispatch-verb-match.sh and HALTs with the canonical message when a dispatch-verb AC lacks a companion integration-test AC and has no <!-- gaia:contract-only: <reason> --> override. Closes the documented drift class (dispatch-verb ACs landing without integration coverage). Story-template.md and validate-frontmatter.sh gain a new 16th required delivered: boolean field (default true) — the bookkeeping primitive a later story will consume for retroactive back-fill.
- 2026-05-13 — Sentinel-Write Writer Shift. Following an incident, the Val sentinel write has been relocated from the Val sub-agent context to the orchestrator's main turn. Val now RETURNS the sentinel content inside the envelope; the orchestrator writes the sentinel via the helper
plugins/gaia/scripts/lib/write-val-envelope.sh. The writer accepts Val's returned envelope shape DIRECTLY — it unwraps a nested sentinel_envelope (passing persona_sig through verbatim) or accepts a flat top-level sentinel, with no caller-side reshaping. This closes the Claude Code substrate content-integrity false-fire that blocked the cascade end-to-end after the bridge migration landed. Forgery resistance preserved via persona_sig binding to validator.md's on-disk sha256. The Step 2b dispatch contract now reads: (1) spawn Val via Agent tool; (2) write sentinel by piping Val's returned envelope straight into write-val-envelope.sh --envelope-stdin (captures the path on stdout); (3) source assert-agent-envelope.sh; (4) assert_agent_envelope against the captured path; (5) HALT on non-zero; (6) consume verdict. The four-layer fail-closed enforcement (dispatch checkpoint, AskUserQuestion precondition, dispatch prompt hygiene, bats anti-pattern check) is preserved intact. Coverage: helper-level bats in plugins/gaia/tests/write-val-envelope.bats; existing bats in plugins/gaia/tests/val-bridge-migration.bats continues to pass (assertion logic unchanged); validator.md §Sentinel-Write Contract rewritten to specify the return-channel.
- 2026-05-13 — Dispatch prompt hygiene + hash-basis reconcile. Fixed three operator-error vectors surfaced by a cascade attempt (substrate content-integrity HALT). (a) Reconciled the envelope sentinel hash basis: Step 2b body had drifted to
sha256(feature_id) while the Subagent Dispatch Contract section and validator persona §Sentinel-Write Contract both say sha256(artifact_path). Step 2b now matches; the convention is documented as "pass feature_id as the literal artifact_path" so caller and persona hash the same string. Validator persona amended with the same convention. (b) Added an explicit "Dispatch prompt hygiene" block to Step 2b enumerating three forbidden patterns: caller-side sentinel JSON shape override (causes Val to write a malformed sentinel that fails assert_agent_envelope), prior-findings pre-loading on re-dispatch (substrate content-integrity guard flags as forgery), and artifact_path invention (breaks hash agreement). Anchored to memory rule feedback_val_redispatch_no_preload.md. (c) Mirrored the hygiene rule into Critical Rules so it survives Step 2b skim. No script changes — write-val-sentinel.sh and finalize.sh are unchanged; the bug surface is entirely in the SKILL.md prose contract with Val.
- 2026-05-13 — Val Bridge Migration, FINAL self-referential migration. Migrated
/gaia-add-feature Step 2 Val gate from fork isolation to main-turn Agent-tool dispatch. Added the post-dispatch envelope-assert step (source assert-agent-envelope.sh + assert_agent_envelope + HALT on non-zero) at Step 2b. The four-layer fail-closed enforcement (sentinel checkpoint, AskUserQuestion precondition, prose hardening, bats anti-pattern check) is preserved intact — the envelope-assert is a NEW layer ON TOP, not a replacement. Two layered sentinels coexist at distinct paths: dispatch checkpoint .gaia/memory/checkpoints/add-feature-{feature_id}-val-dispatched.json (validated by finalize.sh, proves dispatch HAPPENED) and envelope sentinel .gaia/memory/checkpoints/val-envelope-{artifact-hash}.json (validated by assert_agent_envelope, proves dispatcher was AUTHENTIC Val persona). Closes feedback_add_feature_val_gate_fails_open.md at the authenticity layer. Coverage by bats in plugins/gaia/tests/val-bridge-migration.bats; the prior verdict-surfacing bats suite continues to pass.
Mode B Readiness
Driving teammate turns (MANDATORY under team orchestration). Declaring
readiness above sets up the spawn / relay / shutdown bookkeeping seams — it does
NOT by itself drive a teammate. When SESSION_MODE == team, the orchestrator
MUST drive each teammate turn per the canonical Mode B teammate round-trip
contract at knowledge/mode-b-round-trip-contract.md: emit a real
SendMessage(to: <handle>) whose message ends with the reply-routing reminder,
let the teammate reply via SendMessage(to: team-lead) (one-shot re-prompt on
idle-without-reply; never fabricate the reply), then relay the received body to
the transcript / artifact. The bridge functions named above are bookkeeping
only; the round-trip itself is an orchestrator-driven, main-turn loop.
No discretionary Mode A fall-through. The team-mode round-trip is mandatory
when the session resolves to team orchestration — "it is a small / focused /
quick step" is NOT a license to fall back to one-shot Mode A, and a slow reply
is the cross-turn-boundary case (wait or re-prompt once), not a fallback
trigger. The ONLY legitimate fall-through is a real MODE_B_FALLBACK token
emitted by the bridge at spawn time (substrate genuinely unavailable).
This skill is Mode B-ready. Under the team-orchestration mode, the authoring subagent work that the prose above describes as inline subagent dispatch is instead routed through the shared execution bridge library at ${CLAUDE_PLUGIN_ROOT}/scripts/lib/execution-mode-b-bridge.sh, which itself layers on the shared dispatch library ${CLAUDE_PLUGIN_ROOT}/scripts/lib/dispatch-teammate.sh.
- Spawn seam. The cascade-authoring subagent updates the affected artifacts. The orchestration runs
execution_spawn_subagent <authoring-persona> "gaia-add-feature" to obtain a persistent teammate handle. The clean-room gate in the shared library refuses any reviewer persona before a teammate is created.
- Relay seam. Each authoring turn is relayed verbatim to the team lead via
execution_relay_turn <handle> <payload>, so the assessment-doc audit trail and the cascaded artifacts are identical to the Mode A subagent-dispatch path — only the dispatch seam differs, never the produced output.
- Shutdown seam. At skill exit the orchestration runs
execution_shutdown, which delegates to shutdown_all so no teammate pane is left orphaned.
- Honest fallback. Live Mode B is not exercisable in every Claude Code context. When the substrate is absent the bridge degrades to the existing Mode A foreground dispatch and emits a single
MODE_B_FALLBACK token to stderr; the Mode A behaviour documented above remains the source of truth.
Finalize
!${CLAUDE_PLUGIN_ROOT}/skills/gaia-add-feature/scripts/finalize.sh