TDD-first spec workflow for AI coding agents. Strict red-green-refactor enforcement, alternating TEST-IMPL task pairs, TDD Log audit trail. Everything in Spec Mint Core plus test-driven discipline. Claude Code plugin + universal skill.
SaferSkills independently audited specmint-tdd (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Turn ephemeral plans into structured, persistent specs built through deep research and iterative interviews — with strict test-driven development at every step. Every task starts with a failing test, production code exists only to make tests pass, and refactoring happens under green. Tests use testcontainers for real services, mock only at boundaries, and make no external network calls. Specs have phases, tasks, acceptance criteria, a registry, resume context, a decision log, a TDD log, and a deviations log. They live in .specs/ at the project root and work with any AI coding tool that can read markdown.
Whether .specs/ is committed is repository policy. Respect .gitignore and the user's preference for tracked vs local-only spec state.
SKILL.md file..specs/registry.md.specs/<id>/SPEC.md, .specs/<id>/research-*.md,.specs/<id>/interview-*.md
SPEC.md frontmatter is authoritative. Registry is adenormalized index for quick lookup.
guidance instead of hard failure on malformed rows.
workflow enforces red-green-refactor at every task. Tests are executed via the actual test runner, not assumed to pass. This is sacred — see "Tests Are Sacred" and "Blocking Rule" in the implement section.
update SPEC.md (checkbox, ← current marker, phase marker, TDD log) AND registry.md (progress count, date). Then re-read both files to verify the edits landed correctly. Never move to the next task without updating both files. Never end a session with the registry out of sync with SPEC.md. This is non-negotiable — if you do nothing else, do this.
If active-spec context was injected by host tooling, use it directly instead of reading files. Otherwise, fall back to reading files manually:
.specs/registry.md to check for a spec with active status"You have an active spec: User Auth System (5/12 tasks, Phase 2). Say 'resume' to pick up where you left off."
| Situation | Required behavior |
|---|---|
.specs/registry.md missing | If .specs/ exists, report "No registry yet" and offer to initialize it. If .specs/ is missing, report "No specs yet" and continue normally. |
| Malformed registry row | Skip malformed row, emit warning with row text, continue parsing remaining rows. |
Multiple active rows | Warn user. Pick the row with the newest Updated date (or first active row if dates are unavailable) for this run. On next write, normalize to a single active spec. |
Registry row exists but .specs/<id>/SPEC.md missing | Warn and continue. Keep row visible in list/status with (SPEC.md missing). |
| Registry and SPEC conflict | Trust SPEC.md, then repair registry values on next write. |
| No active spec | List available specs and ask which to activate or resume. |
When the user says "resume", "what was I working on", or similar:
.specs/registry.md — find the spec with active status. If none, list specs and ask which to resume.specs/<id>/SPEC.md[x] vs total tasks per phase[in-progress] phase)← current marker, or first unchecked in current phase) Resuming: User Auth System
Progress: 5/12 tasks (Phase 2: OAuth Integration)
Current: [TEST-AUTH-07] Write OAuth callback tests
TDD Phase: RED (next: write test, run, confirm fail)
Last Cycle: [IMPL-AUTH-06] GREEN — 4/4 pass
Context: Finished Google OAuth (TEST-05 red, IMPL-06 green+refactored).
Starting GitHub OAuth callback tests next.
Next file: tests/auth/test_oauth_github.pyWhen the user says "implement the spec", "implement phase N", "implement all phases", or similar:
#### Scope Detection
Parse the user's request to determine scope:
(the ← current marker) and work forward
tasks in that specific phase
remaining unchecked tasks across all phases, in order
#### TDD Implementation Flow
.specs/registry.md to find the active spec.specs/<id>/SPEC.md and parse phases/taskstask code prefix (TEST- vs IMPL-)
TEST-IMPL pair is one red-green-refactor cycle.
For each TEST-IMPL pair (one red-green-refactor cycle):
RED — TEST task:
← currentand test descriptions listed
Do not proceed. Either the feature already exists or the tests are wrong.
| [TEST-XX-NN] | <command>: N tests, N failed — <key failure message> | — | — |
- [ ] -> - [x], remove ← currentGREEN — IMPL task:
← currentthe tests expect
tests require. Nothing more.
and run again. Repeat until green. Do not modify tests to make them pass (see Tests Are Sacred below).
| [IMPL-XX-NN] | — | <command>: N passed, 0 failed | — |
REFACTOR — still on the IMPL task:
helpers
- [ ] -> - [x], remove ← current.specs/registry.mdThen move to the next TEST-IMPL pair and repeat.
#### Self-Check Before Every Task
Before starting any task, pause and verify:
← current marker? → Do it now.If any answer is wrong, correct it before proceeding.
#### Violation Examples
These are common TDD violations. If you recognize yourself doing any of these, STOP immediately and correct course:
| Violation | What it looks like | Correct action |
|---|---|---|
| Writing code before test | "I'll implement the handler first, then test it" | Write the test first. Watch it fail. Then implement. |
| Skipping test execution | "The tests would pass since I wrote the correct code" | Run the tests via Bash. Read the actual output. |
| Modifying tests to pass | "I'll adjust the assertion to match what the code returns" | The test is the spec. Fix the production code to match. |
| Batching tests | "I'll write all 3 tests, then implement all 3" | Write one test. Implement. Write the next test. Implement. |
| Skipping refactor | "The code is fine, moving to the next test" | Review the code. Decide consciously. Log "none" if no changes. |
| Forgetting TDD Log | "I'll update the log later" | Update it now, after each task. It's the audit trail. |
#### Tests Are Sacred
Tests define expected behavior. They are the specification in code form. During the GREEN phase, when tests fail:
syntax error, broken test setup) — not when the assertion doesn't match what your code returns
wrong — make it do X
changed, the user gave new requirements), STOP and ask the user before modifying the test. Do not silently change test expectations.
#### Blocking Rule
Each IMPL task is preceded by its TEST task. You cannot start an IMPL task until its TEST task is completed and the tests are confirmed failing. This is enforced per-task. If about to write implementation code before its test exists, STOP and write the test first. Non-negotiable.
#### Test Execution Rule
Run the actual test command (pytest, vitest, cargo test, go test, dotnet test, etc.) via Bash at every RED, GREEN, and REFACTOR transition. That is 3 runs minimum per TEST-IMPL cycle. Claims like "tests would pass" or "tests should fail" are never acceptable — run them and report the actual output. If the test runner is not available, report the blocker immediately.
#### Phase Transitions
Phases group by feature, not by test vs implementation. Each phase contains interleaved TEST-IMPL pairs. When all tasks in a phase are done, the phase is [completed] and the next phase becomes [in-progress].
#### Update Transaction (sacred — never skip steps)
Progress tracking is sacred (see Critical Invariant #7). Stale tracking is the single most common failure mode — it makes resume unreliable and the registry useless.
SPEC.md (checkbox, current marker, phase marker, resume context,TDD log entry).
SPEC.md checkboxes.SPEC.md and registry.md to confirm theedits are correct. If the registry progress doesn't match the SPEC.md checkbox count, fix it now.
SPEC.md as source of truth and emit awarning with exact repair action for .specs/registry.md.
If you notice you forgot to update after a previous task, stop what you're doing and update now before continuing.
Also:
discovered, assumptions proved wrong), log it in the Deviations section
on — re-read the phase's tasks and acceptance criteria, verify each task's implementation matches what was specified, check that the TDD Log has entries for every TEST-IMPL pair, and check for missing edge cases or spec drift. Fix issues before marking the phase complete. Log findings in the Decision Log.
#### Verification Gate
Before reporting any phase or spec as complete, provide evidence:
Evidence first, then assertions. The TDD log captures per-task evidence; this gate ensures phase and spec completion also have fresh verification.
#### Completion
When all in-scope tasks are done:
report which ones and ask the user before marking the spec complete.
[completed]completed in frontmatter and registryupdated date[in-progress] if applicableWhen the user says "pause", switches specs, or a session is ending:
← current marker to the right taskstatus: paused in frontmatterupdated dateResume Context is the most important part of pausing. Write it as if briefing a colleague who will pick up tomorrow. Include specific file paths, function names, the exact next step, and the TDD state. Vague context like "was working on auth" is useless — write "implementing verifyRefreshToken() in src/auth/tokens.ts to satisfy TEST-AUTH-03. Tests in tests/auth/test_tokens.py are RED — 2 of 3 assertions failing on refresh rotation. Next step: hook up rotation logic to the /auth/refresh endpoint."
.specs/<target-id>/SPEC.md exists. If not, stop with an error.active in frontmatter and in .specs/registry.md.YAML frontmatter with: id, title, status, created, updated, optional priority and tags.
Status values: active, paused, completed, archived
[pending], [in-progress], [completed], [blocked]
- [ ] [TEST-CODE-01] unchecked test task, - [x] [TEST-CODE-01] done- [ ] [IMPL-CODE-02] unchecked impl task, - [x] [IMPL-CODE-02] done[TEST-PREFIX-NN] — for tasks that write failing tests[IMPL-PREFIX-NN] — for tasks that write production codeto satisfy tests. Each impl task includes -> satisfies [TEST-XX-NN] referencing the test task it makes pass.
pair is one red-green-refactor cycle.
(e.g., user-auth-system -> AUTH). Numbers auto-increment continuously across all phases starting at 01.
<- current after the task text marks the active task[NEEDS CLARIFICATION] after the task code on unclear tasksstrategy (testcontainers, mocks at boundaries, in-memory where appropriate)
task it satisfies
Testable conditions that define when the spec is "done". Written during forge, verified after each phase completes. Format: checkboxes with specific, verifiable statements — not vague goals.
## Acceptance Criteria
- [ ] Users can sign in with Google OAuth and receive a JWT
- [ ] Expired tokens return 401 with `{"error": "token_expired"}`
- [ ] Refresh tokens rotate on each use (old token is invalidated)
- [ ] All auth paths have corresponding red-green-refactor cycles in TDD LogCheck off criteria as they are satisfied during implementation. At phase completion, review which acceptance criteria are now met. At spec completion, all criteria must be checked — if any remain unchecked, the spec is not done.
Specs include a Testing Architecture section specifying:
at system boundaries (HTTP clients, third-party APIs), no external network calls in tests
→ service → DB → response) using testcontainers for real databases and mocked external APIs (MSW, WireMock). No browser needed.
applicable
A markdown table tracking the red-green-refactor cycle for every task:
## TDD Log
| Task | Red | Green | Refactor |
|------|-----|-------|----------|
| [TEST-AUTH-01] | 3 tests fail: `Cannot find module './jwt'` | — | — |
| [IMPL-AUTH-02] | — | 3/3 pass after implementing JwtService | Extracted token config to constants |
| [TEST-AUTH-03] | 2 tests fail: `Expected rotated token` | — | — |
| [IMPL-AUTH-04] | — | 5/5 pass | Renamed `createToken` -> `issueAccessToken` |The TDD Log is an audit trail proving discipline was followed. It is filled in during implementation, not during forging.
Blockquote section with specific file paths, function names, exact next step, and TDD state (current phase, failing tests, last run output). This is what makes cross-session continuity work.
Markdown table with date, decision, and rationale columns. Log non-obvious technical choices (library selection, architecture pattern, API design).
Markdown table tracking where implementation diverged from the spec: task, what the spec said, what was actually done, and why. Only log changes that would surprise someone comparing the spec to the code.
Use this skeleton when creating new specs. references/spec-format.md has the full template with examples.
---
id: <spec-id>
title: <Human Readable Title>
status: active
created: <YYYY-MM-DD>
updated: <YYYY-MM-DD>
priority: high | medium | low
tags: [<tag1>, <tag2>]
---
# <Title>
## Overview
<2-4 sentences: what and why>
## Acceptance Criteria
- [ ] <Testable condition 1>
- [ ] <Testable condition 2>
- [ ] <Testable condition 3>
## Architecture
<ASCII art or Mermaid diagram>
## Testing Architecture
### Test Framework & Tools
| Tool | Choice | Version | Purpose |
|------|--------|---------|---------|
| Test framework | <name> | <ver> | Unit and integration tests |
| Mocking library | <name> | <ver> | Dependency isolation |
| DB testing | <name> | <ver> | Real database tests |
### Isolation Strategy
| Layer | Approach | Services |
|-------|----------|----------|
| Domain logic | No mocks; pure functions | None |
| Service layer | Mock ports/interfaces | <deps> |
| Data access | Testcontainers | <DB/cache> |
| HTTP clients | MSW / WireMock | <external APIs> |
### Coverage Targets
| Metric | Target |
|--------|--------|
| Line coverage | <XX%> |
| Branch coverage | <XX%> |
### Test Commands
| Command | Purpose |
|---------|---------|
| `<test command>` | Run all tests |
## Library Choices
| Need | Library | Version | Alternatives | Rationale |
|------|---------|---------|-------------|-----------|
## Phase 1: <Feature A> [in-progress]
- [ ] [TEST-XX-01] <test task with file path, assertions, isolation> <- current
- [ ] [IMPL-XX-02] <impl task> -> satisfies [TEST-XX-01]
- [ ] [TEST-XX-03] <test task>
- [ ] [IMPL-XX-04] <impl task> -> satisfies [TEST-XX-03]
## Phase 2: <Feature B> [pending]
- [ ] [TEST-XX-05] <test task>
- [ ] [IMPL-XX-06] <impl task> -> satisfies [TEST-XX-05]
CRITICAL: Phases group by FEATURE, not by test-vs-impl. Every phase
has interleaved TEST-IMPL pairs. A phase containing only TEST tasks
or only IMPL tasks is WRONG. A phase named "Tests for X (TEST)" or
"Implement X (IMPL)" is WRONG. Correct: "Phase 1: Auth Foundation"
with TEST-01, IMPL-02, TEST-03, IMPL-04 alternating inside it.
---
## Resume Context
> <TDD Phase, failing tests, last run, next step, file paths>
## Decision Log
| Date | Decision | Rationale |
|------|----------|-----------|
## TDD Log
| Task | Red | Green | Refactor |
|------|-----|-------|----------|
## Deviations
| Task | Spec Said | Actually Did | Why |
|------|-----------|-------------|-----|When asked to forge, plan, spec out, or "write a spec for X", follow the full forge workflow: setup, research deeply, interview the user, iterate until clear, then write the spec.
Plan mode: In Claude Code, if the environment is in read-only plan mode, ask the user to exit plan mode (Shift+Tab) and start the forge workflow again. Other tools: proceed normally.
The forge workflow never produces application code. Its outputs are only .specs/ files: research notes, interview notes, and the SPEC.md.
"User Auth System" -> user-auth-system
.specs/<id>/SPEC.md already exists or the IDappears in .specs/registry.md, warn the user and ask:
<id>-v2 or ask for a new title)Do not proceed until the user chooses.
mkdir -p .specs/<id>.specs/registry.md doesn't exist, initialize it with the header row.Research is the foundation of a good spec. Be exhaustive — use every available resource so the spec won't need revision mid-build.
Research runs on two parallel tracks:
#### Track A: Spawn a Research Subagent
If your tool supports subagents: Spawn a research subagent with the Task tool, using the brief in references/researcher.md. Provide: the user's request, spec ID, output path .specs/<id>/research-01.md, and any Context7 findings from Track B. The research subagent maps the project architecture, reads 15-30 files, runs 3+ web searches, compares library candidates, assesses risks, and analyzes the full test infrastructure.
If subagents are not available: Perform the research inline yourself — scan the project structure, read relevant files (15-30 for non-trivial features), search the web for best practices and library comparisons, and analyze the existing test infrastructure (frameworks, runners, mocking patterns, testcontainers, coverage tools). Save findings to .specs/<id>/research-01.md.
#### Track B: Context7 & Cross-Skill Research (in parallel)
While the research subagent runs (or between inline research steps):
libraries. Check API changes, deprecated features, and recommended patterns.
modern UI patterns, accessibility requirements
#### Merging Research
Combine all findings. The research should cover: architecture, relevant code, tech stack, library comparisons, internet research, Context7 docs, UI research (if applicable), risk assessment, test infrastructure analysis, and open questions.
Present research findings and ask targeted questions:
should we follow that pattern or is there a reason to change?")
or use a testcontainer with a sandbox endpoint?")
conditions that must be true when this is complete?")
STOP after presenting questions. Wait for the user to answer. Do not answer your own questions, assume answers, or continue until the user responds. Save to .specs/<id>/interview-01.md.
Based on answers, do another round of research — explore chosen paths, check feasibility, find issues. Save to .specs/<id>/research-02.md. Then present findings and ask about trade-offs, edge cases, implementation sequence, and scope refinement.
Repeat until: no ambiguous tasks remain, the user is satisfied, and every task can be described concretely. Two rounds is typical.
Synthesize all research and interviews into a SPEC.md using the template above. The spec should include:
Derived from interview answers. Check them off during implementation.
coverage targets, test commands, anti-patterns
per pair, not batched). Phases are named by feature ("Auth Foundation"), NEVER by test-vs-impl ("Tests for Auth" / "Implement Auth"). No (TEST) or (IMPL) suffixes on phase names. Every phase contains both TEST and IMPL tasks alternating.
[TEST-PREFIX-NN] and [IMPL-PREFIX-NN] codes alternatingwithin each phase
Coherence review (mandatory before presenting):
behaviors the user expects
with only TEST tasks or only IMPL tasks is WRONG. A phase named "Tests for X" or "Implement X" or with (TEST)/(IMPL) suffix is WRONG. Restructure: merge test-only and impl-only phases into a single feature phase with alternating TEST-IMPL pairs inside.
[IMPL-XX-NN] task immediately follows its [TEST-XX-NN] task[TEST-XX-NN] task is followed by an [IMPL-XX-NN] that satisfies it"TBC", "to be determined", "will be decided", "figure out" — replace every instance with a concrete decision or remove the section
tasks, all task code references are valid, -> satisfies references point to existing TEST tasks, library versions don't conflict
it deliver what was discussed? Nothing more, nothing less?
this without asking me a question?" If no, add detail until yes.
Save to .specs/<id>/SPEC.md. Update .specs/registry.md — set status to active. Mark first phase [in-progress], first task ← current.
Present the spec and wait for approval. Do not begin implementing until the user explicitly approves.
When the user says "generate openapi", "update api docs", or similar: scan the codebase for API routes, schemas, and security config. Write .openapi/openapi.yaml (OpenAPI 3.1.1) with operationId per operation, reusable $ref schemas, and accurate parameters/responses/security. Write per-endpoint docs under .openapi/endpoints/{method}-{path-slug}.md. Preserve manual additions when updating existing files. Report totals.
If the session is ending:
.specs/
├── registry.md # Denormalized index for status/progress lookups
└── <spec-id>/
├── SPEC.md # The spec document
├── research-01.md # Deep research findings
├── interview-01.md # Interview notes
└── ....specs/registry.md is a simple markdown table:
# Spec Registry
| ID | Title | Status | Priority | Progress | Updated |
|----|-------|--------|----------|----------|---------|
| user-auth-system | User Auth System | active | high | 5/12 | 2026-02-10 |
| api-refactor | API Refactoring | paused | medium | 2/8 | 2026-02-09 |SPEC.md frontmatter is authoritative. The registry is a denormalized index for quick lookups. Always update both together. If they conflict, SPEC.md wins.
Use these concise formats consistently:
Resume
Resuming: <Title> (<id>)
Progress: <done>/<total> tasks
Phase: <phase name>
Current: <task text>
TDD Phase: RED | GREEN | REFACTOR
Failing Tests: <count and names>
Last Test Run: <result>
Context: <one to three lines from Resume Context>List
Active:
-> <id>: <Title> (<done>/<total>, <phase>) [<priority>]
Paused:
|| <id>: <Title> (<done>/<total>, <phase>) [<priority>]
Completed:
+ <id>: <Title> (<done>/<total>) [<priority>]Status
<Title> [<status>, <priority>]
Created: <date> | Updated: <date>
Phase <n>: <name> [<marker>]
Progress: <done>/<total> (<pct>%)
Current: <task text or none>completed in frontmatter and registryupdated date in botharchived in frontmatter and registrySpecs can be archived from completed or paused status.
.specs/<id>/ directory.specs/registry.mdThis is irreversible — consider archiving instead.
The spec format is pure markdown with YAML frontmatter. Any tool that can read and write files can use these specs:
npx skills add (auto-triggers on natural language)npx skills addTo configure another tool, run npx skills add ngvoicu/specmint-tdd -g -a <tool>.
Be proactive about spec management. If you notice the user has made progress, update the spec without being asked. If a session is ending, offer to pause and save context.
Specs should evolve. It's fine to add tasks, reorder phases, or split a phase as understanding deepens.
The Decision Log matters. Log non-obvious technical choices with rationale. Future-you resuming this spec will thank present-you.
The TDD Log matters. It is the audit trail proving red-green-refactor discipline. Fill it in as you go — not retroactively.
Don't over-structure. A spec with 3 phases and 15 tasks is useful. A spec with 12 phases and 80 tasks is a project plan, not a coding spec.
Respect the user's flow. Don't interrupt deep coding work to update the spec. Batch updates for natural pauses.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.