Skip to content

Architecture ​

Uranus follows a serverless, edge-first architecture built entirely on Cloudflare's infrastructure.

System Overview ​

┌──────────────────────────────────────────────────────────────────┐
│                      Cloudflare Edge Network                      │
├──────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌─────────────────┐    ┌─────────────────┐                      │
│  │   Static Assets │    │   Worker Entry   │                      │
│  │   (React SPA)   │    │   (src/worker.ts)│                      │
│  └────────┬────────┘    └────────┬─────────┘                      │
│           │                      │                                │
│           │    ┌─────────────────┼─────────────────┐              │
│           │    │                 │                 │              │
│           ▼    ▼                 ▼                 ▼              │
│  ┌──────────────────┐   ┌──────────────┐   ┌──────────────┐      │
│  │   API Routes     │   │  WebSocket   │   │    Queue     │      │
│  │  (/api/agents/*) │   │  (/agent/*)  │   │  Consumer    │      │
│  └────────┬─────────┘   └──────┬───────┘   └──────┬───────┘      │
│           │                    │                  │               │
│           └────────────────────┼──────────────────┘               │
│                                │                                  │
│                    ┌───────────▼───────────┐                      │
│                    │    Durable Object     │                      │
│                    │   (DashboardAgent)    │                      │
│                    │                       │                      │
│                    │ • WebSocket Handler   │                      │
│                    │ • State Management    │                      │
│                    │ • Alarm Scheduler     │                      │
│                    │ • API Router          │                      │
│                    └───────────┬───────────┘                      │
│                                │                                  │
│        ┌───────────────────────┼───────────────────────┐          │
│        │                       │                       │          │
│        ▼                       ▼                       ▼          │
│  ┌──────────┐           ┌──────────┐           ┌──────────┐      │
│  │    D1    │           │    R2    │           │ Vectorize│      │
│  │ Database │           │  Storage │           │ Embeddings│     │
│  └──────────┘           └──────────┘           └──────────┘      │
│                                                                   │
└──────────────────────────────────────────────────────────────────┘

Autonomy loop ​

Beyond serving chat requests, each DashboardAgent participates in a self-maintenance loop driven by three daily crons and a runtime trigger. This is what makes the agent a long-running operator rather than a request handler.

                  ┌────────────────────────────────────┐
                  │     User input  /  Gateway event    │
                  └──────────────────┬─────────────────┘
                                     │
                  ┌──────────────────▼─────────────────┐
                  │    DashboardAgent.runAgenticLoop    │
                  │                                     │
                  │  ┌────────────┐    ┌─────────────┐  │
                  │  │ Tool calls │ ←→ │ Memory L1-3 │  │
                  │  └────────────┘    └─────────────┘  │
                  └────────┬─────────────────┬──────────┘
                           │                 │
              writes ↓     │                 │  reads ↑
                           ▼                 │
                  ┌──────────────────────────┴──────┐
                  │  chat_messages, agent_state,     │
                  │  memory_embeddings, Vectorize    │
                  └──────────────────────────────────┘
                           ▲                 ▲
                           │                 │
            ┌──────────────┴──┐    ┌─────────┴────────────┐
            │ Reflection 03:00 │    │ Consolidation 04:00  │
            │ glm-4.7-flash    │    │ cluster + merge +     │
            │ writes:           │    │ supersede + decay     │
            │ • observations    │    └──────────────────────┘
            │ • plan            │
            │ • memory:reflection:*  ┌──────────────────────┐
            │ • draft workflows ────►│  workflows (drafts)  │
            └───────┬───────────┘    └──────────────────────┘
                    │
                    ▼
            ┌──────────────────┐    ┌──────────────────────┐
            │ Reindex 05:00     │    │ error_spike trigger  │
            │ embed changed     │    │ (>5 failures / 10min)│
            │ workflows         │    └─────────┬────────────┘
            └──────────────────┘              ▼
                                    ad-hoc reflection

Each cron is auto-seeded on the agent's first wake. None require manual setup; the schedules table gets the rows via INSERT OR IGNORE from inside alarm().

See Goals & Reflection, Agent Memory, and Scheduling for details.

Inside one turn ​

A chat turn through runAgenticLoop touches a handful of small modules around index.ts, each with one job:

StepModuleWhat happens
Route toolsjev-tools.tsthe Jev decision model picks which tool categories to load; regex triggers are the fallback
Build the promptindex.ts, tasks.ts, compaction.tsstable blocks (identity, tools, skills) + volatile tail: open tasks, working notes, clock, context budget. History = protected head + overlays + verbatim tail
Retrieveknowledge.tsif Jev says the message needs documents: fused vector + keyword (+ AI Search) search, scoped to the tenant → agent → contact, reranked
Recallmemory.tsfused memory recall (vector + FTS + exact key)
Run toolsturn-checkpoint.tsafter every tool round the turn's progress is checkpointed in DO storage, so an eviction mid-turn resumes instead of re-running
After the replytasks.ts, memory.tsJev auto-closes finished tasks; new memories pass the write-time verifier before they are stored

Every Jev-backed step has a non-partner fallback and is gated by the data-flow policy, which is itself keyed on the agent's tenant.

Core Components ​

Worker Entry Point ​

The main src/worker.ts handles all incoming requests:

typescript
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    // Route handling
    // - Static assets (from Vite build)
    // - API routes (/api/*)
    // - WebSocket connections (/agent/*)
  },

  async queue(batch: MessageBatch, env: Env) {
    // Async workflow execution
  }
}

Durable Objects ​

Each agent is a separate DashboardAgent Durable Object instance:

typescript
export class DashboardAgent implements DurableObject {
  // Persistent state
  private state: DurableObjectState;

  // Handle HTTP requests
  async fetch(request: Request): Promise<Response>;

  // Handle WebSocket messages
  async webSocketMessage(ws: WebSocket, message: string);

  // Execute scheduled tasks
  async alarm(): Promise<void>;
}

Key Properties:

  • Isolation - Each agent has its own instance
  • State - Persistent storage via this.state.storage
  • Alarms - Built-in scheduling mechanism
  • WebSockets - Native real-time support

Database Layer ​

D1 (SQLite) stores all persistent data:

TablePurpose
agentsAgent registry
agent_settingsPer-agent configuration
workflowsVisual workflow definitions
schedulesCron and one-time tasks
chat_messagesConversation history
browser_sessionsBrowser automation sessions
contactsContact directory
data_sourcesRAG source files

Storage Layer ​

R2 handles file storage:

  • Uploaded documents for RAG
  • Browser screenshots
  • Workflow artifacts

Vector Database ​

Vectorize enables semantic search:

  • Document embeddings
  • RAG query matching
  • Content similarity search

Request Flow ​

API Request ​

Client Request
     │
     ▼
┌─────────────┐
│   Worker    │
│  (Routing)  │
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│   Pages     │────▶│  Durable    │
│  Functions  │     │   Object    │
└─────────────┘     └──────┬──────┘
                           │
                           ▼
                    ┌─────────────┐
                    │     D1      │
                    │  Database   │
                    └─────────────┘

WebSocket Connection ​

Client WebSocket
     │
     ▼
┌─────────────┐
│   Worker    │
│  (Upgrade)  │
└──────┬──────┘
       │
       ▼
┌─────────────────────────┐
│     Durable Object      │
│                         │
│  • Accept connection    │
│  • Add to client set    │
│  • Handle messages      │
│  • Broadcast updates    │
└─────────────────────────┘

Scheduled Task ​

┌─────────────────────────┐
│     Durable Object      │
│                         │
│  alarm() triggered      │
│         │               │
│         ▼               │
│  ┌─────────────┐        │
│  │ Get pending │        │
│  │  schedules  │        │
│  └──────┬──────┘        │
│         │               │
│         ▼               │
│  ┌─────────────┐        │
│  │  Execute    │        │
│  │  workflow   │        │
│  └──────┬──────┘        │
│         │               │
│         ▼               │
│  ┌─────────────┐        │
│  │ Update next │        │
│  │  run time   │        │
│  └─────────────┘        │
└─────────────────────────┘

Multi-Tenancy Model ​

Each agent operates in isolation:

┌─────────────────────────────────────────────┐
│              Cloudflare Workers              │
├──────────────┬──────────────┬───────────────┤
│   Agent A    │   Agent B    │   Agent C     │
│              │              │               │
│ ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐  │
│ │ Durable  │ │ │ Durable  │ │ │ Durable  │  │
│ │ Object   │ │ │ Object   │ │ │ Object   │  │
│ └──────────┘ │ └──────────┘ │ └──────────┘  │
│      │       │      │       │      │        │
│      ▼       │      ▼       │      ▼        │
│  ┌───────┐   │  ┌───────┐   │  ┌───────┐   │
│  │State A│   │  │State B│   │  │State C│   │
│  └───────┘   │  └───────┘   │  └───────┘   │
└──────────────┴──────────────┴───────────────┘
                      │
                      ▼
        ┌─────────────────────────┐
        │     Shared D1 Database   │
        │                          │
        │  WHERE agent_id = ?      │
        └─────────────────────────┘

Tenants ​

Above the agent sits the tenant (tenants table, agents.tenant_id) — the customer that owns one or more agents. The tenant id is whatever the product that manages it uses (for OAC it is the business id), and products keep the registry current through the product-neutral internal platform API; Uranus never reads a product's own database.

Three things key on the tenant:

  • Knowledge scope — a search sees this agent's documents plus documents other agents of the same tenant have marked visibility = business; never another tenant's.
  • Task memory — tasks carry the business id alongside the conversation and contact.
  • Policy — tenants.partner_ai_consent_at decides whether customer-facing conversations may use partner models (Jev, Agent Memory).

Security Architecture ​

Access Control Layers ​

  1. Cloudflare Access (Optional)

    • JWT validation
    • Identity provider integration
  2. Email-Based Access

    • Role-based permissions (owner, admin, viewer)
    • Per-agent access control
  3. Agent Isolation

    • Data scoped by agent_id
    • Separate Durable Object instances

Authentication Flow ​

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Client    │────▶│   Worker    │────▶│   Durable   │
│   Request   │     │   (Auth)    │     │   Object    │
└─────────────┘     └──────┬──────┘     └─────────────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
              ▼            ▼            ▼
        ┌─────────┐  ┌─────────┐  ┌─────────┐
        │   CF    │  │  Email  │  │  Agent  │
        │ Access  │  │  Check  │  │  Access │
        └─────────┘  └─────────┘  └─────────┘

Technology Choices ​

ComponentTechnologyRationale
RuntimeCloudflare WorkersEdge deployment, low latency
StateDurable ObjectsStateful compute, WebSocket support
DatabaseD1 (SQLite)Edge-native, SQL interface
StorageR2S3-compatible, no egress fees
VectorsVectorizeNative integration, fast similarity search
AIWorkers AIEdge inference, multiple models
FrontendReact + ViteModern DX, fast builds
UIRadix + TailwindAccessible, customizable