tailtest¶
You build. We cover.
tailtest watches every file Claude writes and automatically generates tests for it -- no prompting, no configuration, no test runner setup (beyond what you already have).
When tests pass, you get one line of confirmation. When something fails, you get one line with "want me to fix this?" That is the entire interaction.
Choose your platform¶
tailtest works with three AI coding tools. Pick the one you use:
| Platform | Install time | How it works |
|---|---|---|
| Claude Code | 30 seconds | Claude Code plugin -- hooks fire automatically inside the Claude CLI |
| Cursor | 2 minutes | Cursor hooks -- fires after every file save, triggers a test turn |
| Codex | 2 minutes | Codex hooks -- mtime sweep at turn end, blocks to run tests before continuing |
What tailtest does¶
After any Claude-written file lands in your project:
- Tailtest generates scenarios that describe real business behavior -- not function signatures
- It runs them using your existing test runner (pytest, vitest, jest, go test, and more)
- If all pass:
tailtest: 6 scenarios -- all passed. - If something fails: one line surfaced, "want me to fix this?"
Example: Claude builds a billing service. Tailtest generates: "Create invoice at $800 against a $1,000 credit limit -- verify it succeeds. Create invoice at $1,200 -- verify it is rejected." Runs them. If the credit-limit check has a bug, you see it before you move on.
Supported languages¶
| Language | Runner | Test location |
|---|---|---|
| Python | pytest (with pytest-asyncio auto-detected) |
tests/test_{name}.py |
| TypeScript | vitest / jest / bun test / deno test | __tests__/{name}.test.ts (or colocated for Deno) |
| JavaScript | vitest / jest / bun test | __tests__/{name}.test.js |
| Go | go test | colocated {name}_test.go |
| Ruby | rspec / minitest | spec/{name}_spec.rb or test/{name}_test.rb |
| PHP (Laravel) | phpunit | tests/Feature/ or tests/Unit/ |
| Java | Maven / Gradle | src/test/java/{Name}Test.java |
| Kotlin | Maven / Gradle (with Kotlin plugin) | src/test/kotlin/{Name}Test.kt |
| C# / .NET | dotnet test |
*.Tests/{SourceName}Tests.cs (sibling test project by convention) |
| Rust | cargo test | inline #[cfg(test)] module |
Supported frameworks¶
When a framework is detected, tailtest layers framework-keyed baseline scenarios on top of the language baselines. The framework is written to session.json so every test generated during the session knows to include these scenarios.
| Framework | Detection signal | Baseline scenarios always included |
|---|---|---|
| Django (Python) | manage.py present |
Auth required / rejected, model field validation, URL routing |
| FastAPI (Python) | fastapi in pyproject deps |
Valid body / missing field (422) / wrong type (422), app.dependency_overrides |
| Flask (Python) | flask in pyproject deps |
Valid route (200) / unknown (404), blueprint registration, test_client + app context, validation rejection |
| Next.js (JS/TS) | next in package.json deps |
Component renders with required props, missing optional props, loading / loaded / error states |
| NestJS (JS/TS) | @nestjs/core in package.json deps |
DTO validation pass / fail, guard rejects unauthenticated, Test.createTestingModule provider override, controller or microservice harness |
| Nuxt (JS/TS) | nuxt in deps or nuxt.config.{ts,js} |
mountSuspended render, required props, async setup |
| Rails (Ruby) | rails in Gemfile |
Valid record saves, invalid record fails validation, unauthorized request rejected |
| Laravel (PHP) | laravel/framework in composer.json + artisan |
Valid input, validation failure (422), unauthenticated rejection |
| Spring Boot (Java) | spring-boot in pom.xml or build.gradle |
Valid request (200), missing field (400), unauthenticated (401), @WebMvcTest slice, @MockBean service override |
Precedence when multiple signals are present: manage.py wins for Django. For other Python frameworks, when both flask and fastapi are declared (rare, e.g. mid-migration), tailtest inspects entry-point files (app.py, main.py, wsgi.py, asgi.py) for Flask(__name__) or FastAPI() to pick the right one. For Node, @nestjs/core is checked before next. Monorepos with different frameworks per workspace are detected per-package.
Initial coverage scan¶
The first time tailtest starts on an existing project, it scans your codebase and queues the most important files for an initial coverage pass. Files are ranked by git activity, path (services and models score higher), and size. The top 7 are queued by default.
Before running them, you see: tailtest: initial coverage scan -- first session detected. 7 file(s) queued for coverage.
This runs once. A sentinel file prevents it from re-firing on restart. You can control how many files are scanned with the ramp_up_limit config option.
Escape hatch¶
Add a .tailtest-ignore file at your project root (gitignore syntax) to silence specific paths:
Session state¶
Tailtest writes .tailtest/session.json during each session. Add .tailtest/ to your .gitignore to keep it out of version control.