Ask questions, triage bugs, and explore FE/BE contracts across repos you configure locally.
The backend is built with Effect — typed services, composable layers, and structured errors wire the CLI, investigation modes, and API together.
For domain vocabulary see CONTEXT.md.
| Capability | Description |
|---|---|
| Investigations | Modes (ask, simulate, triage, regress, chat) seed relevant files, run an in-process AI agent, and persist findings, traces, suspects, impacts, and scenarios. |
| Contract index | Static graph of FE HTTP call sites matched to BE routes; mismatch hints are advisory. |
| Dashboard | Browse investigations, contracts, branches, scenarios; chat with native AI SDK streaming (text, reasoning, tool calls). |
| Scoped workspace | Symlinks selected repos under QA_WORKSPACE_ROOT so the agent only sees allowed paths. |
-
Bun 1.3+ — runtime, package manager, and workspace tooling for the whole monorepo (install, scripts, CLI, API)
-
LLM gateway — OpenAI-compatible API reachable from
.env(QA_AISDK_BASE_URL,QA_AISDK_API_KEY,QA_REASONER_MODEL). The model is called directly via the Vercel AI SDK; there is no separate agent server to install. -
Target repos on disk — at minimum a FE and BE checkout (paths in
.env) -
Ollama for semantic codebase search (branch-aware), with the embedding model pulled:
ollama pull nomic-embed-text
On startup,
ensureCodebaseIndexConfigwrites index settings to the global config path used by the bundled semantic-index CLI. Each target repo is indexed on demand into<repo>/.opencode/index/(git-ignored, branch-aware) before investigations; you can reindex and watch progress from the repo picker in the dashboard. Indices are per-machine and rebuild automatically — they are not committed. -
Redis (optional) — set
REDIS_URLorKV_URLfor resumable chat streams across reconnects. Without Redis, streams use an in-process pub/sub fallback suitable for local dev.
From the repository root:
# Install all workspace packages (root, dashboard, @qa-agent/shared)
bun install
# Configure target repos, LLM gateway, and data paths
cp .env.example .env
# Edit .env: QA_TARGET_FE, QA_TARGET_BE, QA_AISDK_API_KEY
# Typecheck (builds shared package, then checks root + dashboard)
bun run typecheck
# Start API (port 4321) + Vite dashboard (port 5173)
bun devOpen http://localhost:5173/chat (or / for the home view).
If ports are in use:
bun run dashboard -- --api-port 4322 --ui-port 5174API only (no Vite UI):
bun run dev:apiProduction-style builds:
bun run build # compile root CLI → dist/
bun run --filter qa-agent-dashboard build # shared + dashboard bundle| Package | Path | Role |
|---|---|---|
qa-agent |
. |
Effect CLI + orchestration, AI agent, Hono API, SQLite |
qa-agent-dashboard |
dashboard/ |
Vite + React UI |
@qa-agent/shared |
packages/shared/ |
Shared domain types and repo-selection helpers |
Common workspace commands (run from repo root):
bun install # install entire workspace
bun run typecheck # shared build + root tsc
bun test # test runner (root)
bun run --filter @qa-agent/shared build
bun run --filter qa-agent-dashboard dev
bun run qa <subcommand> # CLI entry (alias: bun src/cli.ts)After bun run build, the qa binary is available as ./dist/cli.js (or bun run qa during development).
Copy .env.example to .env. Important variables:
| Variable | Purpose |
|---|---|
QA_TARGET_FE / QA_TARGET_BE |
Absolute paths to frontend and backend repos |
QA_REPOS |
Optional multi-repo catalog (id=/path;…) for the dashboard picker |
QA_WORKSPACE_ROOT |
Scoped symlink root (default: common ancestor of catalog paths) |
QA_DATA_DIR |
SQLite and app data (default ./data) |
QA_RUNS_DIR |
Investigation transcripts (default ./runs) |
QA_AISDK_BASE_URL / QA_AISDK_API_KEY |
OpenAI-compatible LLM gateway |
QA_REASONER_MODEL |
Model id sent to the gateway (default deepseek-v4-flash) |
QA_VERIFIER_MODEL |
Optional second model for adversarial finding verification |
QA_HARNESS_TIMEOUT_MS |
Agent and long SSE timeout (default 600000) |
QA_SIM_BUDGET |
Default simulate budget: low | med | high |
QA_SEED_TOPK / QA_SEED_EXPAND_DEPTH |
Codegraph seed breadth |
REDIS_URL / KV_URL |
Optional Redis for resumable chat streams |
Inspect resolved config:
bun run qa infoAll commands are subcommands of qa:
bun run qa <subcommand> ...Global options on investigation modes:
-p, --pin <file>— workspace-relative files to force into the seed (repeatable)-q, --quiet— suppress live tool/text stream on stderr
| Command | Description |
|---|---|
qa ask <question> |
Focused FE↔BE Q&A with file:line citations in findings and traces |
qa simulate <fuzz|replay|repro> <scope> |
Scenario generation: fuzz a feature, replay a saved scenario, or repro a bug. Options: -i/--input, -b/--budget low|med|high, --no-save |
qa triage <report…> |
Rank suspects and hypotheses from bug report text (-f/--file for input file) |
qa regress <spec> |
Change-impact analysis from diff / PR / branch (-r/--repo fe|be) |
Examples:
bun run qa ask "Where does the FE call POST /api/v1/orders?"
bun run qa simulate fuzz "checkout flow" -b high
bun run qa triage "500 on save cart after deploy" -f ./bug.txt
bun run qa regress "origin/main...HEAD" -r fe| Command | Description |
|---|---|
qa index |
Build or refresh FE call-site ↔ BE route graph in SQLite. Flags: --changed, --only <glob>, --dry-run |
qa contracts |
List contract rows (default: mismatches only). --all, --search <q> |
The dashboard can trigger indexing via POST /api/index; chat auto-syncs the index when FE+BE are in scope.
| Command | Description |
|---|---|
qa scenarios list |
List saved scenario specs |
qa scenarios save <title> |
Author a spec (-s/--scope, -k/--kind) |
qa scenarios rm <id> |
Delete a spec (id prefix ok) |
qa scenarios run <id> |
Replay one spec; qa scenarios run --all runs the library |
| Command | Description |
|---|---|
qa list |
Recent investigations (-n/--limit) |
qa show <id> |
Full structured outcome JSON |
qa dashboard |
Start API + Vite dev server |
qa info |
Resolved configuration JSON |
| Script | Command |
|---|---|
bun dev |
bun src/cli.ts dashboard |
bun run dev:api |
Dashboard API only (hot reload) |
bun run dashboard |
Same as dev; pass -- --api-port … --ui-port … |
bun run qa |
bun src/cli.ts (forward subcommands) |
bun run typecheck |
Build @qa-agent/shared, then tsc --noEmit |
bun run build |
Compile CLI to dist/ |
bun test |
bun test src |
bun run db:generate |
Drizzle migration generate |
bun run db:migrate |
Apply migrations |
Started by bun dev / qa dashboard. Default URLs:
Routes:
| Path | Purpose |
|---|---|
/ |
Home |
/chat, /chat/:id |
AI SDK chat (modes: chat, ask, simulate, triage, regress) |
/investigations |
Investigation list |
/i/:id |
Investigation detail (findings, traces, progress) |
/contracts |
Contract graph browser |
/simulate |
Simulation runner UI |
/scenarios |
Saved scenarios |
/branches |
Repo branch context |
Chat uses POST /api/chat with native AI SDK UI streaming — text deltas, reasoning, and tool call/result parts flow directly from streamText into the dashboard. Threads persist in SQLite (chat_threads). Pass strategy: "hive" for parallel multi-angle agent passes merged into one outcome; simulate runs can use phased fanout with live progress in the UI.
qa-agent/
├── src/
│ ├── cli.ts # Effect CLI entry (Bun)
│ ├── ai/ # AI SDK provider, read-only tools, runInvestigation
│ ├── effect/ # Effect services, layers, modes, orchestration
│ ├── server/ # Hono API (chat, index, repos, simulate, …)
│ ├── storage/ # Drizzle schema, migrations, repositories
│ ├── analysis/ # Contract graph builder
│ ├── retrieval/ # Research pack (pre-agent retrieval)
│ ├── seed/ # Codegraph + contract seeding
│ ├── jobs/ # Background snapshot/index refresh jobs
│ ├── prompts/ # Mode-specific system prompts
│ └── repos/ # Catalog, scoped workspace, branch worktrees
├── dashboard/ # Vite + React + Tailwind
├── packages/shared/ # @qa-agent/shared
├── data/ # qa.db (gitignored)
├── runs/ # transcripts per investigation (gitignored)
└── CONTEXT.md
| Location | Contents |
|---|---|
data/qa.db |
Investigations, outcomes, contracts, chat threads, scenario specs |
runs/<investigation-id>/transcript.json |
Raw agent transcript for a run |
flowchart LR
subgraph UI [Dashboard]
Chat[Chat / investigations]
end
subgraph API [Hono API]
ChatAPI["/api/chat"]
IndexAPI["/api/index"]
end
subgraph Core [qa-agent]
Modes[ask / simulate / triage / regress]
Graph[contract graph]
DB[(SQLite)]
Agent[AI SDK agent]
Index[semantic index]
end
subgraph Targets [Your repos]
FE[FE checkout]
BE[BE checkout]
end
Chat --> ChatAPI
ChatAPI --> Modes
Modes --> Agent
Agent --> FE
Agent --> BE
Agent --> Index
Index --> FE
Index --> BE
Modes --> DB
Graph --> DB
IndexAPI --> Graph
- Repo catalog — env-defined paths; dashboard repo selection chooses a subset and branch context (advisory).
- Scoped workspace — symlinks under
QA_WORKSPACE_ROOT; prompts enforce allowed roots. - Retrieval — Codegraph ranks seed files from the question; optional research pack pre-fetches snippets; contract ids can boost seeding.
- Agent — in-process
streamText/generateTextwith read-only tools (read_file,grep,glob,list_dir,codebase_*); structured outcome JSON parsed from the final reply. Hive strategy fans out parallel angle passes and merges; simulate can run a phased fanout with adversarial verifier pass on findings. - Semantic index — Ollama embeddings via
opencode-codebase-index(stdio MCP); branch worktrees keep search branch-correct without mutating checkouts. - Contract index — static extraction from FE services and BE routes; stored for
/contractsand seeding.
Investigation flows are expressed as Effect programs rather than ad-hoc async chains. A small layer graph (src/effect/runtime.ts) wires dependencies:
| Layer / service | Role |
|---|---|
ConfigService |
Env-backed config (@effect/schema validation) |
DbService |
SQLite access via Drizzle |
AiService |
In-process AI SDK provider + models |
BaseLive (config + db) powers read-only commands (list, show, contracts, info). FullLive adds AiService for anything that runs an agent (ask, simulate, triage, regress, chat, index).
Notable Effect usage elsewhere:
@effect/cli— theqasubcommand tree (src/cli.ts)Effect.gen— mode orchestration, chat turns, hive fanout, contract-index sync- Typed errors —
HarnessError,TimeoutError,DbErrortagged at the boundary instead of stringly exceptions - Parallelism — hive strategy fans out angle passes with structured merge; semaphores guard index rebuilds
The dashboard stays plain React; Effect owns the server and CLI side.
- Long chat/simulate runs need aligned timeouts:
QA_HARNESS_TIMEOUT_MS, server limits insrc/server/api.ts, and Vite proxy timeouts indashboard/vite.config.ts. - Contract shape diffs in
qa contractsare unverified hints; route mappings are the reliable signal. README.mdsupersedes older Playwright-centric docs; do not useqa explore/validate/generate— those flows are not implemented.
- CONTEXT.md — glossary (investigation, contract index, scoped workspace, …)
- docs/adr/0001-shared-types-and-storage-split.md — shared package and storage boundaries
- Effect — framework docs for services, layers, and CLI