Files
skills/feature-spec/SKILL.md
Mathias d6a71e370e
Some checks failed
release / tag (push) Has been cancelled
chore: bootstrap skills library — 19 skills + installer + CI auto-tag
Phase 1 of mathias/skills extraction (infra#62 Track D — homelab
next-step plan addendum). Imports ~/dev/.skills/ verbatim (19 skill
dirs + SKILLS_INDEX.md) and adds the installation surface:

- Taskfile.yml — install / update / list / release / check targets
- install.sh — bootstrap installer for hosts without Task. Idempotent
  symlink wirer; default checkout at ~/.local/share/skills/ on every
  host; SKILLS_REF env var pins a tag (default: main).
- .gitea/workflows/release.yml — auto-tag every push to main by
  Bump-Type footer (major/minor/patch, default patch). Skipped when
  commit contains [skip-release].
- README — usage, versioning, contribution flow, secret-hygiene rule.

Phase 1 wires Claude Code only (~/.claude/skills/<name> global +
<repo>/.claude/skills/<name> per-repo). Phase 2 adds Crush, opencode,
antigravity, and gitea-resident agents (cobalt-dingo, agentsquad)
once their skill conventions are researched.

Public repo, markdown-only — no secrets, no client names. Verified
via pre-push grep before initial push.

[skip-release]
2026-05-24 14:59:54 +02:00

173 lines
8.0 KiB
Markdown

---
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: "<phase-name>", final_status: "pass" | "fail" | "skip", message: "<one-line summary>", duration_ms: <wall-clock>, project_root: "<absolute path>"}`
**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.