# How is the assistant architected?

> Open-source personal assistants — a good answer covers: Agent loop and runtime; frontend/backend split; main packages; how a user request flows to an action.

Canonical page: https://llms-technical-reviews.com/personal-assistants/q/architecture/

## Verdict

Both published assistants split a web API from the agent loop, but they put the loop in different places.

[OpenBot](/p/openbot/) runs the loop inside its Hono server through CopilotKit's `CopilotRuntime` in Intelligence mode. Built-in Bots run in-process as `BuiltInAgent`; any other AG-UI server (LangGraph, Mastra, Pydantic AI and more) plugs in as an `HttpAgent`. Every browser and file action then passes through one `ComputerGateway`, which resolves the target, checks policy and writes an audit row before acting. Threads and learning live in CopilotKit Intelligence, an external service.

[Rakazo](/p/rakazo/) keeps the API thin. `threads.send` writes a queued run and enqueues a Graphile job; a separate worker leases the run and drives the Pi agent runtime from a large `executor.ts`. All state, including the job queue and realtime fanout, sits in Postgres, and every backend (runtime, sandbox, connectors, memory) is an `adapter-kit` interface.

Choose OpenBot if you already build agents in several frameworks and want one governed front door for them. Choose Rakazo if you want one self-contained stack where runs are durable background jobs that survive restarts and can wait for approval or a takeover.

More projects in this category are being researched.

## Per-project answers

### CopilotKit/OpenBot (answered)

**Agent loop and runtime.** The runtime is built on `@copilotkit/runtime/v2` in Intelligence mode (`server/src/copilot.ts:52-62`). The server mounts a CopilotRuntime via Hono that drives agents over the AG-UI protocol. Built-in agents (the 13 shipped coworkers) run as `BuiltInAgent` instances; external agents are `HttpAgent` instances — anything that speaks AG-UI (LangGraph, Mastra, CrewAI, Pydantic AI, Google ADK, or hand-written servers) works without adapters. The runtime is always in Intelligence mode because CopilotKit Intelligence is required for durable threads, memory, and learning.

**Frontend/backend split.** The browser app (`app/`) is a React application built with TanStack Router (`app/src/router.tsx:1-8`). It communicates with the server via TanStack Query (React Query). The server (`server/`) is a Hono app running on Bun (`server/src/app.ts`). Both are colocated in the monorepo and share the `shared/` package for types. The frontend renders the AG-UI stream and manages sign-in; the server handles all agent orchestration, policy, memory, and data.

**Main packages.** The monorepo at `/work/project/package.json` declares workspaces: `app`, `server`, `worker`. Thirteen `agent-*` directories each implement one agent framework adapter (agent-mastra, agent-langgraph, agent-crewai, agent-pydantic-ai, agent-adk, agent-ag2, agent-agno, agent-langroid, agent-llamaindex, agent-strands, agent-claude-sdk, agent-bot, agent-computer). The `desktop/` and `mobile/` directories hold Tauri desktop and mobile builds. `supervisor/` manages per-Bot Docker containers. `shared/` contains model provider specs, bot prompts, and utilities.

**Request flow.** A user types in the browser → the AG-UI stream arrives at the server → the runtime resolves the target agent via `ActorAgentResolver` (`server/src/agents/agent-resolver.ts`) → the agent's prompt is assembled with standing role, memory and learning injected as system messages → the agent runs against its provider (OpenAI/Anthropic/Google) → every tool call the agent makes passes through the **gateway** (`server/src/computer/gateway.ts:1-15`), which: (1) resolves snapshot refs on the server, never from what the model claimed; (2) evaluates the action policy (`server/src/computer/policy.ts`); (3) passes through the approvals gate for human-in-the-loop; (4) records every action in the audit trail — then and only then acts.

> **Editor's note.** Correction: the server runs Hono on Bun, not Elysia (see `server/package.json`, `server/src/app.ts`). Desktop is Tauri, but mobile is an Expo app, not Tauri. There are 15 `agent-*` packages, including `agent-microsoft` and `agent-langgraph-agui`.

