diff --git a/.changeset/fix-3087-planner-directive-language.md b/.changeset/fix-3087-planner-directive-language.md
new file mode 100644
index 000000000..83dd18d35
--- /dev/null
+++ b/.changeset/fix-3087-planner-directive-language.md
@@ -0,0 +1,5 @@
+---
+type: Fixed
+pr: 3138
+---
+**`gsd-planner.md` directive language restored** — 10 instances of `CRITICAL`/`MANDATORY`/`ALWAYS`/`MUST` emphasis were silently removed in v1.38.4 (PR #2489) without documentation, conflicting with that release's stated sycophancy-hardening intent. Downstream effect: planner output in v1.38.4–v1.40.x exhibited weaker adherence to user decisions and requirement coverage, as observed in #3087. Restored: `CRITICAL: User Decision Fidelity`, `CRITICAL: Never Simplify User Decisions`, `Multi-Source Coverage Audit (MANDATORY in every plan set)`, `Audit ALL four source types`, `Discovery is MANDATORY`, `ALWAYS split if:`, `requirements MUST list`, `CRITICAL: Every requirement ID MUST appear`, `ALWAYS use the Write tool`, and `CRITICAL — File naming convention`. Closes #3087.
diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md
index 6382cbae1..5f7ffbf39 100644
--- a/agents/gsd-planner.md
+++ b/agents/gsd-planner.md
@@ -49,7 +49,7 @@ Before planning, discover project context:
-## User Decision Fidelity
+## CRITICAL: User Decision Fidelity
The orchestrator provides user decisions in `` tags from `/gsd-discuss-phase`.
@@ -73,7 +73,7 @@ The orchestrator provides user decisions in `` tags from `/gsd-d
-## Never Simplify User Decisions — Split Instead
+## CRITICAL: Never Simplify User Decisions — Split Instead
**PROHIBITED language/patterns in task actions:**
- "v1", "v2", "simplified version", "static for now", "hardcoded for now"
@@ -94,11 +94,11 @@ Do NOT silently omit features. Instead:
3. The orchestrator presents the split to the user for approval
4. After approval, plan each sub-phase within budget
-## Multi-Source Coverage Audit
+## Multi-Source Coverage Audit (MANDATORY in every plan set)
@~/.claude/get-shit-done/references/planner-source-audit.md for full format, examples, and gap-handling rules.
-Perform this audit for every plan set before finalizing. Check all four source types: **GOAL** (ROADMAP phase goal), **REQ** (phase_req_ids from REQUIREMENTS.md), **RESEARCH** (RESEARCH.md features/constraints), **CONTEXT** (D-XX decisions from CONTEXT.md).
+Audit ALL four source types before finalizing: **GOAL** (ROADMAP phase goal), **REQ** (phase_req_ids from REQUIREMENTS.md), **RESEARCH** (RESEARCH.md features/constraints), **CONTEXT** (D-XX decisions from CONTEXT.md).
Every item must be COVERED by a plan. If ANY item is MISSING → return `## ⚠ Source Audit: Unplanned Items Found` to the orchestrator with options (add plan / split phase / defer with developer confirmation). Never finalize silently with gaps.
@@ -160,7 +160,7 @@ Plan -> Execute -> Ship -> Learn -> Repeat
## Mandatory Discovery Protocol
-Discovery is required unless you can prove current context exists.
+Discovery is MANDATORY unless you can prove current context exists.
**Level 0 - Skip** (pure internal work, existing patterns only)
- ALL work follows established codebase patterns (grep confirms)
@@ -362,7 +362,7 @@ Plans should complete within ~50% context (not 80%). No context anxiety, quality
## Split Signals
-**Split if any of these apply:**
+**ALWAYS split if:**
- More than 3 tasks
- Multiple subsystems (DB + API + UI = separate plans)
- Any task with >5 file modifications
@@ -477,7 +477,7 @@ After completion, create `.planning/phases/XX-name/{phase}-{plan}-SUMMARY.md`
| `depends_on` | Yes | Plan IDs this plan requires |
| `files_modified` | Yes | Files this plan touches |
| `autonomous` | Yes | `true` if no checkpoints |
-| `requirements` | Yes | Requirement IDs from ROADMAP. Every roadmap requirement ID MUST appear in at least one plan. |
+| `requirements` | Yes | **MUST** list requirement IDs from ROADMAP. Every roadmap requirement ID MUST appear in at least one plan. |
| `user_setup` | No | Human-required setup items |
| `must_haves` | Yes | Goal-backward verification criteria |
@@ -582,7 +582,7 @@ Only include what Claude literally cannot do.
## The Process
**Step 0: Extract Requirement IDs**
-Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field lists the IDs its tasks address. Every requirement ID MUST appear in at least one plan. Plans with an empty `requirements` field are invalid.
+Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field MUST list the IDs its tasks address. **CRITICAL:** Every requirement ID MUST appear in at least one plan. Plans with an empty `requirements` field are invalid.
**Security (when `security_enforcement` enabled — absent = enabled):** Identify trust boundaries in this phase's scope. Map STRIDE categories to applicable tech stack from RESEARCH.md security domain. For each threat: assign disposition (mitigate if ASVS L1 requires it, accept if low risk, transfer if third-party). Every plan MUST include `` when security_enforcement is enabled.
@@ -1056,9 +1056,9 @@ Present breakdown with wave structure. Wait for confirmation in interactive mode
Use template structure for each PLAN.md.
-Use the Write tool to create files — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
+**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.
-**File naming convention (enforced):**
+**CRITICAL — File naming convention (enforced):**
The filename MUST follow the exact pattern: `{padded_phase}-{NN}-PLAN.md`
diff --git a/tests/bug-3087-planner-directive-language.test.cjs b/tests/bug-3087-planner-directive-language.test.cjs
new file mode 100644
index 000000000..a54e5ffea
--- /dev/null
+++ b/tests/bug-3087-planner-directive-language.test.cjs
@@ -0,0 +1,46 @@
+'use strict';
+
+// Regression guard for bug #3087.
+//
+// Between v1.38.3 and v1.38.4, agents/gsd-planner.md had 10 instances of
+// CRITICAL/MANDATORY/ALWAYS/MUST directive emphasis systematically removed.
+// The change was undocumented and conflicts with the stated intent of PR #2489
+// (the sycophancy-hardening pass that shipped in the same release). This test
+// enforces the restored directive language so the demotion cannot recur silently.
+
+const { test } = require('node:test');
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const path = require('node:path');
+
+const ROOT = path.join(__dirname, '..');
+let src;
+try {
+ src = fs.readFileSync(path.join(ROOT, 'agents', 'gsd-planner.md'), 'utf8');
+} catch (err) {
+ throw new Error(`agents/gsd-planner.md not found — was the file renamed? (${err.message})`);
+}
+
+const directives = [
+ { desc: 'User Decision Fidelity heading is CRITICAL', pattern: /## CRITICAL: User Decision Fidelity/ },
+ { desc: 'Never Simplify heading is CRITICAL', pattern: /## CRITICAL: Never Simplify User Decisions/ },
+ { desc: 'Multi-Source Audit heading is MANDATORY', pattern: /## Multi-Source Coverage Audit \(MANDATORY in every plan set\)/ },
+ { desc: 'Source audit uses "Audit ALL" imperative', pattern: /Audit ALL four source types before finalizing/ },
+ { desc: 'Discovery is MANDATORY', pattern: /Discovery is MANDATORY unless/ },
+ { desc: 'Split signals use ALWAYS', pattern: /\*\*ALWAYS split if:\*\*/ },
+ { desc: 'requirements field doc uses MUST', pattern: /\*\*MUST\*\* list requirement IDs from ROADMAP/ },
+ { desc: 'Step 0 has CRITICAL requirement ID directive', pattern: /\*\*CRITICAL:\*\* Every requirement ID MUST appear/ },
+ { desc: 'Write tool directive uses ALWAYS', pattern: /\*\*ALWAYS use the Write tool to create files\*\*/ },
+ { desc: 'File naming convention heading is CRITICAL', pattern: /\*\*CRITICAL — File naming convention \(enforced\):\*\*/ },
+];
+
+for (const { desc, pattern } of directives) {
+ test(`gsd-planner.md: ${desc}`, () => {
+ assert.ok(
+ pattern.test(src),
+ `Directive enforcement missing from gsd-planner.md: "${desc}" — pattern ${pattern} not found. ` +
+ `This language was demoted in v1.38.4 (PR #2489) without documentation, conflicting with ` +
+ `the sycophancy-hardening intent of that release. See bug #3087.`,
+ );
+ });
+}