Skip to content
MCP Servers
Skill

/bug-fix-tdd

Reproduce and fix bugs using TDD. Use when analyzing a bug report, writing a regression test, or applying a minimal fix. Covers test placement, mock patterns, and the red-green-refactor workflow for automated bug fixing.

From plugin
toolhive-studio
1639 skills
Install
$ npx -y skills add stacklok/toolhive-studio --skill bug-fix-tdd --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/bug-fix-tdd

Context preview

The summary Claude sees to decide when to auto-load this skill.

Reproduce and fix bugs using TDD. Use when analyzing a bug report, writing a regression test, or applying a minimal fix. Covers test placement, mock patterns, and the red-green-refactor workflow for automated bug fixing.

SKILL.md

bug-fix-tdd.SKILL.md
name: bug-fix-tdd
description: Reproduce and fix bugs using TDD. Use when analyzing a bug report, writing a regression test, or applying a minimal fix. Covers test placement, mock patterns, and the red-green-refactor workflow for automated bug fixing.

Bug Fix TDD

Reproduce bugs with a failing test, then apply the minimum fix. This skill is used by the automated bug-fix agent in CI but can also be invoked manually.

TDD Workflow

Phase 1 — Analysis & Failing Test (Red)

1. **Parse the bug report**: extract description, steps to reproduce, expected vs actual behavior 2. **Find relevant code**: use Grep/Glob to locate the component, hook, or route mentioned in the bug 3. **Write a unit test** that reproduces the bug — the test MUST FAIL 4. **Run the test**: `pnpm run test:nonInteractive -- <test-file-path>` 5. **Verify failure reason**: the test must fail because of the bug, not because of import errors or unrelated issues 6. **Retry if needed**: if the test passes (bug not reproduced), try a different approach (max 3 attempts) 7. **Write `bug-analysis.md`** with findings (see format below)

**Constraints**: Do NOT modify source files in Phase 1. Only create/edit test files and `bug-analysis.md`.

Phase 2 — Fix (Green)

1. **Read the failing test** and `bug-analysis.md` 2. **Apply the MINIMUM fix** to make the test pass — do not over-engineer 3. **Run the single test**: `pnpm run test:nonInteractive -- <test-file-path>` 4. **Run the full suite**: `pnpm run test:nonInteractive` 5. **Run static checks**: `pnpm run lint` and `pnpm run type-check` 6. **Retry if needed**: if any check fails, adjust the fix (max 5 attempts) 7. **Write `pr-body.md` and `fix-title.txt`**

**Constraints**: Do NOT run git, gh, or modify .env files.

Phase 2b — Direct Fix (Fallback)

If Phase 1 cannot reproduce the bug in a test (test passes after 3 attempts), Phase 2b runs instead of Phase 2.

1. **Read `bug-analysis.md`** and `issue-body.md` for context 2. **Apply the MINIMUM fix** based on code analysis alone 3. **If you CAN write a regression test**, do so — but it is not required 4. **Run the full suite**: `pnpm run test:nonInteractive` 5. **Run static checks**: `pnpm run lint` and `pnpm run type-check` 6. **Retry if needed**: if any check fails, adjust the fix (max 5 attempts) 7. **Write `pr-body.md` and `fix-title.txt`** — note in the PR body that no regression test was possible

**Constraints**: Same as Phase 2. Do NOT run git, gh, or modify .env files.

Test Placement Rules

  • Tests go in `__tests__/` directories colocated with the source file
  • If a test file already exists for the component, **add a new `describe('Bug #N', ...)` block** instead of creating a new file
  • Naming: `<component-name>.test.tsx` or `<hook-name>.test.ts`
  • Example: source at `renderer/src/features/skills/components/card-skill.tsx` → test at `renderer/src/features/skills/components/__tests__/card-skill.test.tsx`

Test Patterns

Component test (simplest)

import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: false } },
})

render(
  <QueryClientProvider client={queryClient}>
    <MyComponent prop="value" />
  </QueryClientProvider>
)

await userEvent.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
  expect(screen.getByText('Saved')).toBeVisible()
})

Route-level component test

import { createTestRouter } from '@/common/test/create-test-router'
import { renderRoute } from '@/common/test/render-route'

const router = createTestRouter(MyPage, '/my-page')
renderRoute(router, { permissions: { canManageClients: true } })

await waitFor(() => {
  expect(screen.getByRole('heading', { name: /my page/i })).toBeVisible()
})

Hook test

import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: false } },
})
const Wrapper = ({ children }) =>
  <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>

const { result } = renderHook(() => useMyHook(), { wrapper: Wrapper })

await waitFor(() => expect(result.current.isLoading).toBe(false))
expect(result.current.data).toEqual({ ... })

API mock override (return different data)

import { mockedGetApiV1BetaWorkloads } from '@mocks/fixtures/workloads/get'

mockedGetApiV1BetaWorkloads.override((data) => ({
  ...data,
  workloads: [], // Force empty state
}))

API mock error response

import { HttpResponse } from 'msw'

mockedGetApiV1BetaWorkloads.overrideHandler(() =>
  HttpResponse.json({ error: 'Server error' }, { status: 500 })
)

Request recording (for mutations)

import { recordRequests } from '@/common/mocks/node'

const rec = recordRequests()
// ... trigger action ...
const request = rec.recordedRequests.find(
  (r) => r.method === 'POST' && r.pathname === '/api/v1beta/workloads'
)
expect(request?.payload).toMatchObject({ name: 'my-server' })

bug-analysis.md Format

## Bug Summary

<1-2 sentences describing the bug>

## Root Cause

<Technical explanation of why the bug occurs>

## Relevant Files

- `path/to/source.tsx` — <what it does>
- `path/to/related.ts` — <why it's relevant>

Test file: path/to/\_\_tests\_\_/component.test.tsx

## Proposed Fix

<Description of the minimum change needed>

## Files to Modify

- `path/to/file.tsx` — <what to change>

**Important**: The `Test file:` line must be on its own line starting with exactly `Test file: ` followed by the path. This is parsed by the CI workflow.

pr-body.md Format

## Summary

Fixes #<issue-number>.

- <1-2 bullet points describing the fix>
Read more
Ships withtoolhive-studio

Run any Model Context Protocol (MCP) server — securely, instantly, anywhere. ToolHive is the easiest way to discover, deploy, and manage MCP servers. Launch any MCP server in a locked-down container with just a few clicks.

Get the whole plugin
Stats
163
Stars
22
Forks
Active
Maintenance
TypeScript
Language
Apache-2.0
License
6h ago
Last commit
1y ago
Created

Repo: stacklok/toolhive-studio