Architecture
Ultron is a Next.js application deployed on a containerized cloud runtime, alongside a set of scheduled workers running at the edge. The application runtime orchestrates a 57-skill registry through a tool-calling chat loop. The edge workers handle scheduled work, the marketing swarm, and an inference relay that backs the sandbox's specialist model tier.
Overview
- Frontend
- Next.js 14 App Router, output: standalone
- Host
- A containerized cloud runtime
- Build
- A build pipeline that ships a new container on every release (multi-stage Docker)
- Chat handler
src/app/api/chat/v2/route.ts- Skill registry
- 57 skills in
src/lib/skills/registry.ts - Skill engine
src/lib/skills/engine.ts- Models
- Four tiers — Minuet, Allegro, Forte, Plinth — each mapped to a distinct role
- Sandbox
- An isolated per-conversation sandbox on managed Kubernetes, with a live remote desktop view
- Postgres
- Supabase with pgvector for embeddings
- Edge
- Scheduled workers running alongside the app: cron, swarm, and an inference relay
Ultron runs two coordinated planes. The application plane is a single Next.js container deployed on a containerized cloud runtime; everything a user can touch from the chat surface routes through it. The edge plane is a set of scheduled workers that pick up work the application plane is not the right place for: scheduled jobs, the marketing swarm renderer, and the inference relay used by the sandbox.
Both planes share state. Supabase Postgres is the canonical store for users, conversations, messages, skills metadata, memory, billing, and pause points. Object storage holds binary assets: brain file uploads, carousel exemplar PNGs, the carousel component index. A small database stores the carousel engine's own catalog. A vector index stores the 768-dimension brief embeddings the swarm uses for exemplar retrieval.
Runtimes
Three execution environments, each picked for a specific reason.
| Runtime | Where | What runs there | Why |
|---|---|---|---|
| Application runtime | Containerized cloud runtime | Next.js app, chat handler, every interactive API, cron endpoints | Heavy Node runtime with playwright-core, the model SDK, Supabase service-role calls. Needs more headroom than an edge worker's tight memory limit and short execution budget. |
| Edge worker | Edge | Scheduled cron, marketing swarm pipeline, inference relay | Cheap, globally distributed, native scheduled triggers, native bindings to storage, database, and vector-index services. |
| Sandbox | Per user, on demand | Bundled engineering skills (CLI coding agent, playwright, ffmpeg) | Untrusted code execution with a real Linux desktop the user can watch over a live remote desktop view. |
cf-workers/ultron-cron/wrangler.toml, not in the application runtime. The worker fires on schedule, then POSTs to the application runtime with the shared WEBHOOK_SECRET. This keeps the schedule discoverable in one place and isolates a misbehaving cron from the rest of the app.Deploy stack
What ships when you push to the production branch.
Container build pipeline
A push to the production branch triggers a build pipeline defined in deploy-pipeline.yaml. The build produces a container image tagged with the commit SHA, pushes it to the image registry, and rolls it out as the latest revision.
Worker deployment
Each worker has its own wrangler.toml. Deployment is wrangler deploy from the worker's directory; secrets are set with wrangler secret put.
Request path
A user message travels through five layers before the assistant responds. Each layer is one file you can open and read.
The handler is structured so each step is its own function. You can open src/app/api/chat/v2/route.ts, scroll to the body of POST, and read top to bottom for the exact path. Tool execution lives in src/lib/skills/engine.ts for skill runs and src/lib/chat-tools.ts for the chat-level native tools.
Skills
A skill is the unit of work. Skills are loaded from a flat registry; each declares a manifest with a model tier, a turn budget, and a tool allow list.
The engine reads the tier and resolves it to a concrete model id at request time. The current mapping is hard-coded in src/lib/skills/engine.ts:
| Category | Count | Examples |
|---|---|---|
| research | 8 | competitive-analysis, market-sizing |
| lead-gen | 7 | vc-prospector, lead-enrichment |
| sales | 9 | cold-outreach, pipeline-review |
| content | 11 | content-pulse, ad-copy |
| ops | 7 | morning-briefing, churn-save |
| legal | 5 | contract-draft, clause-library |
| design | 5 | brand-system, asset-batch |
| paid-ads | 4 | audience-builder, creative-test |
cortex, specter, striker, pulse, sentinel are UI grouping labels that bundle multiple skills under a single slash command. They are not separate runtime entities.Tools
Three families of tools are exposed to the model on every turn. The registry dispatches in that order on every tool call.
Provider modules
Each module exports a ToolModule. The dispatcher checks modules before falling through to the legacy switch in chat-tools.ts. Two modules are wired today: hitl.ts (approvals) and stripe.ts (billing).
Native catalog
The native catalog at src/lib/chat-tools.ts exposes 91 tools across web research, CRM, email, calendar, content, integrations, code execution, and brain access. Each tool is a tool-call function schema paired with an async executor that receives the tool context.
External MCP servers
Servers expose tools over JSON-RPC 2.0. Ultron treats them as a pluggable layer: each server is registered with a name prefix, an auth header, and an optional per-user scoping. Tools discovered from external servers are cached for ten minutes per user.
Memory
Ultron persists state across three storage surfaces, plus a nightly consolidation pass that reviews and prunes what's stored. Retrieval is hybrid: meaning-based search combined with keyword search, then a small step narrows to what's relevant for the turn.
| Surface | Backing store | What it holds | Read path |
|---|---|---|---|
| Notes & auto-summaries | Postgres + pgvector | User-written notes, pinned conversation snapshots, automatic end-of-turn summaries | Hybrid retrieval (meaning + keyword), then a relevance pass |
| Uploaded files | Postgres + Storage | Uploaded documents, chunked and indexed, read-only once stored | Hybrid retrieval over chunks |
| Artifacts & agreements | Postgres | Tracked artifacts and agreements | Counted in a per-turn inventory so the model knows the corpus exists without reading it all |
Workspace
When a skill needs to run code, browse a site, or render a file, Ultron provisions an isolated per-conversation sandbox on managed Kubernetes.
The sandbox comes prebaked with a virtual display, a window manager, and a remote-desktop server. The user opens the workspace at /dashboard/workspace and sees the sandbox through an embedded live remote desktop view.
The sandbox runs a CLI coding agent for the lite tier. To keep cost down, the CLI is pointed at an inference relay (see Scheduled workers below), which translates the CLI's tool-calling protocol into a call against the Plinth tier — a free, specialist model tuned for sandbox and background-agent work. The CLI speaks the same protocol regardless of which tier answers it.
Canvas
Canvas is the rendering surface for skill output. A canvas is a JSON spec that gets compiled at runtime into one of 30+ block types.
The block catalog at src/components/canvas/CanvasBlock.tsx registers blocks like comparison_table, kanban, score_card, code_diff, and structured_doc. The canvas exporter can save the rendered block as PNG, PDF, or push it into the brain as a memory.
Scheduled workers
A small set of scheduled workers run alongside the application runtime. Each is small, isolated, and has its own deployment config.
ultron-cron
Fires scheduled triggers and POSTs to the application runtime with the shared WEBHOOK_SECRET. Two schedules ship today: a daily lifecycle email run at 09:00 UTC and a one-minute reconciler that fails any stuck job.
marketing-swarm
The carousel engine. A user posts a brief to POST /carousel, the worker retrieves exemplars from a vector index, plans a deck with a lightweight planning model, validates against per-slide budgets, renders to PNG in-worker via Satori plus Resvg WASM, scores each slide with a vision-scoring model, and promotes the run back to the catalog database and vector index if it scores well.
services/carousel-renderer/ as a cold fallback but is not called in production. The active path is in-worker render-v2.inference relay
Exposes a POST /v1/messages-shaped tool-calling surface and translates each request into a call against the Plinth tier. The sandbox's CLI coding agent is pointed at the relay via a base-URL override, so it keeps speaking the same tool-calling protocol while the inference is routed to the cheaper specialist tier.
Background jobs
Cron is split between the ultron-cron worker (canonical) and a small set of cron endpoints on the application runtime, called from the worker.
| Job | Cadence | Trigger source | Purpose |
|---|---|---|---|
reconcile-jobs | Every 60s | ultron-cron worker | Probe sandbox + apify health, fail stuck jobs |
lifecycle-emails | Daily 09:00 UTC | ultron-cron worker | Onboarding, winback, churn-save sequences |
workspace-janitor | Daily 03:30 UTC | scheduler → application runtime | Evict idle sandboxes (idle > 30 days) |
publish | Per minute | scheduler → application runtime | Drain the content publish queue |
automations | Every 5 min | scheduler → application runtime | Run user-defined automations |
run-scheduled | Every 15 min | scheduler → application runtime | Kick scheduled skill runs |
sequences / pipeline / workflows / dispatch / task-update | Variable | scheduler → application runtime | CRM and content workflow advancement |
marketing-swarm | On demand | User → marketing-swarm worker | Plan, render, and score carousels |
apify-webhook | Push | Apify → application runtime | Ingest maps and jobs scraper results |
src/app/api/cron/. Adding a new schedule means adding the entry to SCHEDULES in cf-workers/ultron-cron/src/index.ts AND to the [triggers].crons array in its wrangler.toml. Forgetting one half is a silent failure.Repository map
The shape of the codebase. Folders you will visit on every page in this section.
Glossary
- Skill
- A registered unit of work with a manifest, a tool allow list, a model tier, and a turn budget. 57 skills ship in the registry.
- Tool
- A function exposed to the model during a turn. Tools come from three families: provider modules, native handlers, and external MCP servers.
- Turn
- One iteration of the tool-calling loop. A skill run usually spans several turns.
- Persona
- A UI grouping label that bundles related skills under one slash command. Cortex, Specter, Striker, Pulse, and Sentinel are personas.
- Pause point
- A row written by the wait_for_approval tool. It blocks the turn until the user approves through the UI.
- Canvas
- A JSON spec rendered into one of 30+ block types. Canvases are the visual output of a skill run.
- Sandbox
- An isolated per-conversation sandbox on managed Kubernetes where untrusted code, browsers, and renderers execute.
- Application runtime
- The containerized cloud runtime that hosts Ultron's Next.js app; a build pipeline ships a new container image on every release.
- Worker
- A scheduled worker running alongside the app. Ultron ships several, including ultron-cron and marketing-swarm.
- Inference relay
- The worker that exposes a tool-calling surface for the sandbox's CLI coding agent but routes the actual inference to the Plinth tier.