Skip to content

Tech stack

This page lists each technology that Rhumbatron uses and what it does. The sources are the code, the wrangler.jsonc files, the package.json files, bun.lock, and the Terraform roots. Versions are the pinned versions.

Solid arrows are service bindings, Durable Object bindings, or direct calls. Dotted arrows are Queue messages or K2 records. The Storage table lists the storage bindings.

flowchart LR
  USER["Browser"] --> WEB["web (TanStack Start)"]
  USER --> APPS["apps (Dynamic Workers)"]
  WEB --> API["api (Hono)"]
  API --> COORD["coordinator<br/>ProjectRootDO, ResourceShardDO,<br/>ProjectViewDO"]
  API --> INT["integration<br/>3 Workflows"]
  API --> AG["agents<br/>AgentDO + Pi"]
  COORD -.->|"K2 EVENTS_00..07"| ER["event-router"]
  ER -.->|"Queues"| AG
  ER -.->|"Queues"| INT
  ER -.->|"Queues"| IDX["indexer"]
  INT -->|"APPS"| APPS
  AG --> SBX["sandbox (container)"]
  INT --> SBX
  INT --> BR["Browser Run"]
  AG --> GW["AI Gateway"]
  INT --> GW
  GW --> ANT["Anthropic"]
  AG --> WAI["Workers AI"]
  INT --> WAI
  ER --> WAI
  IDX --> WAI
