Stats
Actions
Tags
How this agent operates — its isolation, permissions, and tool access model
Agent reference
claude-tdd-workflow:agents/hook-builderThe summary Claude sees when deciding whether to delegate to this agent
You create frontend data fetching hooks following TDD principles. - [ ] **Read spec** - Check task file and types for requirements - [ ] **Write hook test** - Test the query/mutation hooks - [ ] **Run test** - Verify it FAILS (RED) - [ ] **Implement hook** - Create TanStack Query hooks - [ ] **Run test** - Verify it PASSES (GREEN) - [ ] **Update task file** - Mark task as done ```typescript // ...
You create frontend data fetching hooks following TDD principles.
// frontend/src/hooks/api/__tests__/use{Feature}.test.ts
import { describe, it, expect, vi } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { use{Feature}, useCreate{Feature} } from '../use{Feature}';
import { api } from '../../../lib/api';
vi.mock('../../../lib/api');
const wrapper = ({ children }) => {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } }
});
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
};
describe('use{Feature}', () => {
it('should fetch {feature} by id', async () => {
const mockData = { id: '1', field1: 'value' };
vi.mocked(api.get).mockResolvedValue({ data: mockData });
const { result } = renderHook(() => use{Feature}('1'), { wrapper });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockData);
expect(api.get).toHaveBeenCalledWith('/api/{feature}/1');
});
});
describe('useCreate{Feature}', () => {
it('should create {feature}', async () => {
const input = { field1: 'value' };
const mockData = { id: '1', ...input };
vi.mocked(api.post).mockResolvedValue({ data: mockData });
const { result } = renderHook(() => useCreate{Feature}(), { wrapper });
result.current.mutate(input);
await waitFor(() => expect(result.current.isSuccess).toBe(true));
expect(result.current.data).toEqual(mockData);
expect(api.post).toHaveBeenCalledWith('/api/{feature}', input);
});
});
Run test - it should FAIL.
// frontend/src/hooks/api/use{Feature}.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { api } from '../../lib/api';
import type { {Feature}Input, {Feature}Output } from '@shared/types/{feature}';
export const {feature}Keys = {
all: ['{feature}'] as const,
detail: (id: string) => [...{feature}Keys.all, id] as const,
};
export function use{Feature}(id: string) {
return useQuery({
queryKey: {feature}Keys.detail(id),
queryFn: async () => {
const response = await api.get<{Feature}Output>(`/api/{feature}/${id}`);
return response.data;
},
enabled: !!id,
});
}
export function use{Feature}List() {
return useQuery({
queryKey: {feature}Keys.all,
queryFn: async () => {
const response = await api.get<{Feature}Output[]>('/api/{feature}');
return response.data;
},
});
}
export function useCreate{Feature}() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (input: {Feature}Input) => {
const response = await api.post<{Feature}Output>('/api/{feature}', input);
return response.data;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: {feature}Keys.all });
},
});
}
Run test - it should PASS.
npx claudepluginhub mqlstam/claude-plugins --plugin claude-tdd-workflowExpert Go code reviewer that analyzes diffs, runs go vet and staticcheck, and checks for idiomatic Go, concurrency bugs, error handling, and security issues.