System Architecture

Agentic Coding Platform (Auraison Studio)

Status: Proposed (RFC) · Updated: 2026-07-18 · Jira: AURA-743 (this doc closes its assessment scope), AURA-744 (data model, done), AURA-730 / AURA-733 (security, linked)

1. Context and scope

Auraison's architecture docs have been converging on a Cloudflare-hosted central agent runtime for over a quarter: the system architecture commits to a Claude Managed Agent on Cloudflare (Agents SDK, Durable Objects, Dynamic Workers), and the agent data model distilled the ontology of Cloudflare's vibesdk into a canonical Auraison schema. What has been missing is the product that makes those commitments concrete. This doc designs that product: a browser-based agentic ROS2 development service, modeled on Cloudflare's enterprise AI vibe-coding reference architecture, in which a session agent orchestrates ROS2 development the way vibesdk's agent orchestrates web-app generation. The nearest existing service is Leet Robotics, which puts ROS2, Gazebo, and Foxglove in the browser as a learning platform; Auraison Studio differs in that the agent, not a lesson sequence, drives the development loop, that a GPU execution tier (Ray, Isaac Sim) sits behind the free tier, and that tenants can attach their own hardware, laptop included, as a workspace substrate.

The doc also discharges AURA-743: section 6 maps both Cloudflare reference architectures onto Auraison's four planes with an adopt/adapt/skip decision per component, and section 4 gives the vibesdk verdict with license.

Working name: Auraison Studio, at studio.aegeanai.com. "Studio" below means the product surface; "control plane" keeps its existing meaning (the on-prem FastAPI service and its agents).

2. Product definition and user journey

An external user signs in, describes a robotics task in chat ("make the TurtleBot patrol the maze and stop at obstacles"), and a session agent plans the work, scaffolds a ROS2 workspace, builds it, runs it in simulation, and streams the running sim back into the browser as a live Foxglove view. The session terminates in a shareable artifact: the packaged ROS2 workspace plus a recorded replay at a public URL. Reference apps seed the catalog (TurtleBot maze first, AR4 manipulation later) the way courses seed Leet Robotics, but the user's primary interaction is conversational, with an embedded editor available as a secondary surface.

Robotics development on the platform is wider than the code-build-simulate loop. Recorded runs accumulate in the tenant's storage and the lakehouse, and working with them means annotation (labeling episodes and events for training data), visualization (Rerun and Foxglove views over stored recordings, not just live sims), and analytics (success rates, regressions across runs). Sessions can therefore generate companion web apps for these functions and deploy them as isolated Workers (section 9), so "an annotation tool for my grasp dataset" is as valid a session outcome as "a patrol behavior for the TurtleBot".

The v1 journey:

  1. Sign in at studio.aegeanai.com through Cloudflare Access; first login creates the tenant and provisions the free tier.
  2. Pick a reference-app template or start blank. A hosted CPU workspace container is provisioned by default; alternatively the user runs the Auraison connector on their own laptop or on-prem machine (CPU or GPU) and the session attaches to that instead.
  3. Chat with the session agent. The agent produces a Blueprint, writes ROS2 packages into the workspace, runs colcon build, launches headless Gazebo, and the UI embeds Foxglove web against the workspace's bridge.
  4. Iterate conversationally. Sessions can burst to a GPU-tier session (quota- and waitlist-gated) for full-physics simulation, Isaac Sim, or training.
  5. Publish. The workspace is packaged to R2 and the final sim run is recorded; the share page at artifacts.aegeanai.com embeds the replay.

3. Decisions

Five product decisions were made before the architecture was drawn, and the rest of the doc follows from them.