Citations: [server/src/copilot.ts:52-62](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/server/src/copilot.ts#L52-L62) · [server/src/computer/gateway.ts:1-15](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/server/src/computer/gateway.ts#L1-L15) · [app/src/router.tsx:1-8](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/app/src/router.tsx#L1-L8) · [app/src/main.tsx:1-22](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/app/src/main.tsx#L1-L22) · [package.json:1-44](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/package.json#L1-L44) · [server/src/computer/policy.ts:1-35](https://github.com/CopilotKit/OpenBot/blob/f4bc60bf9b12c65eb3d7640173f1b3432f6b2a60/server/src/computer/policy.ts#L1-L35)

### elie222/rakazo (answered)

**Architecture overview.** Rakazo is structured as a monorepo (packages/ for domain logic, apps/ for deployable surfaces) built in TypeScript. The backend is two processes: a **Hono/oRPC API server** (`apps/api/src/app.ts`) that handles HTTP requests, authentication (Better Auth), WebSocket realtime fanout, and RPC endpoints, and a **Graphile Worker** (`apps/worker/src/index.ts`) that runs the actual agent loops as background jobs. The API enqueues run jobs; the worker picks them up and calls the executor.

**Agent loop and runtime.** The core execution lives in `packages/adapters/src/executor.ts` in `createRunExecutor()`. The exported `continueRun()` method (line 3166) leases the run from Postgres, sets up a computer execution lease, resolves the model credential, builds the system prompt, assembles conversation history (including compacted summaries and semantic recall), and calls `deps.runtime.run()` (line 6134). The runtime is either the **Pi agent runtime** (`PiAgentRuntime`, which uses `@earendil-works/pi-agent-core` for tool-calling LLM loops) or a **ScriptedAgentRuntime** for deterministic replay. The Pi runtime (`packages/adapters/src/pi-runtime.ts`) orchestrates the model stream, tool execution, and approval pauses.

**Frontend/backend split.** The three frontends (web React/Electron via `apps/web/`, and Expo mobile via `apps/mobile/`) are pure clients of the API. The web app uses shadcn/ui components from `packages/ui-web` and semantic tokens from `@rakazo/ui-tokens`. Desktop Electron hosts the web UI with added native setup/sandbox management. Mobile is native-first with Expo Router and StyleSheet, diverging only where native patterns are stronger.

**User request flow.** A user sends a message via the web/mobile composer → API RPC handler (`apps/api/src/router.ts` enqueues a run via `runContinueJob`) → Graphile Worker picks up the job → `continueRun()` in `executor.ts` leases the run, resolves the bot's model and tools, and calls `PiAgentRuntime.run()` → the LLM streams tokens and tool calls → results are persisted as `MessageBlock` rows and fanned out via Postgres realtime to the frontend.


Citations: [apps/worker/src/index.ts:60-90](https://github.com/elie222/rakazo/blob/4cdf3e23315c2633b6b3fde8977f197b986f06fa/apps/worker/src/index.ts#L60-L90) · [apps/api/src/app.ts:1-100](https://github.com/elie222/rakazo/blob/4cdf3e23315c2633b6b3fde8977f197b986f06fa/apps/api/src/app.ts#L1-L100) · [packages/adapters/src/executor.ts:2897-2970](https://github.com/elie222/rakazo/blob/4cdf3e23315c2633b6b3fde8977f197b986f06fa/packages/adapters/src/executor.ts#L2897-L2970) · [packages/adapters/src/executor.ts:3166-3245](https://github.com/elie222/rakazo/blob/4cdf3e23315c2633b6b3fde8977f197b986f06fa/packages/adapters/src/executor.ts#L3166-L3245) · [packages/adapters/src/executor.ts:6134-6195](https://github.com/elie222/rakazo/blob/4cdf3e23315c2633b6b3fde8977f197b986f06fa/packages/adapters/src/executor.ts#L6134-L6195)
