Oktapod Docs

Architecture

Components, the request loop, durable state, and the rules the runtime keeps. For contributors and technical readers.

This is the technical companion to How Oktapod works.

Components

Oktapod is a TypeScript monorepo. The runtime is two long-running processes, core and gateway, plus a CLI.

PathRole
apps/coreThe runtime daemon: intake, planning, policy, approvals, execution, memory, scheduler, replay, audit.
apps/gatewayThe authenticated edge: serves the Control UI, checks access keys and Tailscale identity, relays push.
apps/ctlThe oktapod CLI.
apps/uiThe Control UI (web app), built with Lit and served by the gateway.
apps/mcpThe MCP connector broker.
apps/local-runtime-connectorsSupervisor for connectors that run next to the runtime.
apps/observerThe lightweight observer for other machines.
apps/desktop-installerThe Windows and Linux setup app.
apps/landingThe public website.
apps/sharedShared Swift package for the Apple clients.
connectors/*Channel adapters: Discord, Slack, Telegram, web chat, Microsoft Teams, Google Chat, Matrix, IRC, voice.
native/ios, native/android, native/macosNative clients.
packages/contractsCanonical schemas, envelopes, and validators.
packages/sharedShared utilities.
packages/coderThe first-party coding runtime that drives Codex, Claude, and Gemini.
packages/connector-runtime-sharedHelpers between connectors and the runtime.

Only core decides. The gateway, connectors, native apps, plugins, and coding engines are input and output boundaries: they translate, authenticate, and deliver, but do not own planning, policy, or memory.

The request loop

  1. Intake. A message arrives in a canonical envelope that carries trace_id, idempotency_key, session_id, tenant_id, and request_id.
  2. Policy. Each proposed action is evaluated by its effect: target, reach, reversibility, blast radius, and risk tier. The result is a lane (silent, report, hold, or ask) and a recorded reason.
  3. Planning. A typed plan of steps with dependencies. A deterministic plan critic rejects structurally broken plans (duplicate step IDs, missing action types, invalid timeouts) before anything runs.
  4. Execution. Steps run as a dependency graph within one run. Every mutation carries an idempotency key, so retrying a completed action returns its stored outcome instead of repeating the effect. Transient failures are not stored as final answers; they can be retried.
  5. Approvals. Gated steps park durably until a person resolves them; resolution dispatches the approved run.
  6. Proactive scheduling. A single-flight scheduler tick drives schedules, queued work, media processing, embeddings, retention, and health checks.
  7. Replay and audit. Every side effect is recorded as input, decision, action, and outcome.

Every stage that uses a model resolves it through one model picker. A stage may choose no model, but the choice is recorded.

Action types

  • core.* actions are canonical runtime actions with first-party policy, state, replay, and audit.
  • tool.* actions are tool or integration entry points. A tool that routes into a core action declares its canonical_action_type in the tool registry.
  • Action identity is defined once in apps/core/src/action-taxonomy.ts.

Durable state

  • Canonical state is SQLite, with sqlite-vec for vector search. Markdown files are projections, never the source of truth.
  • Memory writes carry provenance, confidence, retention class, and policy reason. Retrieval scope is enforced while candidates are selected.
  • Growth is bounded. A daily retention pass soft-deletes expired records and hard-deletes old ones, and high-frequency writers are rate-limited at the source.
  • Media (uploads, downloads, generated files) is tracked as durable items with hashes, provenance, retention, and scheduler-owned processing and generation jobs.

Hosted edge services

Two optional hosted services exist for Google and Microsoft sign-in. The account issuer approves one installation through a short email link. The OAuth broker exchanges authorization codes and refreshes tokens with its app credentials, encrypts results to the requesting installation, and holds only ciphertext briefly. Core still owns PKCE state, connected accounts, token custody, policy, and audit. Bring-your-own OAuth clients keep the exchange and refresh local.

Rules that do not change

  1. The core loop is first-party. External projects do not orchestrate it.
  2. The runtime is a TypeScript daemon.
  3. Canonical state lives in SQLite plus sqlite-vec.
  4. Adapters and connectors stay thin input and output boundaries.
  5. Every side effect is auditable as input, decision, action, and outcome.
  6. Every mutation is idempotent and replay-safe.
  7. High-risk proactive actions require approval by default.
  8. Coding engines run through the first-party direct runtime; unsupported engines need an explicit command.