--- name: feature-spec description: Write a tight implementation-level spec for a single feature or component before coding it. Use after a project-level spec exists (see spec-driven-dev) and you need to nail down one feature inside it. --- # Feature Spec ## Overview A feature spec is the implementation-level contract for one feature or component, written by an engineer before code. It is shorter and more focused than a project-level spec (`spec-driven-dev`) — it assumes the project context, the stack, and the user are already known. Its job is to force one decision: **what does done look like, and what is explicitly not in this feature.** **Core principle:** If you cannot write three measurable success criteria, you do not understand the feature well enough to build it. ## When to Use - About to start implementing a feature inside an existing, already-specced project - A change that touches more than one file or one package - A change that introduces a new public API, schema, or external contract - Any time the requirements feel "obvious" — that feeling usually means assumptions are stacking silently **When NOT to use:** - Project kickoff or first-time architecture decisions — use `spec-driven-dev` instead, which covers the broader lifecycle (Objective, Tech Stack, Project Structure, Boundaries, etc.) - Single-line fixes, typos, dependency bumps - Spike or throwaway prototypes (note them as such; no spec needed) ## Iron Laws 1. **Success criteria must be measurable.** "The system is fast" is banned. "p99 < 200ms under 100 RPS" is valid. If you cannot state a measurement, the criterion is not a criterion. 2. **An "Out of scope" section is mandatory.** If you do not draw the boundary, the implementer (you, future-you, or another agent) will guess wrong. 3. **Every technical decision in "Technical approach" must have a rationale.** A decision is any choice where a reasonable alternative existed and was not taken. "Use Postgres" is not a decision; "use Postgres because the rest of the stack uses it and we need transactions across user + invoice" is. ## Spec Template ```markdown # Spec: [Feature Name] ## Problem Statement What problem does this feature solve? For whom? Why now? (2-4 sentences. If you cannot answer "why now," ask before writing the rest.) ## Success Criteria - [ ] Criterion 1 — measurable and verifiable - [ ] Criterion 2 — measurable and verifiable - [ ] Criterion 3 — measurable and verifiable ## Constraints Non-negotiable requirements the solution must satisfy. Examples: "must not change the public API", "must complete in < 500ms", "must not require a database migration", "must work offline". ## Out of Scope What this feature explicitly does NOT do, even if related. Anything plausibly in scope that you decided to defer goes here. ## Technical Approach The architecture or design decisions, with rationale for each. Each bullet should answer "why this choice over the obvious alternative." ## Risks What could go wrong, and how it would be mitigated or detected. At least one risk must be listed; "no risks" usually means insufficient analysis. ``` ## Worked Example ```markdown # Spec: IBAN extraction from Swedish PDF invoices ## Problem Statement Invoice processors at small accounting firms manually copy IBANs from PDF invoices into the banking system. The current parser handles ~60% of formats; 40% require manual fallback, defeating the automation premise. Why now: the pilot customer is onboarding three new firms next month, all of which use formats currently in the 40%. ## Success Criteria - [ ] IBAN extracted correctly from ≥ 95% of a 200-invoice test corpus - [ ] Zero false positives (extracting a non-IBAN string as an IBAN) on the corpus - [ ] p99 extraction time < 500ms per invoice - [ ] Returns a structured error (not a panic) for unrecognized formats ## Constraints - Must not require a new dependency (PDF library is already chosen) - Must work without network access (no external IBAN validation API) - Must be callable from the existing `Parser.Extract(ctx, r)` signature ## Out of Scope - Non-Swedish IBAN formats (separate spec when needed) - BIC/SWIFT extraction (handled by a separate parser) - OCR — input is assumed to be text-extractable PDF, not scanned image - Validating that the IBAN refers to a real account ## Technical Approach - Layered regex-then-checksum approach: regex narrows candidates, MOD-97 checksum validates. Rationale: pure regex is too permissive; pure checksum requires too many candidates to test. - Use the existing `pdfplumber` text layer rather than re-extracting. Rationale: extraction is already the slow path; reusing the layer avoids doubling extraction time. - Return `(iban string, ok bool, err error)` not `(*IBAN, error)`. Rationale: the caller almost always wants to know "did we find one" separately from "did extraction itself fail," and a pointer return invites nil-deref bugs. ## Risks - Regex tuned to current corpus may overfit; mitigation: corpus is held out per-firm, so we will see degradation at the next firm onboarding before it reaches production. - MOD-97 implementation bugs are subtle; mitigation: cross-check against the Wikipedia reference implementation in tests. ``` ## Common Rationalizations | Rationalization | Reality | |---|---| | "It's a small feature, I don't need a spec" | Small features still need a measurable definition of done. The spec stays small too. | | "I'll write the spec after, when I know more" | Then it is documentation, not a spec. The point is forcing clarity *before* the code locks in your assumptions. | | "The success criteria are obvious" | If they are obvious, they are easy to write down. If they are hard to write down, they are not obvious. | | "I don't have time to enumerate out-of-scope items" | You will spend more time arguing over scope creep at review than writing this section now. | ## Brain MCP Integration The brain holds prior feature specs across the project. Use it to keep constraints and out-of-scope decisions coherent across related features. **At spec start:** - Run `brain_query` for prior specs in the same area or for the same problem domain. Reusing the same constraints and out-of-scope decisions across related features keeps the system coherent. **After spec is approved:** - Run `brain_write` with the spec's success criteria and out-of-scope list. Future related specs can cross-reference rather than re-derive. ### Logging Call `session_log` once at the end of every phase to record the outcome. Pass-rate is computed downstream by the `/pass-rate` HTTP endpoint, which treats `pass` as success, `fail` as failure, `skip` as neither. **At end of each phase:** - `session_log` with `{skill: "feature-spec", phase: "", final_status: "pass" | "fail" | "skip", message: "", duration_ms: , project_root: ""}` **Phases for this skill:** draft **Status semantics:** - `pass` — the phase's intended outcome was reached (spec drafted and approved). - `fail` — the phase's intended outcome was NOT reached (spec rejected, blocked on unresolved questions). - `skip` — phase was skipped intentionally. **Why this matters:** the routing pod (Plan 6) reads pass-rate to decide whether to route a future call to a local model. If your skill never logs, the routing pod sees no data. ## Mode 2 Routing Note Spec writing requires interpretation of intent and tradeoff reasoning — work where Claude generally outperforms a 9-13B local model. This skill is intentionally **not** a Mode 2 routing candidate. In Mode 2, the routing layer should leave `feature-spec` calls on Claude. ## Cross-References - Load `spec-driven-dev` instead if this is the first spec for a project (broader template, includes tech stack, project structure, boundaries). - Load `problem-analysis` skill before this if the problem statement itself feels fuzzy. - Load `tdd` skill once the spec is approved — each success criterion becomes a test. - Load `planning` skill if the spec implies more than ~5 implementation tasks.