DecisionChoice
Audience (v1)External users; a product, not an internal tool
Execution substrateThree, behind one provider interface: Cloudflare Containers (hosted CPU, default), Auraison GPU nodes (hosted burst, gated), BYO connector (tenant's own laptop or on-prem machine, CPU or GPU)
Primary surfaceChat-first vibe coding; editor secondary
Terminal artifactTwo kinds: shareable sim artifact (packaged workspace + recorded replay) and companion web apps (annotation, visualization, analytics) on Workers for Platforms; no physical robots in v1
Monetization (v1)Full metering and free-tier quotas from day one; Stripe deferred to v1.5

Choosing an external audience pulls parts of the management plane (tenancy, quotas, metering) forward from v2 into this design. Choosing a sim artifact as the terminal deliverable keeps physical robots, and the safety and scheduling machinery they need, out of v1; the user-plane actuation-gating constraints remain the path for a later deploy-to-robot tier.

4. Build strategy

The strategy question concerns the platform layer only: the chat surface, the session agent, tenancy, and metadata. It does not decide where workspaces execute; workspace execution is a provider interface with three substrates (section 5), and the tenant's own hardware is one of them. Three strategies for the platform layer were considered. Forking vibesdk would buy a working chat product, session catalog, and sandbox lifecycle, but its blueprint prompts, phase machine, preview model, and deploy pipeline all assume web apps deployed to Workers for Platforms; the ROS2 domain and the multi-substrate workspace model would be surgery against inherited assumptions. Extending the existing FastAPI control plane with Cloudflare as a mere front door would minimize new technology but concentrate multi-tenant isolation, metering, and free-tier scaling on a single on-prem process with an in-memory job store, and it would walk back the central-runtime direction the system architecture already adopted. The chosen strategy builds natively on the Cloudflare Agents SDK, implementing the canonical ontology from the agent data model doc, and treats vibesdk as a reference to quarry rather than a base to fork.

The vibesdk verdict, for AURA-743: reference, not fork. The repository is MIT-licensed, so forking is legally clean, but web-app generation is its only deliverable, wired through the core of the codebase; ours is one deliverable among several (ROS2 workspaces, sim recordings, companion apps) on a multi-substrate workspace model it has no concept of. Its data model has already been absorbed into agent-data-model.mdx; its sandbox lifecycle and phase-machine patterns are adopted below in adapted form, and its Workers-for-Platforms deploy path is adopted as-is for companion apps (section 9).

5. System architecture

Cloudflare runs the product surface, the agent runtime, and all tenant-facing state. Workspace execution happens on one of three substrates behind a single provider interface: Cloudflare Containers (hosted CPU, the zero-friction default), Auraison's GPU nodes (hosted burst, gated), or the tenant's own hardware attached through a connector. The on-prem cluster keeps its existing control plane, demoted from public front door to internal service.

In the monorepo, the Studio Worker, its UI, and the Orchestrator Agent live under control-plane/studio/ (they are control-plane surface); the ros2-workspace image and its CI live under user-plane/.

The Studio Worker serves the Next.js UI and the platform API. Each session is an Orchestrator Agent, a Durable Object created through the Agents SDK, which holds live session state and drives the agent loop. Every LLM call from every session goes through AI Gateway, which is what makes per-tenant cost attribution and prompt auditing a configuration rather than a feature. D1 holds the platform catalog (tenants, apps, sessions, artifacts, deployments; the target schema in agent-data-model.mdx §5 lands here for platform metadata, while the control plane keeps its own store for GPU jobs). KV holds session and permission lookups. R2 holds workspace snapshots and published artifacts, tenant-prefixed. Secrets Store holds platform credentials, injected at the platform layer.

All three substrates run the same pinned ros2-workspace image (ROS 2 Jazzy, Gazebo Sim headless, foxglove_bridge, colcon, reference-app templates) and are driven through one workspace provider interface: the Orchestrator DO issues workspace.* and sim.* calls against the interface and does not know which substrate answers. The hosted CPU provider runs one Cloudflare Container per active workspace; the container's preview URL carries the Foxglove websocket into the browser, and there is no X11 or VNC in the CPU tier. The hosted GPU provider is the existing user plane (Ray on Proxmox, ros.dev.gpu, Isaac Sim over WebRTC using the multi-user port scheme from the Isaac Sim runbook), reached only through a Cloudflare Tunnel; GPU endpoints have no public exposure, the FastAPI control plane and its claude -p specialist agents keep their current responsibilities on that side, and the Orchestrator DO is a client of the control plane, not a replacement for it.

The BYO provider is a small connector CLI the tenant runs on their own machine (laptop or on-prem server, CPU or GPU). The connector pulls the ros2-workspace image, runs it locally, and holds a single outbound connection to the platform (a persistent WebSocket to the tenant's Orchestrator DO, or equivalently a cloudflared tunnel); no inbound port is ever opened on the tenant's machine. Through that connection the DO drives the local container exactly as it drives a hosted one. Visualization improves rather than degrades on this substrate: the browser connects to the local container's Foxglove bridge on localhost when the browser and connector share a machine, falling back to a relay through the connector otherwise. GPU-capable tenant machines run the same image with the GPU runtime enabled, which makes the connector the self-serve alternative to the waitlisted hosted GPU tier.

In four-plane terms: the Studio Worker, Orchestrator DOs, and AI Gateway extend the control plane to the edge; workspace containers and GPU sessions are user plane; D1, KV, R2, and the lakehouse are data plane; tenancy, metering, and quotas are the first shipped slice of the management plane.

6. Reference-architecture component mapping (AURA-743)

The table maps the components of Cloudflare's base and enterprise vibe-coding reference architectures onto this design. "Adopt" means used as the reference intends; "adapt" means the role is filled differently; "skip" means deliberately not used in v1, with the reason.

ComponentDecisionPlaneRole here
Cloudflare AccessAdoptManagementSignup/SSO, tenant identity, service tokens on the Tunnel
AI GatewayAdoptControlAll LLM traffic; cost attribution, prompt logging, caching
Sandboxes / ContainersAdoptUserCPU-tier ROS2 workspaces with preview URLs
Durable Objects (Agents SDK)AdoptControlOrchestrator Agent per session; SQLite-in-DO session state
D1AdoptDataPlatform catalog; per-tenant rows, schema from agent-data-model.mdx
KVAdoptDataSession and permission lookups
R2AdoptDataWorkspace snapshots, published artifacts; tenant prefixes
Secrets StoreAdoptManagementPlatform credentials, injected at platform layer only
Cloudflare TunnelAdoptControlOnly path from Cloudflare to the on-prem control plane and GPU tier
Logpush / Tail Workers / Analytics EngineAdoptManagementPlatform observability and the compute-minutes meter
Workers for PlatformsAdoptUserDeploy target for tenant-generated web apps (annotation UIs, Rerun/Foxglove visualization, analytics over recorded runs) as isolated Workers with per-app bindings; sim runs themselves publish as static replays
Artifacts (git-compatible storage)AdaptDataGit bundles in R2 in v1; move to Artifacts when it generalizes
Dynamic WorkersSkipWrong runtime for ROS2; code executes in containers
Workers VPC / HyperdriveSkipTunnel suffices at this scale; revisit with fleet growth
DLP on promptsAdaptManagementAI Gateway logging + audit in v1; enterprise DLP policies deferred

Two deltas against the reference are worth stating. First, our production plane has two artifact kinds where the reference has one. A sim run publishes as a static, replayable recording, which executes nothing on our infrastructure; a companion web app (annotation, visualization, analytics) deploys exactly as the reference intends, an isolated Worker in a dispatch namespace whose only data reach is its explicitly attached bindings. Second, the reference assumes all execution lives on Cloudflare; here only the default CPU tier does. The GPU tier runs on our nodes and the BYO tier on hardware the platform does not control at all, so the outbound-only connection plus scoped-token boundary carries the isolation burden the reference assigns to bindings alone.

7. Session orchestration

Each session runs the phase machine below, adapted from vibesdk's generator agent. Build and sim failures are inputs to the loop, not errors: the agent reads compiler output and sim telemetry in REVIEWING and decides to iterate or present, within a phase budget (MAX_PHASES, default 10, adopted from vibesdk and enforced alongside the AgentOps runtime policies).

SIMULATING launches headless Gazebo with the generated launch file and evaluates declared outcomes (goal reached, no collisions, required topics alive) rather than just exit codes, so REVIEWING has telemetry to reason over. The Blueprint, the append-only event log, and the file state live in the DO per the canonical ontology; terminal state is mirrored to D1 when the session closes.

The agent's tool surface is small and typed, mirroring the control plane's ALLOWED_TOOLS scoping pattern:

ToolEffect
workspace.write_filesWrite/patch files in the workspace
workspace.execRun a command (build, test, rosdep) in the container
sim.launch / sim.stop / sim.statusManage the Gazebo run and read outcome telemetry
viz.streamReturn the Foxglove websocket URL for the UI to embed
gpu.request_sessionBroker a GPU-tier session through the control plane
artifact.publishRun the publish pipeline (section 9)
app.deployBuild a companion web app and deploy it to the Workers-for-Platforms dispatch namespace (section 9)

8. Workspace execution

A hosted CPU workspace moves through Provisioning → Ready → Active → Idle → Hibernated → Destroyed. On idle timeout the workspace directory is snapshotted to the tenant's R2 prefix and the container is released; resume rehydrates from the snapshot. Containers are cattle and R2 is the workspace of record, which is also what makes a mid-session container death a recoverable event rather than data loss.

A BYO workspace inverts the ownership: the tenant's disk is the workspace of record, and the platform holds only what the tenant publishes plus optional snapshots. The connector lifecycle is Registered → Attached → Detached: registering binds a named connector to the tenant with a scoped token, attaching makes its workspace available to sessions, and detaching (or simply closing the laptop) leaves the session paused, resumable when the connector returns. A workspace snapshotted to R2 can move between substrates, so a session started on a laptop can burst to a hosted GPU session and come back.

gpu.request_session calls the control plane over the Tunnel. The control plane allocates a Ray-managed ros.dev.gpu session, or an Isaac Sim WebRTC session using the existing multi-user signal/media port scheme, syncs the workspace from R2, and returns connection details to the DO. GPU sessions carry hard caps (wall-clock duration, concurrent sessions per tenant) enforced on the control-plane side, so a compromised or runaway edge component cannot exhaust the pool.

9. Artifact pipeline

artifact.publish is the deploy step and it is transactional: the share page is minted only if all three writes land.

  1. Package the workspace as a git bundle plus tarball to the tenant's R2 prefix, versioned, with lineage recorded per the Artifact model (parent artifact, session, blueprint).
  2. Record the final sim run: rosbag captured during SIMULATING, converted to .mcap (and optionally Rerun .rrd), written to the public artifacts bucket under <tenant>/<app>/<run>.
  3. Write the artifacts and deployments rows in D1 and mint the share page at artifacts.aegeanai.com/<tenant>/<app>/<run>, which embeds the Foxglove or Rerun web viewer against the recording.

The share page is the static deliverable, playing the role a deployed Worker URL plays in vibesdk for sim runs. It reuses the existing R2 public-viewer pattern but tenant-namespaced; unlike the current ar4-physical-ai bucket, only the published prefix is world-readable, not the bucket. Serving shares from artifacts.aegeanai.com rather than the product origin follows the standard rule that user-generated content never shares an origin with the app (GitHub's githubusercontent.com, Google's googleusercontent.com); a same-domain subdomain is acceptable here because the tenant contributes only data files (.mcap, .rrd) while the page HTML and viewer are platform-authored.

A project (AURA-799) can additionally bind its DATA-artifact writes — the workspace tarball, git bundle, and recording above — to a bring-your-own S3-compatible target instead of the platform default, via the projects table's bucket_endpoint/bucket_name/bucket_prefix/ bucket_region/credentials_ref columns. This is a storage-seam config change, not an architecture change: any S3-compatible target that accepts path-style URLs works. Hugging Face Buckets are a validated example (https://s3.hf.co/<namespace>, region us-east-1, path-style, operator-provided HFAK… keys generated in the HF UI — there is no minting API, and HF bucket creation itself is manual/UI-only). Credentials are never stored raw in D1: credentials_ref is a name, resolved from the Worker's environment at publish time (STORAGE_CRED_<REF>_ACCESS_KEY_ID/_SECRET_ACCESS_KEY). The share page above stays on the platform artifacts bucket regardless of a project's binding — public serving directly from a bring-your-own bucket (which for HF Buckets means following a GET's 302 redirect to its CDN) is deferred; only the write path is wired today.

Companion web apps are the second deliverable, and they use the reference architecture's deploy path unmodified. app.deploy builds the app in the workspace and deploys it into a Workers-for-Platforms dispatch namespace as an isolated Worker at a tenant-scoped URL on a dedicated registrable domain acquired for tenant apps (the workers.dev analog; name chosen at Phase 4), never on aegeanai.com or a subdomain of it. Companion apps are arbitrary tenant code, so the weaker same-site subdomain isolation that suffices for data-only shares does not suffice here: a separate domain removes shared-cookie and same-site exposure and confines abuse or blocklisting fallout to the app domain. Its bindings are the whole of its data reach: a read-only R2 binding on the tenant's recordings prefix, its own D1 database and KV namespace for app state (annotations land here or back into tenant R2), and access to lakehouse queries only through a platform data API over the Tunnel, authenticated per tenant. An annotation UI, a Rerun or Foxglove viewer over stored .rrd and .mcap files, and an analytics dashboard over run history are all this shape: static assets plus fetch calls against bindings, which is precisely the workload Workers for Platforms isolates well. Apps are private to the tenant by default, with Access-gated sharing following the same pattern as the share page.

10. Tenancy and security

Identity is Cloudflare Access with public IdPs (Google, GitHub, email OTP); first login creates the tenant row in D1. The security posture is the reference architecture's untrusted-code assumption applied end to end: agent-generated code executes only inside the tenant's container, containers get allowlist egress (ROS, apt, and PyPI mirrors only), and platform credentials never enter a workspace; anything the workspace needs is injected by the platform layer from Secrets Store. Calls from the Studio Worker and DOs to the control plane authenticate with Access service tokens over the Tunnel. Storage is tenant-prefixed in R2 and tenant-keyed in D1, and the published-artifact prefix is the only world-readable surface.

The BYO substrate changes who is protected from whom, not the mechanisms. The platform treats a BYO workspace as an untrusted executor: its connector token is scoped to the owning tenant's sessions and R2 prefix, tool results arriving from it are untrusted input to the agent loop, and platform secrets are never sent to it. In the other direction, code executing on the tenant's own hardware is the tenant's own risk, which is the normal posture of any local dev tool; the platform cannot enforce egress allowlists there and does not pretend to. What the tenant runs is the same published, pinned image, so they can audit exactly what the connector executes.

AI Gateway gives every LLM call a tenant- and session-attributed audit record, which is the v1 answer to the reference's DLP requirement. The AgentOps runtime policies already defined in the control plane design (max_tool_calls, token budgets, max_duration) are enforced inside the Orchestrator DO. The new surfaces this design creates (studio.aegeanai.com, the Tunnel, container preview URLs, the tenant-namespaced share bucket, and at Phase 4 the tenant-app domain) fall under the AURA-733 access-control audit, and the shared concerns with the Platform Security epic (AURA-730) are linked there rather than restated. Domain isolation for tenant content follows the split in section 9: data-only shares on the artifacts.aegeanai.com subdomain, executable tenant apps on a separate registrable domain.

11. Metering and quotas

Three meters run from day one, each attributable to tenant and session: LLM spend (AI Gateway), compute minutes (Analytics Engine events emitted on container and GPU-session start/stop), and storage bytes (R2). Quotas live in D1 and are checked by the orchestrator before it provisions anything. Free-tier limits are hard: one concurrent hosted workspace, a daily sim-minute cap on hosted compute, no hosted GPU (waitlist). BYO workspaces consume no compute quota, since the tenant supplies the hardware; only their LLM spend and platform storage are metered, which makes the connector the natural unlimited-sim path for free-tier users. Quota exhaustion surfaces as a chat message with an upgrade path, never a stuck session. Stripe checkout is v1.5; the metering schema is designed so that pricing a tier is a query over existing data, not a migration.

12. Error handling

Task failures and infrastructure failures are kept distinct. Build errors and failed sim assertions feed the agent loop (section 7). Infrastructure failures surface as typed events and degrade the session instead of ending it: a dead container rehydrates from the last R2 snapshot, an exhausted GPU pool queues the request or continues on CPU sim, and a Durable Object eviction is invisible because session state persists in DO storage and the event log is append-only and replayable. Publish failures retry; a partial publish never mints a share page.

13. Testing

Four layers. Container-image CI builds ros2-workspace and runs a colcon plus headless-Gazebo smoke test on every image change. Orchestrator unit tests exercise the phase machine and tool dispatch in vitest/miniflare against recorded LLM fixtures. Contract tests pin both sides of the Tunnel API (DO client, FastAPI server) to a shared schema. A golden-path end-to-end run on staging scripts a full TurtleBot-maze session from prompt to published share page on every release. Security tests assert egress denial from a workspace, rejection of cross-tenant R2 access, and the absence of platform secrets inside a container.

Golden-path e2e sequence (as built, AURA-780/790)

The harness (control-plane/studio/e2e/golden-path.ts) drives a deployed Worker through the full session lifecycle. Every hop below runs against real staging infrastructure: Cloudflare Access admits the harness via a service token, the Orchestrator Durable Object replays persisted conversation history into each turn, tool calls execute in the session's ros2-workspace container, and the published artifact is asserted straight off the public studio-artifacts.aegeanai.com bucket domain.

Budget guards bound the whole flow: 30 minutes wall clock and a 50-tool-call session budget on the harness side (mirroring the Orchestrator's own MAX_TOOL_CALLS), 15 LLM steps per turn server-side, and a 120 req/min rate cap on the studio-gateway AI Gateway. State reads use the Agents SDK's own WebSocket push protocol (cf_agent_state) because no plain JSON state route exists — see control-plane/studio/e2e/README.md for the operator runbook.

14. Rollout

PhaseScopeExit criterion
0Merge this doc; Terraform the new Cloudflare resources (D1, KV, Access app, AI Gateway, Tunnel, containers); build ros2-workspace imageImage passes smoke test; studio.aegeanai.com resolves behind Access
1Internal alpha, single tenant: chat → Blueprint → CPU workspace → Gazebo → Foxglove → publishTurtleBot-maze share page produced end-to-end by the agent
2Multi-tenant beta: public signup, metering, free-tier quotas; BYO connector alpha (laptop, CPU)External user completes the golden path unassisted, on hosted and on BYO
3GPU burst tier over the Tunnel (Ray, Isaac Sim), invite-gated; BYO GPU support in the connectorGPU session brokered from a chat session; caps enforced; connector runs the image with GPU runtime
4Public launch; companion-app deploy via Workers for Platforms (annotation, visualization, analytics); Stripe in v1.5Tenant deploys a working annotation or viz app from a chat session; pricing live on metered data

All new Cloudflare resources are Terraform-managed in infra/terraform/stacks/cloudflare/ per the IaC policy; nothing is console-created.

15. Backlog plan

Per the planning policy, Jira issues are created only after this doc merges. Work lands under the capability-epic spine with a new studio label (Component when available) as the project facet: the Orchestrator DO, phase machine, and tool surface under Agent Orchestration / Control (AURA-544), along with the workspace provider interface and the BYO connector protocol; Terraform, Tunnel, containers, connector packaging, D1/KV, and observability under Platform Infrastructure (AURA-670); Access, egress, and tenancy isolation under Security (AURA-730), linked to AURA-733; the artifact and metering schemas under Data & Lakehouse (AURA-176). AURA-743 closes on the merge of this doc, with its system-architecture.mdx update requirement satisfied by the cross-reference added there.

16. What this does not cover

Deploy-to-robot is out of v1 by decision, not omission; the actuation-gating and scheduling design it needs stays in the user-plane doc. Stripe payment flows are v1.5. Fine-tuned domain-specific coding agents (the second agent type in the system architecture) plug into this platform later as alternative session-agent harnesses; nothing here precludes them, but their training and evaluation are separate work. Multi-region and Workers VPC are revisited when tenant load justifies them.

On this page