Architecture
How Spectrace is put together — the monorepo, the Next.js app, Postgres with Drizzle and pgvector, Trigger.dev jobs, the AI provider seam, and the MCP server.
This page shows you the components that make up Spectrace and how data moves between them, so you can judge where your data lives and which parts you can run yourself.
Overview
Spectrace is one Next.js application backed by one Postgres database, with background work offloaded to Trigger.dev and AI calls routed through a single provider seam. Two clients sit outside the web app: the MCP (Model Context Protocol) server, which lets AI coding agents act on your requirements, and the VS Code extension.
Monorepo layout
Spectrace is a Turborepo with pnpm workspaces. Each package is described below with its role.
| Package | Path | Role |
|---|---|---|
@spectrace/web | apps/web | The product: Next.js 15 App Router, React 19, TypeScript, Tailwind CSS 4. Server Actions in src/lib/actions, Route Handlers in src/app/api, background jobs in src/trigger/jobs. |
spectrace-vscode | apps/vscode | The VS Code extension. Talks to the web app over /api/v1/*. |
@spectrace/db | packages/db | Drizzle schema and client. All tables live in src/schema/*; migrations in drizzle/. |
@spectrace/ai | packages/ai | AI agents and prompts, the provider seam, embeddings, and the safety layer (trust boundary, secret scrubbing, provenance). |
@spectrace/mcp-server | packages/mcp-server | The Spectrace MCP server: tools, templated resources and prompts for AI assistants. Ships a spectrace-mcp CLI and a Dockerfile. |
@spectrace/mcp | packages/mcp | Shared integration clients (GitHub, Linear). |
@spectrace/ui | packages/ui | Shared React UI components. |
Web application
The web app is a Next.js 15 App Router application. Pages render on the server; mutations run as Server Actions ("use server" functions in apps/web/src/lib/actions/*); Route Handlers under apps/web/src/app/api expose the extension API (/api/v1/*), the hosted MCP endpoint (/api/mcp), inbound webhook receivers (/api/webhooks/*), and OAuth callbacks.
Authentication is Supabase Auth; middleware refreshes the session cookie on each request. Project authorisation resolves through getProjectAccess(), which looks up the caller's role against the project's own organization. See Roles and permissions.
Database
Data lives in one PostgreSQL database, accessed through Drizzle ORM. The pgvector extension stores 1536-dimension embeddings for requirements and repository code chunks, which power semantic search and the related-code context given to the PR verifier. Which requirement a PR is verified against is resolved from explicit references and file traceability links, not from embeddings. In production the connection requires SSL.
Row-level-security policies exist in the migrations. Almost all queries run through Drizzle over a single DATABASE_URL, so tenant isolation as experienced by users is enforced by the application-layer authorisation logic; RLS applies only to the few profile reads made through the Supabase client with your session.
Background jobs
Long-running work runs on Trigger.dev, a hosted job runner. Jobs are defined in apps/web/src/trigger/jobs/* and include PR verification, requirement enrichment, requirement and code embedding, GitHub repository indexing, GitHub issue sync, requirement import, test generation, Slack digests and PR escalations, and the account-deletion sweep. Server Actions and Route Handlers trigger most jobs; the Slack digest and the account-deletion sweep run on Trigger.dev cron schedules. Jobs write results back to Postgres and, for verification, back to GitHub as check runs and comments.
AI provider seam
Every model-calling agent in packages/ai/src/agents/* calls runStructured() in packages/ai/src/provider. That seam selects the chat provider from AI_PROVIDER — OpenAI by default, Anthropic or Google when configured — and applies each agent's model and sampling settings from a registry. Agents return Zod-validated structured output.
Embeddings bypass the chat-provider choice: they always use OpenAI text-embedding-3-small. The safety layer wraps untrusted content in a marked block, scrubs recognised secret patterns, and stamps a provenance record on each persisted artefact. What is and is not scrubbed is listed on the Security page.
MCP server
The MCP server exposes Spectrace to AI assistants through the Model Context Protocol (MCP), a standard for giving models tools and context. It runs three ways: hosted at /api/mcp inside the web app, as a local stdio process via the spectrace-mcp CLI, or self-hosted over HTTP from the package's Dockerfile. The hosted endpoint authenticates each request with an API key and reads Spectrace's own database. The stdio and Docker paths connect to a Postgres you supply through DATABASE_URL (the same schema, your own instance) and authenticate with an API key from that database.
Tool permissions derive from the key owner's organization role, intersected with any scopes on the key. See Connect an agent and the tool reference.
VS Code extension
The extension signs in through a one-time authorization code exchanged for a Supabase session, then calls /api/v1/* with that session as a bearer token. It lists your projects and assigned requirements, links files and tasks to a requirement, marks development started or complete, and generates commit messages and Playwright tests from the editor. See VS Code extension.