Ensure accessibility in UI components including semantic HTML, ARIA attributes, keyboard navigation, and WCAG 2.2 AA compliance.
日本語の概要は準備中です。原文の説明を表示しています。
Canon TDD for humans and AI agents. Use for production code changes by writing tests first, proving RED, implementing minimal GREEN, and refactoring safely. 2026 edition adds TDP, flakiness gate, ralph-loop integration, memory-search in Step 0, PBT as Step 5.5, mutation testing gate in Step 4, and CJS LSP warning.
インストールする前に、エージェントに与えられる指示の中身を確認できます。
This skill implements Canon TDD with AI-specific guardrails:
Use for:
Ask human approval before bypassing only for:
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
If code was written first, discard and restart from RED.
Before building the backlog, query memory for past failure signatures and reusable test templates:
Skill({ skill: 'memory-search' }); // query: "<feature-name> test failure signatures"
Read .claude/context/memory/learnings.md for recurring anti-patterns relevant to this task.
Then:
Flakiness Gate (mandatory for async, hook, or nondeterministic tests):
For tests that involve async I/O, stop hooks, timers, or file system operations, a single pass is insufficient. Require 3 consecutive passes before declaring GREEN:
# Run 3 times — all 3 must pass
node --test tests/hooks/routing-guard.test.cjs && \
node --test tests/hooks/routing-guard.test.cjs && \
node --test tests/hooks/routing-guard.test.cjs
A test that passes once and fails on the second run is RED, not GREEN. Do not advance to Step 5 until 3 consecutive passes are confirmed.
Mutation Testing Gate (security-critical code only):
For security hooks, routing validators, auth logic, and any code path that controls access or trust decisions, run Stryker mutation testing after achieving GREEN to verify that tests genuinely catch faults and are not vacuously passing.
# Run Stryker mutation testing (threshold: 85%)
npx stryker run
# Require mutationScore >= 85 in stryker.config.json
For fast-check-based property tests on security hooks, the fail-closed property is the mutation-equivalent gate:
// fast-check fail-closed property — must hold for any input
fc.assert(
fc.property(fc.anything(), input => {
const result = securityHook(input);
// Hook must NEVER return allow=true for malformed/unexpected input
expect(result.allow).not.toBe(true);
})
);
Skip this gate for non-security application code (Step 4 → Step 5 directly).
After refactor (or after Step 4 for security-critical code), consider supplementing example-based tests with property-based tests. PBT achieves 23.1–37.3% pass@1 improvement over example-based TDD alone for LLM code generation (arXiv:2506.18315) by breaking the self-deception cycle.
When to invoke:
Invocation:
Skill({ skill: 'property-based-testing' });
Key property patterns to identify:
| Pattern | Example |
|---|---|
| Round-trip | decode(encode(x)) === x |
| Idempotence | normalize(normalize(x)) === normalize(x) |
| Invariant | sort(arr).length === arr.length |
| Fail-closed (security) | securityHook(anyInput).allow !== true (unless explicitly whitelisted) |
PBT is a supplement to Canon TDD, not a replacement. Canon RED/GREEN/REFACTOR completes first; PBT runs after GREEN is confirmed.
Use lightweight memory only to reduce repeated setup and triage:
Reference: references/tdd-memory-profile.md
Hard rules:
TDP is the dominant 2026 pattern for multi-agent TDD: inject the verbatim failing test output into the developer agent spawn prompt. This eliminates interpretation errors — the developer sees exactly what the test runner sees.
Instead of describing the failure in prose, capture stdout/stderr and inject it directly:
// Step 1: Run test and capture raw output
const { execSync } = require('child_process');
let testOutput = '';
try {
execSync('node --test tests/hooks/routing-guard.test.cjs', { encoding: 'utf-8' });
} catch (e) {
testOutput = e.stdout + e.stderr; // Verbatim failure output
}
// Step 2: Inject verbatim into developer spawn prompt (no paraphrasing)
Task({
task_id: 'task-impl',
subagent_type: 'developer',
prompt: `## FAILING TEST (verbatim — do NOT modify the test file)\n\`\`\`\n${testOutput}\n\`\`\`\nImplement ONLY what is needed to make this pass.`,
});
| Step | Agent | Action |
|---|---|---|
| 1 | qa | Write failing test, commit test-only, capture raw output |
| 2 | Router | Extract test output, build TDP spawn prompt |
| 3 | developer | Implement to GREEN using verbatim test output as spec |
| 4 | reflection-agent | Verify no test assertions were modified (git diff check) |
Source: Simon Willison (2026) — "Red/Green TDD for agents: failing test output IS the specification"; TDFlow arXiv:2510.23761.
For repository-scale TDD where sessions may be interrupted, wire ralph-loop (Mode 2 — router-managed) to maintain the TDD scenario backlog across interruptions:
Maintain a TDD-specific state file at .claude/context/runtime/tdd-state.json:
{
"scenarios": [
{
"id": "sc-001",
"description": "routing-guard blocks Write on creator paths",
"status": "pending"
},
{ "id": "sc-002", "description": "spawn-token-guard warns at 80K tokens", "status": "green" }
],
"completedScenarios": [
{
"id": "sc-002",
"evidenceCommand": "node --test tests/hooks/spawn-token-guard.test.cjs",
"passedAt": "2026-03-12T10:00:00Z"
}
],
"currentScenario": "sc-001",
"evidenceLog": [
{
"scenarioId": "sc-001",
"phase": "red",
"output": "AssertionError: expected exit code 2, got 0",
"timestamp": "..."
}
]
}
At the start of each iteration, read the TDD state file:
// Step 0 — before building/refreshing backlog
const state = JSON.parse(
fs.readFileSync('.claude/context/runtime/tdd-state.json', 'utf-8') || '{}'
);
const completedIds = (state.completedScenarios || []).map(s => s.id);
const remaining = (state.scenarios || []).filter(s => !completedIds.includes(s.id));
// Pick next scenario from remaining — never re-run completed ones
qa agent with { task_id, subagent_type: 'qa', prompt: TDP_PROMPT + verbatim state }qa writes test → runs → captures output → updates tdd-state.json (phase: red)developer with TDP prompt (verbatim test output injected)developer implements → updates tdd-state.json (phase: green)remaining.length === 0 → emit RALPH_AUDIT_COMPLETE_NO_FINDINGSAnti-pattern: Never re-run scenarios already marked green in state — this wastes iterations and may corrupt evidence logs.
Use the project's actual commands. Typical sequence:
# 1) targeted test
pnpm test <target>
# 2) impacted suite
pnpm test
# 3) lint
pnpm lint
# 4) format check
pnpm format:check
If the repo uses different scripts, replace these with local equivalents and report exactly what ran.
references/research-requirements.mdreferences/tdd-memory-profile.mdtesting-anti-patterns.mdrules/tdd.mdtemplates/implementation-template.mdThis skill is aligned with:
Before starting:
Read .claude/context/memory/learnings.md
After completing:
.claude/context/memory/learnings.md.claude/context/memory/issues.md.claude/context/memory/decisions.mdAssume interruption: if it is not in memory, it did not happen.
Hooks use stdin/stdout JSON protocol:
const proc = require('child_process').spawn('node', ['.claude/hooks/routing/routing-guard.cjs'], {
shell: false,
});
proc.stdin.write(JSON.stringify({ tool_name: 'Write', tool_input: {} }));
proc.stdin.end();
// Exit 0=allow, 2=block
Mock MemoryRecord. Test confidence gate (threshold 0.7). Use atomic writes.
Use fast-check (and @fast-check/vitest for vitest integration) for any function with invariants — not just routing. fast-check 3.x (2025) adds improved unicode, date, and bigint arbitraries.
Routing invariant (existing):
import fc from 'fast-check';
fc.assert(
fc.property(fc.string(), intent => {
return typeof routeIntent(intent) === 'string';
})
);
Memory serialization roundtrip (new):
// Property: serialize(deserialize(x)) === x for all JSON-serializable values
fc.assert(
fc.property(fc.jsonValue(), value => {
const serialized = serializeMemoryRecord(value);
const deserialized = deserializeMemoryRecord(serialized);
return JSON.stringify(deserialized) === JSON.stringify(value);
})
);
Hook validation invariant (new):
// Property: for any tool input, isValidInput(x) === !isBlocked(x)
// (validation and blocking must be inverses)
fc.assert(
fc.property(fc.record({ tool_name: fc.string(), tool_input: fc.object() }), input => {
const valid = isValidInput(input);
const blocked = wouldBlock(input);
return valid !== blocked || (!valid && blocked); // blocked implies invalid
})
);
Path normalization idempotency (new):
// Property: normalize(normalize(path)) === normalize(path) (idempotent)
fc.assert(
fc.property(fc.string(), rawPath => {
const once = normalizePath(rawPath);
const twice = normalizePath(once);
return once === twice;
})
);
Schema validation stability (new):
// Property: validate(schema, x) never throws uncaught exception for any input
fc.assert(
fc.property(fc.anything(), input => {
try {
validateSchema(schema, input);
return true;
} catch (e) {
return e instanceof ValidationError;
} // Only ValidationError allowed
})
);
Validate TaskUpdate metadata schemas (processedReflectionIds: string[]).
Based on TDFlow (arXiv:2510.23761, 94.3% SWE-Bench Verified), monolithic TDD agents score 60–70%. Split into specialized sub-agents:
| Role | Agent | Responsibility |
|---|---|---|
| Test Author | qa | Write failing test, commit test-only |
| Implementer | developer | Implement to green — MUST NOT modify tests |
| Verifier | reflection-agent | Detect test-hacking, verify RED→GREEN evidence |
Pattern:
Test-hacking detection: reflection-agent checks git diff HEAD~1 HEAD -- '*.test.*' — any assertion changes after implementation commit = REJECT.
When to use: repository-scale TDD, complex features with multiple behaviors, any task where a single agent might rationalize test changes.
TDAID extends classic TDD with explicit Planning and Validation gates:
| Phase | TDAID Label | Agent-Studio Owner | Description |
|---|---|---|---|
| 0 | Plan | planner | Thinking-model generates structured TDD plan with explicit test checkpoints before any code is written |
| 1 | Red | qa | Write failing test expressing desired behavior; human verifies failure is expected |
| 2 | Green | developer | Minimal implementation to pass test; MUST NOT modify test assertions |
| 3 | Refactor | developer | Improve code quality with all tests green |
| 4 | Validate | reflection-agent + verification-before-completion skill | Detect specification gaming; confirm implementation matches plan; human gate |
Key TDAID anti-patterns to detect in Validate phase:
Research basis: TDAID (awesome-testing.com, 2025), TDAD agent-to-agent variant (arXiv:2603.08806, 2026), TDFlow (arXiv:2510.23761, 2025)
Before writing a failing test, verify the API contract exists to prevent "fails due to wrong API" rather than "fails due to missing behavior":
# Step 1: Find the target function's file + line
pnpm search:code "functionName"
# Step 2: Verify signature with LSP hover
lsp_hover({ filePath: "/abs/path/to/file.ts", line: 42, character: 10 })
# Returns: function signature, parameter types, return type
# Step 3: Write test using VERIFIED signature
# Now RED is guaranteed to fail due to missing behavior, not API mismatch
Rule: If lsp_hover returns empty (CJS file or LSP not active) → fall back to ripgrep rg -n "functionName" --type ts to read the actual signature.
When NOT needed: trivially new functions that don't exist yet (LSP has nothing to return).
Hook contracts define the stdin/stdout JSON protocol. Test at the boundary:
// Hook contract test pattern
const proc = spawn('node', ['.claude/hooks/routing/routing-guard.cjs'], { shell: false });
const input = JSON.stringify({
tool_name: 'Edit',
tool_input: { file_path: '.claude/agents/core/developer.md' },
});
proc.stdin.write(input);
proc.stdin.end();
// Assert: exit code 2 (block) for protected paths
// Assert: stdout JSON contains { allow: false, message: /Gate 4/ }
TaskUpdate metadata contract:
// Validate processedReflectionIds schema
const schema = {
type: 'object',
required: ['processedReflectionIds'],
properties: { processedReflectionIds: { type: 'array', items: { type: 'string' } } },
additionalProperties: false,
};
Agent-Studio hook contracts to test:
routing-guard.cjs: blocks Task without task_id (exit 2)unified-creator-guard.cjs: blocks Write to .claude/skills/**/SKILL.md (exit 2)spawn-token-guard.cjs: warns at 80K tokens (exit 0 + message)Agent Studio uses node --test (built-in Node.js test runner) as the default for all .cjs CommonJS files (hooks, lib, scripts). Vitest 4 is the recommended runner for ESM/TypeScript files.
| Runner | Use When | Command |
|---|---|---|
node --test | .cjs hooks, lib, CommonJS scripts — current Agent Studio standard | node --test tests/**/*.test.cjs |
vitest | .ts, .mts, ESM .js files — use when migrating to TypeScript | pnpm vitest run |
Why node --test for .cjs: Vitest requires Vite configuration and ESM-compatible modules. Agent Studio hooks use require() and CommonJS — node --test works without transpilation.
Why Vitest 4 for .ts/ESM: Boot time drops from ~8s (Jest) to ~1.2s (Vitest). First-class TypeScript + ESM support, Browser Mode (stable v4), and jest-compatible describe/it/expect API (migration = config change only).
Anti-pattern: Do NOT use Jest for new files. Vitest is the 2025-2026 standard for ESM/TypeScript.
# Current Agent Studio pattern (CJS hooks and lib)
node --test tests/lib/routing/routing-table.test.cjs
# Future ESM/TypeScript pattern
pnpm vitest run tests/lib/routing/routing-table.test.ts
LLM/agent outputs are non-deterministic — binary pass/fail assertions are insufficient. Use score-based evaluation and tool-call sequence validation instead.
// Agent output evaluation — score dimensions 0.0-1.0
function evaluateAgentOutput(output, expectations) {
const scores = {
relevance: scoreRelevance(output, expectations.topic), // 0.0-1.0
safety: scoreSafety(output), // 0.0-1.0
faithfulness: scoreFaithfulness(output, expectations.facts), // 0.0-1.0
format: scoreFormat(output, expectations.schema), // 0.0-1.0
};
const overall = Object.values(scores).reduce((a, b) => a + b) / Object.keys(scores).length;
return { scores, overall, pass: overall >= 0.75 };
}
// Test: agent output meets quality threshold
test('researcher agent output is relevant and safe', () => {
const result = evaluateAgentOutput(agentOutput, { topic: 'TDD patterns', facts: knownFacts });
expect(result.scores.safety).toBeGreaterThanOrEqual(0.9); // Hard floor for safety
expect(result.overall).toBeGreaterThanOrEqual(0.75); // 75% overall threshold
});
For agent tests, validate the sequence and count of tool calls, not just the final output:
// Spy on tool calls and assert ordering
const toolCallLog = [];
const mockTaskUpdate = jest.fn(args => {
toolCallLog.push({ tool: 'TaskUpdate', args });
});
const mockBash = jest.fn(args => {
toolCallLog.push({ tool: 'Bash', args });
});
// Run agent under test with mocked tools
await runAgent({ TaskUpdate: mockTaskUpdate, Bash: mockBash });
// Assert: TaskUpdate(in_progress) called BEFORE TaskUpdate(completed)
const inProgressIdx = toolCallLog.findIndex(
c => c.tool === 'TaskUpdate' && c.args.status === 'in_progress'
);
const completedIdx = toolCallLog.findIndex(
c => c.tool === 'TaskUpdate' && c.args.status === 'completed'
);
expect(inProgressIdx).toBeLessThan(completedIdx); // Ordering enforced
expect(inProgressIdx).toBeGreaterThanOrEqual(0); // Must have been called
expect(completedIdx).toBeGreaterThanOrEqual(0); // Must have been called
Rule: Never test the text content of LLM-generated prose. Test structure, schema validity, tool-call sequences, and score thresholds.
Reference: Simon Willison (2025) — "Red/Green TDD for agents: write assertions on tool-call sequences and structured outputs."
Use MSW (Mock Service Worker) v2 to test skills and agents that make external HTTP calls. MSW intercepts at the network level — no monkey-patching of fetch, no code changes in production.
pnpm add -D msw@2
import { setupServer } from 'msw/node';
import { http, HttpResponse } from 'msw';
// Define handlers — these describe the expected API contract
const handlers = [
http.get('https://api.example.com/search', ({ request }) => {
const url = new URL(request.url);
return HttpResponse.json({
results: [{ id: 1, title: `Result for: ${url.searchParams.get('q')}` }],
});
}),
];
const server = setupServer(...handlers);
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
// Test: researcher skill makes HTTP call and processes response
test('researcher skill fetches and parses search results', async () => {
const results = await researcherSkill.search('TDD patterns 2026');
expect(results).toHaveLength(1);
expect(results[0].title).toContain('TDD patterns');
});
test('researcher skill handles 503 gracefully', async () => {
server.use(
http.get('https://api.example.com/search', () => HttpResponse.json({}, { status: 503 }))
);
const results = await researcherSkill.search('TDD patterns');
expect(results).toEqual([]); // Graceful empty fallback
});
Key benefits over manual mocking:
onUnhandledRequest: 'error' catches unintentional external calls during testsAgent-Studio targets for MSW boundary tests:
researcher skill → WebSearch/WebFetch HTTP callsgithub-ops skill → GitHub API callsmcp__Exa__web_search_exa or WebFetchMutation testing validates test QUALITY, not just coverage. Run after achieving 100% line coverage:
# Install (once per project) — use vitest-runner for ESM/TypeScript
pnpm add -D @stryker-mutator/core @stryker-mutator/vitest-runner vitest
// stryker.config.mjs — working configuration for Vitest projects
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
export default {
testRunner: 'vitest',
vitest: {
configFile: 'vitest.config.ts', // optional: path to your vitest config
related: true, // default: run only tests related to mutated file
},
thresholds: { high: 80, low: 60, break: 50 },
reporters: ['html', 'progress'],
};
# Run mutation tests (use incremental to speed up local loops)
pnpm stryker run --incremental
# Target threshold: >80% mutation score
# Score = (killed mutations / total mutations) × 100
Vitest runner limitations (StrykerJS 7.x):
perTest coverage analysis (ignores coverageAnalysis config).cjs files using node --test, use @stryker-mutator/jest-runner as fallbackpnpm add -D @stryker-mutator/core @stryker-mutator/jest-runner
Interpret results:
When to run: after completing a TDD cycle for security-critical code (hooks, validators, routing logic). Not required for all code — prioritize by risk.
Agent-Studio priority targets for mutation testing:
.claude/hooks/routing/routing-guard.cjs.claude/hooks/safety/unified-creator-guard.cjs.claude/lib/routing/routing-table.cjsBefore committing, agents MUST identify which test files cover the changed source files. Use compiler-assisted reference discovery or targeted grep:
# Find tests that import the changed file
grep -r "import.*changedFile\|require.*changedFile" tests/
# Or use LSP to find all references
lsp_findReferences({ filePath: "/path/to/changed/file.ts", line: 1, character: 1 })
Build a dependency map and run ONLY those tests first (70% faster regression detection per arXiv:2603.17973):
# 1. Run targeted tests (impacted tests only)
pnpm test tests/hooks/routing-guard.test.cjs
# 2. Verify no regressions in targeted scope
# 3. Only then run full suite
pnpm test
Rationale: Full test suites can exceed 5 minutes on large repos. Targeted testing catches regressions in 15-30 seconds, freeing context for next scenarios in a long TDD loop.
In the Validate phase, verify the implementation hasn't gamed test assertions:
Checklist:
Run mutation testing if available:
# Test suite strength validation — mutations should be caught
pnpm stryker run
# If mutation score < 80%, tests are too weak:
# - Add negative tests
# - Add boundary condition tests
# - Verify assertions are on behavior, not mocks
Spec-gaming examples to catch:
return 42 to pass test expecting 42 → mutation testing catches thisAgent-Studio targets: After completing security-critical hook or routing changes, run mutation testing before marking task complete.
まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Ensure accessibility in UI components including semantic HTML, ARIA attributes, keyboard navigation, and WCAG 2.2 AA compliance.
日本語の概要は準備中です。原文の説明を表示しています。
Use when you want to improve response quality through meta-cognitive reasoning. Applies 15+ reasoning methods to reconsider and refine initial outputs.
日本語の概要は準備中です。原文の説明を表示しています。
N-round opposing-stance debates for trade-off analysis. Assigns pro/con roles to agents, runs structured debate rounds with quality scoring, and produces a moderator synthesis with confidence-rated recommendation. Generalizable to architecture, technology, security, and design decisions.
日本語の概要は準備中です。原文の説明を表示しています。
Force adversarial code review stance that eliminates confirmation bias — reviewer must find issues or re-analyze
日本語の概要は準備中です。原文の説明を表示しています。
Creates specialized AI agents on-demand when no existing agent matches a request. Use when the Router cannot find a suitable agent for a task. Enables self-evolution by generating persistent agents.
日本語の概要は準備中です。原文の説明を表示しています。
LLM-as-judge evaluation framework with 5-dimension rubric (accuracy, groundedness, coherence, completeness, helpfulness) for scoring AI-generated content quality with weighted composite scores and evidence citations
日本語の概要は準備中です。原文の説明を表示しています。