Skip to content
Agentmart
Submit a tool

tdd-loop

Drive the red-green-refactor loop for any non-trivial code change.

Skill by ramboz

IndexedMIT★ 7
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/ramboz-tdd-loop

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Drive the red-green-refactor loop for any non-trivial code change. Auto-detect the project's test runner (pytest / vitest / jest / node --test), invoke it via the `tdd.py` helper, and act on the normalized exit code. Use when you write a test, TDD this feature, let me test-drive a behaviour, are about to implement [feature], want to run my tests, ask is my coverage complete, or ask are tests green. Do not use for one-off exploratory scripts, throwaway spikes, or pure-documentation edits that touch no executable code.

Use cases: testing, writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Python package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/tdd-loop

What's inside

Skill name
tdd-loop
Description
Drive the red-green-refactor loop for any non-trivial code change. Auto-detect the project's test runner (pytest / vitest / jest / node --test), invoke it via the `tdd.py` helper, and act on the normalized exit code. Use when you write a test, TDD this feature, let me test-drive a behaviour, are about to implement [feature], want to run my tests, ask is my coverage complete, or ask are tests green. Do not use for one-off exploratory scripts, throwaway spikes, or pure-documentation edits that touch no executable code.
License
MIT
Instructions
194 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (3)

  • SKILL.md
  • quality.py
  • tdd.py

SKILL.md (first lines)

> Spec 006 promoted this skill from a dangling auto-install reference to an
> active skill. The deterministic runner detection + subprocess invocation
> live in `tdd.py`; this SKILL.md drives the judgment layer.

## What this skill does

Codifies the red-green-refactor loop that the `implementer` subagent
(`agents/implementer.md`) already encodes as "non-negotiable TDD discipline."
The skill:

- Detects the project's test runner from filesystem signals (one of `pytest`,
  `vitest`, `jest`, or Node's built-in `node --test`).
- Invokes the runner as a subprocess against a target, a focused
  `--test-path`, or a single `--test` selector.
- Streams the runner's stdout/stderr through to the caller — you see real
  output, not a swallowed summary.
- Normalizes the runner's native exit code so callers can branch
  deterministically:
  - `0` — all green
  - `1` — at least one red test (runner started but reported failure)
  - `2` — could not detect a runner, OR the runner binary is missing

## The red-green-refactor loop

1. **Red.** Write a failing test for one acceptance criterion (or one
   well-bounded behaviour). Run `tdd.py run <target>` and confirm the new
   test is the *only* new failure — exit 1.
2. **Green.** Write the minimum implementation that makes the test pass.
   Run `tdd.py run <target>` again; expect exit 0.
3. **Refactor.** Clean up only after green. Re-run after each meaningful
   refactor; exit 0 must hold.

Stay in this loop one AC at a time. Do not write three tests and then three
implementations — the loop's value is the tight feedback cycle.

### When a test you did NOT just write goes red

The Green step above is about the *new* failing test you wrote for this AC —
making it pass is the work. A **pre-existing** test going red is the opposite
signal: it is a guard reporting that your change touched something load-bearing.
The reflex to "make it green" is wrong here, and an agent is very good at
satisfying it — deleting the assertion, loosening the expectation, or marking
the test skipped all turn the light green while removing the protection.

So: **when a test you did not just write fails, do not fix the test — first
suspect that your change broke what the test guards.** Only after you have ruled
that out (the test encodes an intent that has genuinely, deliberately changed)
may you touch the test, and then update its assertion *and its rationale*
together so the next reader sees why. Never weaken, skip, `xfail`, or quarantine
a pre-existing test to reach green. (This mirrors the standing rule for driving
a PR to green — a red guard is work now, not an obstacle to route around.)

## Helper invocations

Two subcommands cover the loop: `tdd.py detect` figures out which runner the
project uses, and `tdd.py run` invokes it.

### Detect the runner

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/tdd-loop/tdd.py" detect [target]
```

- `target` defaults to `.` when omitted.
- Stdout: `pytest`, `vitest`, `jest`, or `node` (one line).
- Exit 2 with stderr `no test runner detected at <target>` if no signal matches.

Signals checked (priority order — first hit wins):

- **pytest** — `pytest.ini` OR `conftest.py` OR `[tool.pytest` in
  `pyproject.toml` OR a `test_*.py` / `*_test.py` file at root or in any
  direct subdirectory.
- **vitest** — `vitest.config.{ts,js,mjs}` OR `vitest` in `package.json`'s
  `dependencies` / `devDependencies`.
- **jest** — `jest.config.{ts,js,json}` OR `jest` in `package.json`'s
  `dependencies` / `devDependencies`.
- **node** — `package.json` `scripts.test` invokes `node --test`, OR a shallow
  JS/TS file imports from `node:test`.

When multiple runners are detected, priority is
**pytest > vitest > jest > node**.

### Run the suite

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/tdd-loop/tdd.py" run [target] [--test-path PATH]
python3 "${CLAUDE_PLUGIN_ROOT}/skills/tdd-loop/tdd.py" run [target] [--test SELECTOR]
```

- Auto-detects the runner via the same logic as `detect`.
- Default commands:
  - pytest → `python3 -m pytest <path>`
  - vitest → `npx vitest run <path>` (note the `run` — keeps watch mode off)
  - jest → `npx jest <path>`
  - node → `node --test` for the full suite; `node --test <path>` with
    `--test-path`
- Output streams through to the caller's terminal.
- Exit code is normalized (0 / 1 / 2) per the table above.

Use `--test-path` when you want to run a focused subset (e.g. a single
test file) while still letting the helper detect which runner to invoke.
Use `--test` when you want one named test: pytest selectors are passed as
node ids (`path::test_name`), vitest/jest selectors map to file plus `-t`,
and node selectors map to file plus `--test-name-pattern` when shaped as
`path::test name`.

## When NOT to use

- **One-off scripts** or **REPL exploration** — TDD overhead isn't worth it
  for code that won't survive the session.
- **Exploratory spikes.** Spikes are research artifacts; they answer "what
  shape should this take?" — tests come *after* the spike has settled the
  shape.
- **Pure-documentation edits** that touch no executable code.
- **Auto-generated code** (codegen output, vendored deps). Test the
  generator, not the generated artifact.

## Sibling helper: `quality.py` (test-quality snapshot)

From ramboz/jig, MIT.

More from ramboz/jig

Signals

Stars
7
Forks
1
Open issues
10
Last commit (this folder)
Aug 31, 2026 (1 month ago)
Last release
Oct 5, 2026 (24 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from ramboz

Cite this page

tdd-loop skill. Agent Mart. https://agentmart.dev/skills/ramboz-tdd-loop (last updated 2026-10-24)