Skip to content

Architecture

flowchart TD
Init["/qa-catalog:init"] --> RD[route-discoverer<br/>AST / grep]
RD --> PA[page-analyzer ×N<br/>browser MCP<br/>isolated browser]
PA --> TA[test-author ×M<br/>enforced template]
TA --> Catalog[(QA-tests/<br/>catalog.json + tasks/T*.md<br/>+ fingerprints.json)]
Catalog --> Run["/qa-catalog:run-all"]
Run --> Runners[test-runner ×N<br/>parallel, isolated browser each]
Runners --> Results[(results/runs/&lt;runId&gt;/<br/>run.json · report.html · summary.md<br/>&lt;taskId&gt;/result.md + screenshots)]
Results --> History[(history.json · latest.json<br/>by-task/*/latest.json)]
LayerComponentResponsibility
Skill/qa-catalog:initFirst-time bootstrap orchestrator; runs in the main session, fans work to subagents in phases.
Skill/qa-catalog:syncIncremental reconciler — only re-analyses routes whose source fingerprint changed.
Skill/qa-catalog:statusRead-only health + inventory snapshot: browser-agent install state, catalog framework/route/task counts, configured issue trackers, drift vs. source, and the last run’s pass/fail/blocked totals.
Skill/qa-catalog:scanForce full rescan (backs up tasks/ first).
Skill/qa-catalog:runExecute a single task end-to-end.
Skill/qa-catalog:run-allExecute many tasks in parallel, supervisor loop with verification + retry.
Subagent (plugin)qa-catalog:route-discovererWalks the source tree, returns rich JSON per route.
Subagent (plugin)qa-catalog:test-authorConverts each Page Analysis JSON into one or more T*.md task files.
Subagent (plugin)qa-catalog:catalog-reconcilerPure planner — turns a drift report into an add/update/delete plan.
Subagent (project)qa-page-analyzerDrives one route in an isolated browser process. Installed to .claude/agents/ by init Phase 0 because plugin-shipped agents can’t declare inline mcpServers.
Subagent (project)qa-test-runnerExecutes one task end-to-end → result.md + screenshots. Same project-scope reasoning as the analyzer.
Scriptdetect-framework.mjsDetects framework, languages, package manager, build tool, UI libs, validators, etc.
Scriptcatalog-diff.mjsDrift detector. Modes: --json, --silent, --notify, --precommit, --session-start, --post-tool.
Scriptfingerprint.mjsSHA-256 each cataloged source file → .qa-catalog/fingerprints.json.
Scriptverify-result.mjsSchema gate on result.md before the runner’s output enters the run.
Scriptresults-index.mjsMaintains history.json, latest.json, and per-task pointers.
Scriptstatus.mjsRead-only inventory aggregator for /qa-catalog:status: browser-agent install state, route/task counts, integrations, last-run totals. Supports --json.
Scriptrender-report.mjsRenders the self-contained report.html dashboard from the live task-queue.json.
Scriptinstall-precommit.shDrops the Git pre-commit guard during init.
HookSessionStart (matcher: startup)Injects drift context into Claude’s session via hookSpecificOutput.additionalContext.
HookPostToolUse Write|Edit|MultiEditAsync re-check after every file edit. Never blocks the tool loop.
MCPplaywrightBundled Playwright MCP (stdio) for the main session. The project-scope browser agents declare their own inline mcpServers so each parallel spawn gets its own dedicated process.

Plugin-shipped subagents cannot declare inline mcpServers — the field is silently ignored (docs). To give each parallel spawn its own dedicated browser process (true OS-level isolation, no shared cookies/localStorage/auth state), the two browser-driving agents must live at project scope. /qa-catalog:init Phase 0 copies them from the plugin into .claude/agents/.

Because they physically sit in the plugin’s agents/ directory, they would otherwise be auto-registered as plugin agents with mcpServers stripped (no browser, plus duplicate context cost). To prevent that, plugin.json declares an explicit agents allowlist containing only the three true plugin subagents.

Why the supervisor lives in the skill layer

Section titled “Why the supervisor lives in the skill layer”

Subagents cannot spawn other subagents (per Claude docs). The run-all orchestrator therefore lives in the skill (main session), which fans work out to N qa-test-runner subagents in batches, awaits each batch, verifies each result.md, retries failed verifications once, and writes the cross-task summary.md.