Skip to main content

API (@tedos/api)

The API is the Fastify backend for TED OS — the server-side home for the product endpoints, the Plan Engine API, ingress webhooks, and the MCP server. Stack: Fastify + Drizzle + Postgres + pg-boss (ADR-001). Deployed to Fly as the app tedos-api.

What it exposes

SurfaceRoutesNotes
Product API/projects, /p/:id/*Behind the Clerk auth/tenancy guard. See Product SoR
Engine/engine/*The last-mile engine — goals / jobs / decision. See Engine
Plan Engine/plan/*The dev-workflow graph API + 9 plan_* MCP tools. See Plan Engine
Webhooks/webhooks/githubHMAC-verified ingress (GitHub → graph; the ingestion pattern)
Health/healthzUsed by Fly health checks

Process split (web + worker)

One image, two Fly process groups:

ProcessRunsPublic HTTP
webFastify (the routes above)yes
workerthe pg-boss handler + cron (mirror jobs, refresh jobs)no

The web process starts pg-boss only to enqueue (the webhook needs it); the worker process owns the handler/cron — no double-registration. See Deploy topology.

Two databases (a hard rule)

The API touches two separate databases, never one:

ConnectionDatabaseOwnerMigrations
(dev-workflow DB env)the dev-workflow / Plan Engine graph (+ pg-boss tables)api + Plan Engineapps/api/drizzle/
(product DB env)the product System of Record (product schema)@tedos/domainpackages/domain/drizzle/

A single release command runs both migration sets before any new machine serves traffic, and aborts (fail-closed) if either database's connection env var is unset. The two databases are logically separate — tenant/product data must never enter the graph DB. See Decisions (ADR-006).

Environment is referenced by name only

The API's configuration (database connections, Clerk keys, the model layer, the GitHub token) lives in environment variables. This documentation refers to those variables by name only and never includes their values.

The shared contract

The API and the admin both import the frozen @tedos/shared contract (zod-as-source + inferred TypeScript types), so request/response shapes match by construction.

The model layer

The engine's model provider is selected by environment: a local model (Ollama), a hosted vLLM (OpenAI-compatible), or a deterministic mock with no network. See Engine.