TypeScript monorepo powering the web UIs of Inspect AI and Inspect Scout: the eval log viewer, the Scout viewer, and the shared packages behind them.
Parent repos (inspect_ai, inspect_scout) embed this monorepo as a git
submodule and commit the built output, so Python contributors and end users
never need Node.js. If you're doing frontend work inside a parent repo, read
the submodule guide — it covers setup, keeping the
submodule in sync, and the build-and-bump workflow.
You can also clone and develop this repo standalone. The one caveat: type
generation reads OpenAPI schemas from the Python repos, so types:generate
needs either submodule mode or a TSMONO_PYTHON_ROOT_* environment variable
pointing at a local checkout (see Generated types).
Requires Node.js >= 22.13. pnpm is the only supported package manager, and
corepack installs the pinned version
for you (corepack ships with Node.js 22/24; Node 25+ no longer bundles it —
npm install -g corepack first):
corepack enable # once
pnpm installRun everything from the repo root — Turbo orchestrates across workspaces:
| Command | Description |
|---|---|
pnpm dev |
Start dev servers (inspect on :5173, scout on :5174) |
pnpm build |
Build all workspaces |
pnpm test |
Run unit/integration tests (vitest) |
pnpm e2e |
Run Playwright e2e tests |
pnpm check |
Lint, typecheck, format, manypkg, suppressions |
pnpm lint |
Lint only |
pnpm typecheck |
Typecheck only |
pnpm format |
Format with Prettier |
Scope any of these to one workspace with --filter. Extra args to the root
scripts pass through to turbo run, so Turbo's task graph still applies
(e.g. generate:css runs before lint/typecheck):
pnpm dev --filter=scout
pnpm test --filter=@meridianlabs/log-viewer
pnpm check --filter=scout(Prefer this over pnpm --filter <workspace> <script>, which runs the leaf
script directly and skips Turbo's dependency graph.)
Workspace scripts are single-concern leaf commands; all composition lives in
turbo.json — see scripts.md for the conventions.
| Workspace | Purpose |
|---|---|
apps/inspect |
Inspect log viewer — runs standalone, statically hosted, in VS Code, or embedded via @meridianlabs/log-viewer |
apps/scout |
Inspect Scout viewer — browse scans, scanner results, and transcripts |
packages/filter-expression |
The sample filter's expression language: a filtrex-compatible parser and evaluator that never generates code |
packages/inspect-common |
Shared non-UI code for eval logs: generated API types, boundary normalization, query builder, test fixtures |
packages/inspect-components |
Shared React components for rendering eval logs (chat, transcript, content, usage, …) |
packages/scout-components |
React components shared across Scout surfaces |
packages/react |
Shared React infrastructure: hooks, components, icons, virtualization, react-query helpers |
packages/theme |
Theme layer bridging Bootstrap tokens and VS Code webview variables |
packages/util |
General TypeScript utilities (barrel export — import from the package root) |
packages/zustand-devtools |
Dev panel for inspecting zustand stores |
tooling/* |
Shared eslint, prettier, tsconfig, and vite configs |
API types are generated from OpenAPI schemas exported by the Python repos — no schema copies are committed here:
apps/scoutgenerates from inspect_scout'sopenapi.jsonpackages/inspect-commongenerates from inspect_ai'sinspect-openapi.json
Run pnpm types:generate in the relevant workspace after the Python API
changes. Each workspace's README documents its pipeline; the parent repos' CI
validates that committed schemas and generated types stay in sync.
- Submodule guide — developing inside a parent repo
- Script conventions — Turbo orchestration and workspace scripts
- AGENTS.md — code style, testing, and type-safety conventions (written for coding agents; the rules apply to humans too)
- Design docs live per-app:
- Viewer startup/data-layer domain ownership (inspect)
- Frontend testing: integration tests + MSW (scout)
- React Query patterns (scout)