Lightweight spec-driven development for product engineers and AI agents. Write executable feature specs before code, map them to product-stack layers, and verify implementation against acceptance criteria. Use when planning features, delegating to agents, or ensuring consistent CRUD implementation.
install
npx skills add nabinkhair42/nk-skills --skill feature-spec
Feature Spec
Spec-driven development without enterprise ceremony. Write a feature spec before code — structured enough for an AI agent to execute end-to-end without follow-up questions.
The spec is the source of truth. Code is derived from it.
Pairs with product-stack (9-layer checklist) and agent-verification patterns.
When to Write a Spec
| Write a spec | Skip the spec |
|---|---|
| New CRUD resource | One-line bug fix |
| Multi-layer feature (DB → UI) | Style tweak |
| Agent-delegated implementation | Config change |
| Feature touching 3+ files | Dependency bump |
Test: “Could an agent execute this without asking me a follow-up question?” If no, the spec isn’t clear enough.
Spec Template
Copy this for every new feature:
# Feature: [Name]
## Outcome
One sentence: what the user can do when this ships.
## Scope
### In
- [ ] Specific capability 1
- [ ] Specific capability 2
### Out
- What this feature explicitly does NOT include
## Constraints
- Must follow product-stack 9-layer flow
- Auth: [protected | admin | public]
- No hardcoded API paths (use API_ENDPOINTS)
- [Any domain-specific rules]
## Data Model
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| name | text | yes | max 100 chars |
| status | enum | yes | draft, active, archived |
## API
| Method | Path | Auth | Description |
| --- | --- | --- | --- |
| GET | /api/{resource} | protected | List with pagination |
| POST | /api/{resource} | protected | Create |
| GET | /api/{resource}/[id] | protected | Get by ID |
| PUT | /api/{resource}/[id] | protected | Update |
| DELETE | /api/{resource}/[id] | protected | Delete |
## UI
- [ ] List view with data table (sort, filter, paginate)
- [ ] Create dialog
- [ ] Edit dialog (optimistic open with list data)
- [ ] Delete confirmation
- [ ] Empty state for first-time users
## Acceptance Criteria
- [ ] User can create a {resource} and see it in the list immediately (no refetch)
- [ ] User can edit a {resource} — form opens instantly with cached data
- [ ] User can delete a {resource} — removed from list without page reload
- [ ] Invalid input shows field-level errors from Zod validation
- [ ] Unauthorized users get 401, non-owners get 403
## Layers Checklist
- [ ] 1. DB Schema — `db/schema/{resource}.ts`
- [ ] 2. Endpoints — `API_ENDPOINTS.{RESOURCE}` + `QUERY_KEYS`
- [ ] 3. Zod Schema — `schemas/{resource}.ts`
- [ ] 4. Route Handlers — `app/api/{resource}/route.ts` + `[id]/route.ts`
- [ ] 5. Service — `services/{resource}.service.ts`
- [ ] 6. Hook — `hooks/use-{resource}.ts`
- [ ] 7. Columns — `components/{resource}/{resource}-columns.tsx`
- [ ] 8. Table — `components/{resource}/{resource}-table.tsx`
- [ ] 9. Dialogs — create/edit/delete in `components/{resource}/`
Spec → Implementation Flow
1. Write spec (this template)
2. Review: "Can an agent execute without follow-ups?"
3. Agent implements layer by layer (never skip)
4. Verify against acceptance criteria
5. Ship
Phase 1: Specify
Fill the template. Focus on outcome and acceptance criteria — not implementation details. The agent derives implementation from constraints + layers checklist.
Bad outcome: “Add tasks feature” Good outcome: “User can create, edit, delete, and filter tasks by status from the dashboard”
Phase 2: Plan (optional for complex features)
For features with cross-resource dependencies, add a technical plan:
## Technical Plan
- Tasks belong to Projects (FK: projectId → projects.id, cascade delete)
- Status enum: todo, in_progress, done
- List endpoint filters by projectId (required query param)
- Optimistic cache: edit opens with list data, fetches assignee in background
Phase 3: Implement
Agent follows the layers checklist in order. Each layer is a separate step — never combine.
Phase 4: Verify
Check every acceptance criterion. Check every layer exists. Run the agent-verification checklist:
- No hardcoded
/api/strings in services or components - Components call hooks, not services
- Every mutation invalidates or updates cache (not both)
- Route handlers use
schema.safeParse()before processing - FK columns have indexes
-
enabled: !!idon single-item queries
Constitutional Constraints
Non-negotiable rules that apply to every feature. Store in .cursor/rules/ or reference in every spec:
## Constitution
1. Every feature follows the 9-layer product-stack flow — no shortcuts
2. API paths live only in `config/api-endpoints.ts`
3. Types come from Zod (`z.infer`) or Drizzle (`$inferSelect`) — never manual duplicates
4. Toast notifications live in hook `onSuccess`/`onError` — never in services
5. Server Components by default — `"use client"` only at the leaf
6. Auth on every mutation — `protectedApi` or `adminApi`
7. Validate every request body with Zod `safeParse()`
When an agent violates a constitutional rule, reject the output and re-run with the constraint highlighted.
Spec Examples
Minimal (bug fix — skip spec)
“Fix pagination offset on projects list” — no spec needed.
Standard (new CRUD resource)
# Feature: Tasks
## Outcome
User can manage tasks within a project from the project detail page.
## Scope
### In
- CRUD tasks scoped to a project
- Filter by status (todo, in_progress, done)
- Assignee field (user ID, optional)
### Out
- Subtasks
- Due date reminders
- Cross-project task view
## Constraints
- Must follow product-stack 9-layer flow
- Auth: protected (project owner only)
- Tasks cascade-delete when project is deleted
## Data Model
| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| id | uuid | auto | primary key |
| projectId | uuid | yes | FK → projects.id, cascade |
| title | text | yes | max 200 chars |
| status | enum | yes | todo, in_progress, done |
| assigneeId | text | no | FK → users.id, set null |
| position | integer | yes | sort order, default 0 |
## Acceptance Criteria
- [ ] Tasks appear in project detail page table
- [ ] Create task dialog opens from project page
- [ ] Edit opens instantly with cached title/status
- [ ] Delete removes task from list without refetch
- [ ] Only project owner can CRUD tasks
Complex (AI feature)
# Feature: AI Project Summary
## Outcome
User can generate an AI summary of a project's tasks and status from the project detail page.
## Scope
### In
- "Summarize" button on project detail page
- Streams summary text inline
- Uses project tasks as context
### Out
- Chat interface
- Editing the summary
- Sharing summaries
## Constraints
- Must follow product-ai-layer patterns
- Rate limit: 5 summaries per hour per user
- Auth: protected (project owner only)
- Tool scopes to user's projects only
## API
| Method | Path | Auth | Description |
| --- | --- | --- | --- |
| POST | /api/ai/summarize | protected | Stream project summary |
## Acceptance Criteria
- [ ] Summary streams token-by-token (not blocking spinner)
- [ ] Rate limit shows clear error after 5 uses
- [ ] Summary references actual task data, not hallucinated
- [ ] Stop button cancels generation
Storing Specs
Keep specs in the repo so agents can read them:
specs/
├── tasks.md
├── ai-project-summary.md
└── billing-integration.md
Or inline in PR descriptions for smaller features. The key rule: specs are versioned in git, not in chat history or sprint boards.
Agent Handoff Prompt
When delegating to an agent, paste:
Implement the feature described in specs/{name}.md.
Follow the layers checklist in order. Do not skip layers.
Apply constitutional constraints from the spec.
Verify every acceptance criterion before finishing.
Common Mistakes
- Vague outcomes — “add tasks” vs “user can CRUD tasks filtered by status”
- Missing acceptance criteria — agent ships code that “works” but doesn’t meet UX expectations
- Skipping the Out of scope section — agent adds features you didn’t ask for
- Spec in chat, not in repo — lost after session ends; agents can’t re-read it
- No constitutional constraints — agent invents its own patterns per feature
- Implementing before spec review — rework costs 3x when requirements were ambiguous
- Acceptance criteria without cache behavior — “see it immediately” requires optimistic cache, not just CRUD