Reads a PRD (`prds/<feature>/prd.md`) plus its executable `run-prd-test.sh` (and any helper artifacts under `prds/<feature>/`), grounds them in codebase research, and produces `specs/<feature>/mainspec.md` plus dependency-ordered slices. Encodes the runner as a slice success criterion so implementation completion implies `./prds/<feature>/run-prd-test.sh` exits 0. Touches `specs/<feature>/.planning-done` as its final committed action. Agent-first — no human-in-the-loop.
61
72%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./skills/sdd/spec-planning/SKILL.mdTurn a PRD into a structured Spec Plan using Spec-Driven Development. Agent-first: this skill is invoked headless by the harness dispatcher, with the feature slug as its single argument. It reads disk, does the work, commits artifacts plus a sentinel, and exits.
Invoked by the dispatcher as: claude -p "/spec-planning <feature>", run from inside the feature worktree (the dispatcher cds into it — there is no print-mode --cwd flag).
Single argument: <feature> — kebab-case feature slug. All paths derive from this.
Inputs read from disk (paths relative to cwd):
prds/<feature>/prd.md — the why, user story, definition of done, constraints, out-of-scope.prds/<feature>/run-prd-test.sh — executable test runner for this feature's PRD test. Exits 0 when the feature is done.prds/<feature>/ invoked by run-prd-test.sh — fixtures, LLM-judge prompts, helper test files, etc. The runner is the single contract; its internals are intentionally flexible (pure unit test, LLM-as-judge, deterministic shell checks, or any mix).Outputs to disk (paths relative to cwd):
specs/<feature>/mainspec.mdspecs/<feature>/slices/*.mdspecs/<feature>/.planning-done (empty sentinel)Completion protocol (in order):
git add those files, commit with a clear message, push.touch specs/<feature>/.planning-done.git add the sentinel, commit, push.The sentinel is the final commit-and-push action, only after every other artifact is in place. The dispatcher uses only the sentinel to advance to spec-validate.
Idempotency:
specs/<feature>/.planning-done already exists, exit immediately (the previous invocation completed; the dispatcher's worktree wipe will have discarded any uncommitted intermediate state).specs/<feature>/mainspec.md exists but the sentinel does not, treat as crash recovery: verify the existing artifacts are complete and self-consistent, fix any gaps, then write the sentinel.Ambiguous PRD handling:
prds/<feature>/clarifications-needed.md documenting the open questions, commit it, and exit without writing the sentinel. The dispatcher will re-fire on the next tick; if the PRD has been amended, planning may now succeed.Spec planning starts with the end in mind. You create a mainspec that defines the complete end state of a feature, then work backwards to identify logical slices—temporal chunks of intent that each focus on a clear WHAT and WHY. Each slice is a manageable piece that can be implemented independently while building toward the complete vision. Your job: read the PRD as the source of intent, research the codebase to understand what exists today, create temporal ordering of mainspecs and slices based on dependencies, and write spec outlines that paint a clear picture of WHAT needs to be built and WHY it matters. Start each slice with clear objectives and user stories to establish context and purpose. The balance: provide clear intent, constraints, and patterns from the actual codebase, but avoid being overly prescriptive about implementation details. Your output is a mainspec plus ordered slices with dependencies explicitly documented, giving implementation agents the right context to succeed.
prds/<feature>/prd.md and the codebase. Do NOT use AskUserQuestion. There is no human in the loop. If the PRD is too ambiguous to ground (contradictions, undefined terms, missing definition of done), follow the Ambiguous PRD handling protocol in the Invocation Contract above.run-prd-test.sh is the definition of done. The mainspec must include a slice (typically the final one) whose Signal section names the PRD test runner (./prds/<feature>/run-prd-test.sh) as the validation command. When this slice completes, ./prds/<feature>/run-prd-test.sh must exit 0. Document this requirement explicitly in the slice's Objective so the implementing agent does not miss it. The runner is intentionally opaque to spec-planning: it may invoke a unit test, an LLM-as-judge prompt, deterministic shell checks, or any mix — the slice's job is to make it pass, not to assume its internals.Slice | Depends On | Blocks table and a Mermaid flowchart visualizing the DAG. This is the single source of truth for slice dependencies.Specs live in specs/<feature>/ relative to the worktree root, with this structure:
specs/
├── <feature-name-a>/
│ ├── mainspec.md
│ └── slices/
│ ├── 1.1-<slice-intent>.md
│ ├── 1.2-<slice-intent>.md
│ └── ...
├── <feature-b>/
│ ├── mainspec.md
│ └── slices/
│ ├── 2.1-<slice-intent>.md
│ ├── 2.2-<slice-intent>.md
│ └── ...Slice numbering - First digit matches mainspec order (feature 1 → 1.x, feature 2 → 2.x). Second digit is slice order within that feature.
Slice naming - Use kebab-case intent after the number (e.g., 1.1-type-contracts.md, 2.3-api-endpoints.md).
Slice Dependency Map - Every mainspec must end with this section:
## Slice Dependency Map
| Slice | Depends On | Blocks |
|-------|-----------|--------|
| X.1 — Name | — | X.2, X.3 |
| X.2 — Name | X.1 | X.4 |
```mermaid
flowchart TD
X.1[X.1 Name] --> X.2[X.2 Name]Use `—` for no dependencies/blocks. Reference slice numbers (e.g., `X.1`).Context engineering in specs is about choosing what to put in specs to eliminate ambiguity for coding agents. The biggest lever you have is what you include (or exclude) in the spec. Below are key practices to apply when writing specs.
When modifying existing code, show exact file path and current state vs desired state. This eliminates ambiguity about what's changing.
Example:
**File:** `backend/src/features/students/student.types.ts`
**BEFORE (Today):**
```typescript
export interface Student {
userId: string;
email: string;
createdAt: string;
}AFTER (Tomorrow):
export interface Student {
userId: string;
email: string;
createdAt: string;
interestedInPremium?: boolean; // New: early access signup flag
premiumInterestDate?: string; // New: ISO timestamp when signed up
}### 2. Type Contracts First
Define interfaces, schemas, and data structures upfront before any implementation. This can be an entire slice focused only on types—constraining shape removes ambiguity.
**Example:**
```typescript
// Define all types before implementation
export interface LessonEntity {
PK: string; // "COURSE#<courseId>"
SK: string; // "LESSON#<lessonId>"
lessonId: string;
title: string;
videoKey: string; // S3 object key
order: number;
}
export interface LessonResponse {
lessonId: string;
title: string;
videoUrl: string; // Signed CloudFront URL (not S3 key)
isCompleted?: boolean;
}Show one good example and one bad example with explanation of why the bad version fails. Negative examples prevent common mistakes.
Example:
**DO ✅ - Verify enrollment before serving video URL**
```typescript
const lesson = await getLesson(lessonId);
const isEnrolled = await checkEnrollment(studentId, lesson.courseId);
if (!isEnrolled) {
return res.status(403).json({ error: 'Not enrolled' });
}
const signedUrl = await generateSignedUrl(lesson.videoKey);DON'T ❌ - Serve video URLs without authorization
const lesson = await getLesson(lessonId);
const signedUrl = await generateSignedUrl(lesson.videoKey);
// Anyone with lessonId can access video - security vulnerability!### 4. Narrative Temporal Flows with MermaidJS
Use MermaidJS diagrams to show causality across system layers. Participants should map to system boundaries (Student, Frontend, Backend API, DynamoDB, etc.).
**Sequence Diagrams** - For temporal flows showing request/response chains:
```mermaid
sequenceDiagram
participant Student
participant Frontend
participant Backend API
participant DynamoDB
Student->>Frontend: Click "Lesson 2"
Frontend->>Backend API: GET /api/lessons/lesson-2/video-url
Backend API->>Backend API: Verify enrollment
Backend API-->>Frontend: Signed CloudFront URL
Frontend-->>Student: Load video player
Note over Student: Watches video to 90%
Frontend->>Backend API: POST /api/progress
Backend API->>DynamoDB: Update completedLessons
Backend API-->>Frontend: { percentage: 40 }
Frontend-->>Student: Show checkmark, update progress barFlowcharts - For decision logic and component relationships:
flowchart TD
LC[Lesson Completed] --> HF{feedbackGiven?}
HF -->|Yes| NP[No Prompt]
HF -->|No| CL{completedLessons >= threshold?}
CL -->|No| NP
CL -->|Yes| SP[Show Feedback Modal]
style SP fill:#90EE90Spec-planning conventions:
style X fill:#90EE90 to highlight new componentsDocument what future slices/phases will need from the current implementation. Prevents rework and captures dependencies.
Example:
## Forward-Looking Requirements
### For Slice 1.3 (Progress API)
- Progress percentage calculation: `(completedLessons.length / totalLessons) * 100`
- `totalLessons` must be provided or calculated from Lesson count query
### For Slice 1.4 (Video Player Component)
- Video URL fetching: When user clicks lesson → Call `GET /api/lessons/:lessonId/video-url`
- Progress tracking trigger: When video reaches 90% → Call `POST /api/progress`When adding new components or reorganizing code, show the directory structure with inline comments explaining what's new, what's updated, and why the structure matters.
Example:
**BEFORE (Today):**backend/ └── email/ └── handler.ts # Simple Lambda handler, sends hardcoded emails
**AFTER (Tomorrow):**backend/ └── email/ ├── handler.ts # Lambda handler (from Slice 4.1) - unchanged ├── render.ts # NEW: Email rendering + event router ├── types.ts # UPDATE: Add event and email data types ├── emails/ │ ├── enrollment-email.tsx # NEW: React Email template │ └── index.ts # NEW: Export all templates ├── components/ │ ├── header.tsx # NEW: Reusable email header │ ├── footer.tsx # NEW: Reusable email footer │ └── index.ts # NEW: Export all components ├── package.json # NEW: React Email dependencies ├── tsconfig.json # NEW: TypeScript config for email workspace └── .react-email/ # Auto-generated by dev server (gitignored)
**Why this structure:**
- `emails/` folder: Templates are separate from rendering logic
- `components/` folder: Shared components for consistent branding
- `render.ts`: Central router handles all email types
- Workspace-specific package.json: Email dependencies isolated from main backendExperts and Signals enhance spec planning by curating domain knowledge (Experts) and defining runtime validation (Signals).
Experts are Agent Skills that provide domain-specific guidance during spec planning. They help curate better context by offering framework-specific patterns, security best practices, and internal library documentation, etc.
MUST Read the experts catalog at START of planning: references/experts.md
Signals are Agent Skills that provide runtime feedback during implementation. They validate that code works as expected beyond just unit tests passing.
MUST Read the signals catalog at START of planning: references/signals.md
references/experts.md at the start of spec planningskill: "{expert-name}"references/signals.md at the start of spec planningEvery slice must include a Signal section after the Objective:
# Slice X.Y: Name
## Objective
...
## Signal
**Signal Skill:** {signal-skill-name | None}
**Expected Behavior:**
- Specific validations for this slice
- what should succeed when correctly implemented
## BEFORE/AFTER Directory Structure
[rest of slice...]3a7a725
Also appears in
since Aug 20, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.