Test-driven development loop — red-green-refactor with interface confirmation before writing any implementation
From claude-toolkitnpx claudepluginhub johwer/marketplace --plugin claude-toolkitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Forces the red-green-refactor discipline. The most consistent way to improve agent output quality: write the test first, let it fail, then write the minimum code to pass it, then refactor.
Never write implementation before at least one failing test exists.
$ARGUMENTS
If arguments are provided, treat them as the feature or function to implement. Otherwise ask what to build.
Detect the stack from file context or arguments:
.ts, .tsx in apps/web/): Vitest + React Testing Library.cs in services/): xUnit + NSubstitute + FluentAssertionsBefore writing any tests, confirm the contract:
Write out the interface as a type signature or method stub (no implementation yet). Ask the user to confirm it before proceeding.
Frontend example:
// Interface to confirm:
function calculateServiceADays(
startDate: Date,
endDate: Date,
excludeWeekends: boolean
): number
Backend example:
// Interface to confirm:
Task<ApiResponse<ServiceASummary>> GetServiceASummaryAsync(
int employeeId,
DateOnly from,
DateOnly to,
CancellationToken ct = default);
Before writing any test code, list the cases to cover:
| # | Scenario | Input | Expected output |
|---|---|---|---|
| 1 | Happy path | ... | ... |
| 2 | Empty/null input | ... | error or default |
| 3 | Edge case | ... | ... |
| 4 | Error/failure case | ... | ... |
Confirm with user before writing. Add or remove cases based on their feedback.
Write the first test only. Run it. Verify it fails with a meaningful error (not a compilation error — that means the interface isn't set up yet).
Frontend:
cd apps/web && npx vitest run --reporter=verbose <test-file-path>
Backend:
cd services/<Service>/<Service>.Test && dotnet test --filter "<TestName>"
The test must fail for the right reason — not "file not found" or "method doesn't exist", but an assertion failure.
Write the smallest possible implementation that makes the failing test pass. Do not add logic for cases not yet tested. Resist the urge to handle all edge cases up front.
Run the test again. It must pass before moving on.
With the test green, improve the implementation without changing behavior:
Run tests again after refactoring. Still green? Move on.
Return to Step 3 with the next test case from the list. Continue until all cases are covered.
Run the full test file (not just the new tests) to catch regressions:
Frontend:
cd apps/web && npx vitest run --reporter=verbose <test-file-path>
Backend:
cd services/<Service>/<Service>.Test && dotnet test
Also run type-check for frontend:
cd apps/web && npm run type-check
import { describe, expect, it } from "vitest"
// REQUIRED — CI tsc --noEmit fails without this (TS2593/TS2304)
describe("functionName", () => {
it("should <expected behavior>", () => {
// arrange
// act
// assert
})
})
File location: co-located with the source file as <filename>.test.ts.
public class ServiceNameTests
{
private readonly IServiceNameRepository _repository = Substitute.For<IServiceNameRepository>();
private readonly ServiceName _sut;
public ServiceNameTests()
{
_sut = new ServiceName(_repository);
}
[Fact]
public async Task MethodName_WhenCondition_ShouldExpectedBehavior()
{
// Arrange
// Act
var result = await _sut.MethodNameAsync(...);
// Assert
result.Should().Be(...);
}
}