Technology Used for Where
TanStack Start 1.168, Router 1.170 Server-rendered React app and routes. Route loaders read each signed-in page’s primary data on the server, and the HTML carries it (ADR 0027, src/lib/ssr-data.ts). Clock times and ages print the same on the server and in the hydration (src/lib/render-time.ts). The client entry and the route-chunk preloads start after the first contentful paint, so the stylesheet and fonts load alone; a hidden tab starts at once, and every tab after 5 s at the latest (src/server.ts). The chunks preload at low fetch priority. Fingerprinted /assets/* files are cached as immutable for one year (public/_headers, sent by the Terraform worker module). Text typed before hydration stays (src/lib/pre-hydration.ts) apps/web
React 19.3, Vite 8.3 UI runtime and build apps/web
@cloudflare/vite-plugin 1.63 Builds the web app as a Worker apps/web/vite.config.ts
Tailwind CSS 4.3 Styling. One stylesheet (src/styles.css) carries the fonts, Kumo, Tailwind, the theme and XYFlow’s base styles. Below 640px no text is smaller than 12px (ADR 0027) apps/web
@cloudflare/kumo 2.14 Components apps/web/src/components
TanStack Query 5.104, @tanstack/react-router-ssr-query 1.167 Server state and polling of API reads. The router’s SSR integration writes the server-read cache into the HTML; queries stay fresh for 10 s apps/web/src
Zustand 5.0 Small client state: the flight view store and the shared lane time axis apps/web/src/components/flight
XYFlow (@xyflow/react 12.12) Work Graph, DAG views on the Agents and Events pages, and the Product Graph canvas work-graph.tsx, dag/dag-canvas.tsx, product-graph-canvas.tsx
CodeMirror 6 (@codemirror/*) Code editor on the Code page and in its edit-session IDE. It loads on the client only, in its own chunk. The IDE is a further chunk that loads only when a session starts apps/web/src/components/code, apps/web/src/components/code-ide
Phosphor icons, Fontsource Archivo Icons and the font apps/web
  • One replay controller serves the execution timeline on the Project overview and the Agents graph (src/components/replay). The useReplay hook has two modes. Live is the default. In Live, the view shows the newest state and follows new facts. Replay shows the state at a playhead. Play moves the playhead through the recorded facts at 1x, 2x, 4x, or 8x on requestAnimationFrame. At 1x one minute of recorded time plays in one second, and each pause between two facts takes 0.2 to 1.5 s. Under reduced motion the playhead holds at each fact and then steps to the next one. The control bar has play and pause, the speeds, the replay clock, a range with a tick per notable fact, and Live. Space plays or pauses. Left and Right step between facts. Home goes to the first fact. L goes live.
  • Timeline replay (components/timeline/timeline-replay.ts): an accent playhead sweeps the time axis. Attempt bars and Change spans show up to the playhead. A CSS clip follows the playhead every frame, so the layout stays still. Markers appear when the playhead passes them. The “Needs attention” rail shows the open questions, approval requests, Challenges, and failed commands at the playhead.
  • Timeline rows (components/timeline/use-timeline-disclosure.ts): each person and each Change row expands and collapses. The browser keeps the choice per Project in localStorage. Without a stored choice, every person is open, a Change in flight is open, and a finished Change is collapsed. The server render uses these defaults, and the stored choice applies after hydration.
  • Recovered failures (src/lib/recovery.ts): one rule for the timeline, Flight Control, the Change page, and the event feeds. A failed attempt that a later attempt of the same Task completed shows “Retried, recovered” in the warning color. A failed attempt that the Task retries shows “Failed, retrying”. Only a failure that nothing recovered is red. The rule reads the Task status and its attempts, or the task.failed and task.completed events.
  • Agents replay (components/agents-page/agents-replay.ts): Change and Task nodes appear when they were created (task.created or change.compiled from one page of the Change’s oldest events, read once per Change). An agent appears when its first attempt starts. While an attempt runs, the agent shows its tier (H, S, O), a pulse, and a progress line for the recorded duration. Retries and escalations show in its meta line. Conflict edges appear as suspected when detected and take their recorded state at their last update. A strip under the graph shows one lane per agent with the playhead, and the latest steps as text. A polite live region reads the current step.
  • Events filters (components/dag/filter-search.ts, components/events-page/events-filter-bar.tsx): text search over the event type, summary, and IDs; person; Change by its short title; Task or agent; event type group; and time range. The filter lives in the URL (?q=&person=&change=&task=&group=&range=), and the List and Graph views share it. change also scopes the stream on the server, so “Load older” reads further back in that Change. The other fields filter the loaded events. The bar shows the number of set fields and a Clear button.
Technology Used for Where
Hono 4.13 Public product API, body limits, validation workers/api
Zod 4.6 Protocol schemas and request validation packages/protocol, packages/model-router, and the api, apps, coordinator, event-router, and integration Workers
Clerk (@clerk/backend 3.23, @clerk/tanstack-react-start 1.7) User sign-in and token check (ADR 0002). Prod uses a Clerk production instance. For a signed-out visitor, Clerk loads at the first pointer, touch, key, or focus event (src/lib/clerk-deferral.ts) workers/api, apps/web
Technology Used for Where
Durable Objects with SQLite ProjectRootDO (Canonical State and CAS), ResourceShardDO (Claims, Intents, outbox), ProjectViewDO (live read model) workers/coordinator
Transactional outbox in DO SQLite Atomic state change plus Event workers/coordinator/src/outbox.ts
K2 Durable Event log: 8 streams, 4 subscriptions, 7-day retention. Terraform creates it through an adapter (ADR 0006) workers/event-router, scripts/k2-sync.ts
Queues Commands: agent-wakeups, integration, verification, indexing, release, dead-letter workers/event-router, workers/integration, workers/agents
Workflows ChangeWorkflow, CandidateVerificationWorkflow, ReleaseWorkflow workers/integration
Cron Triggers Event router sweep every minute. Every 5 minutes the tick also queues recovery of Changes stuck in releasing. Once a day it queues fork and Project cleanup. The paused switch turns the cron off workers/event-router/src/index.ts
Service bindings and DO RPC Internal calls between Workers every wrangler.jsonc
Technology Used for Where
Agents SDK (agents 0.27) AgentDO base class and PiHarness workers/agents/src/agent-do.ts
Pi (@earendil-works/pi-durable 1.1, pi-ai 1.1) Durable model and tool loop. AgentDO implements AgentRuntime (ADR 0009) workers/agents/src
AI Gateway rhumbatron-models-<env> Proxy for each Anthropic call: logs, 20 requests per minute, and a 30-day spend limit equal to the monthly Anthropic budget infrastructure/terraform/modules/ai
Anthropic (Claude Haiku 5.5, Sonnet 5.5, Opus 5.5) Root Planner, Agents, intake gate, request review, conflict review, acceptance check, Integration Judge, compaction. See Model routing packages/model-router
@anthropic-ai/sdk 0.129 Client for complete() calls through the gateway packages/model-router
Workers AI, Clef-flash (@cf/cloudflare/clef-flash) Bounded decisions: ambiguous wake-ups, goal suggestion pills, intake votes, and the model route when the rules end at default workers/event-router/src/causal.ts, workers/agents/src/suggestions.ts, workers/integration/src/intake.ts, packages/model-router/src/route.ts
Workers AI, @cf/baai/bge-small-en-v1.5 384-dimension embeddings for Vectorize and the intake gate workers/indexer, workers/agents/src/retrieval.ts, workers/integration/src/intake.ts
Workers AI, @cf/baai/bge-reranker-base Reranks related requests in the intake gate workers/integration/src/intake.ts
Context Compiler Deterministic Context Packet packages/context-compiler
Causal Router Deterministic wake-up decision packages/causal-router
Conflict detector Overlap and compatibility rules packages/conflict
Technology Used for Where
Cloudflare Sandbox (@cloudflare/sandbox 0.12.6) Linux shell for Agents and Candidate checks. One container instance, sleep after 2 minutes, a monthly hour cap workers/sandbox, workers/agents, workers/integration
Containers (image docker.io/cloudflare/sandbox:0.12.6, instance type basic) Runs the Sandbox. Terraform deploys it through an adapter (ADR 0012) scripts/sandbox-deploy.ts
Browser Run (@cloudflare/puppeteer 1.4) Browser check of a Candidate, with a daily seconds cap workers/integration/src/browser-check.ts
Dynamic Workers (Worker Loader, @cloudflare/worker-bundler 0.2.6) Run the app of each Project at <slug>.rhumbatron.com (ADR 0020). Run the build, unit, and contract checks when the code allows it workers/apps
Project checks in the Sandbox build, unit, and contract checks that a Dynamic Worker cannot run, plus protected-invariant-cart, performance, security, and browser workers/integration
@rhumbatron/evidence Coverage states, citation validation, promotion rules packages/evidence
Technology Used for Where
Artifacts Source of each Project: canonical repo, Task forks, Candidate forks (namespace rhumbatron-projects-<env>) workers/agents, workers/integration, workers/indexer
isomorphic-git 1.43, memfs 4.80 Read and write Artifacts repos inside Workers workers/integration, workers/indexer
D1 rhumbatron-control-<env> Product metadata, receipts, counters, app pointers. SQL migrations are in migrations/d1 agents, api, apps, event-router, indexer, integration
R2 rhumbatron-evidence-<env> Evidence, context snapshots, indexes, code store, event archive, app bundles most Workers
KV rhumbatron-config-<env> 5-minute cache of the Project policy (CONFIG). D1 is the source of truth workers/integration/src/policy.ts
Vectorize rhumbatron-memory-<env> Semantic retrieval after exact lookup. Terraform creates it through an adapter (ADR 0003) workers/indexer, workers/agents/src/retrieval.ts
@babel/parser 8.0 Symbol index of changed files workers/indexer
Technology Used for Where
Workers Logs Runtime logs. Logs are on for each Worker modules/worker, modules/durable-worker, adapter scripts
Analytics Engine Model calls, Event metrics, wake-ups (METRICS, EVENT_METRICS) workers/agents, workers/indexer, workers/event-router
AI Gateway logs Model request logs and cost AI Gateway
scripts/cost-report.ts, scripts/budget-alerts.ts Usage report and account budget alerts scripts
Technology Used for Where
Terraform 1.16 or later (Cloudflare provider ~> 5.27, hashicorp/external ~> 2.4) Each remote Cloudflare change. Roots: bootstrap, envs/global, envs/prod infrastructure/terraform
R2 remote state Terraform state backend backend.hcl per root
terraform_data adapters K2, Vectorize, Sandbox Worker, apps Worker, D1 migrations, budget alerts (ADR 0003, 0006, 0012, 0020) scripts/*.ts
Cloudflare DNS Worker custom domains rhumbatron.com, www, api, and docs. A wildcard record and route for apps. Clerk CNAME records modules/worker, envs/prod
Zone settings Always HTTPS, minimum TLS 1.2, TLS 1.3 on, strict SSL envs/global, modules/security
Wrangler 4.149 Local development, type generation, and wrangler deploy --dry-run bundling only apps/*, workers/*, scripts/build-workers.ts
Pause switch locals.paused removes the cron and sets the Sandbox max_instances to 0 envs/prod
Technology Used for Where
Bun 1.3.14 Package manager, workspaces, script runner root package.json
TypeScript 7.0.2 Language and typecheck all packages
Turborepo 2.11 Task runner for build, typecheck, tests turbo.json
Biome 2.5 Lint and format biome.json
Vitest 5.0 Critical tests (*.critical.test.ts) packages, Workers, scripts
Playwright 1.63, Lighthouse 12.6 UI suite (bun run test:ui) and signed-in Lighthouse runs against prod root package.json, scripts/lighthouse.ts
Knip 6.40, Sherif 1.13 Unused code and dependency checks bun run check:deps
Lefthook 2.2, commitlint 21 Pre-commit, commit-msg, and pre-push hooks lefthook.yml
Gitleaks Secret scan in the pre-commit hook and bun run check:secrets lefthook.yml
scripts/check-guardrails.ts Enforces Terraform-only deploys and no wrangler deploy scripts
GitHub Actions ci checks each pull request. production deploys each push to main through Terraform (ADR 0031) .github/workflows/ci.yml, .github/workflows/production.yml
Astro 7.3, Starlight 0.42, Mermaid 12.1 This documentation site at docs.rhumbatron.com. Each diagram renders when it comes near the viewport apps/docs

routeByRules in packages/model-router/src/rules.ts picks the tier. resolveTier then maps the tier to a model. ALLOW_OPUS is false in prod (ADR 0021). Each opus decision runs on Sonnet, and the receipt records opus_disabled. Set the Terraform variable allow_opus to true to run claude-opus-5-5.

Work Tier chosen Model that runs Source
Root Planner (plan, large) opus claude-sonnet-5-5 workers/integration/src/root-planner.ts
Destructive migration, design conflict across resources opus claude-sonnet-5-5 rules.ts
Normal implementation (medium) and the default sonnet claude-sonnet-5-5 rules.ts
Large child implementation sonnet claude-sonnet-5-5 rules.ts
Billing and non-trivial authorization floor sonnet at least claude-sonnet-5-5 rules.ts
Small, low-risk first attempt, and summarize, classify, compact, transform haiku claude-haiku-5-5 rules.ts
Context compaction of long failure logs haiku claude-haiku-5-5 workers/agents/src/context-compaction.ts
Conflict review sonnet, then opus only when ALLOW_OPUS is true claude-sonnet-5-5 workers/agents/src/conflict-review.ts
Intake gate Clef-flash votes, then sonnet when needed claude-sonnet-5-5 workers/integration/src/intake.ts
Request review sonnet claude-sonnet-5-5 workers/integration/src/request-policy.ts
Acceptance check haiku, then sonnet once when the haiku output is not valid claude-haiku-5-5, claude-sonnet-5-5 workers/integration/src/acceptance-check.ts
Integration Judge on a selection tie sonnet claude-sonnet-5-5 workers/integration/src/candidate-selection.ts
Ambiguous wake-up, goal suggestion pills Clef-flash @cf/cloudflare/clef-flash causal.ts, suggestions.ts
Release decision No model Deterministic rules workers/integration/src/release-model.ts

Thinking effort is low for haiku, medium for sonnet, and high for opus. Routed Agent steps cap output at 4,000 tokens for haiku and 8,000 tokens for sonnet and opus. Two failures at one tier move the Task up one tier. Two failures at the top tier stop the Task with limit max_attempts_per_tier, and the Change becomes budget_blocked. A transport failure retries once at the same tier and never escalates (packages/model-router/src/escalation.ts). The caps are 1,000 agent model calls per day and an Anthropic budget of 100 USD per calendar month (packages/model-router/src/budget.ts, Terraform anthropic_monthly_budget_usd).

Each row names one area and the choice that the code makes in it.

Area Choice in the code
The opus tier (route kinds plan, architecture, and arbitration) Sonnet 5.5 while ALLOW_OPUS is false (ADR 0021)
Model provider Anthropic only (ADR 0021)
Bounded decision models Only Clef-flash runs. No code path calls Clef
Deployables Nine Workers, including rhumbatron-sandbox (ADR 0012) and rhumbatron-apps (ADR 0020). The docs site is a tenth, assets-only Worker
Products without a first-party Terraform resource terraform_data adapters for K2, Vectorize, the Sandbox Worker, and the apps Worker
Project source at creation Each Project starts from an empty repository (ADR 0022)
Components and charts kumo. No chart library
Tracing No OpenTelemetry or Cloudflare tracing. Durable Object Workers set traces.enabled = false
Edge protection No WAF, rate limiting, Turnstile, or Access. The AI Gateway has a request rate limit
CI/CD ci.yml for checks and production.yml for the Terraform deploy on each push to main
Agent runtime AgentDO implements AgentRuntime and runs Pi through PiHarness of the Agents SDK (ADR 0009)