Skip to content

Design Philosophy

Awaken is structured around three rules. Each is a hard line, not a guideline. Together they produce four properties most agent frameworks lack.

Rule 1 — Code is for tools; config is for prompts

Section titled “Rule 1 — Code is for tools; config is for prompts”

A tool is a Rust artefact: typed input schema, optional state writes, optional deferred-loading hooks. Tools want compile-time checks. They change rarely.

Prompts, tool descriptions, reminders, permission rules, and skill catalogs are content. They change constantly. They want a fast feedback loop.

The two categories are kept strictly separate.

LayerLives inReload trigger
Tools, plugins, schemasRust codeBuild & deploy
Agent system prompts, tool descriptionsAgentSpec via config APINext run
Permission rules (allow/deny/ask)Plugin configNext run
Reminder rules (tool patterns → messages)Plugin configNext run
Skill packages (YAML on disk)FilesystemPeriodicRefresher (opt-in via start_periodic_refresh(interval))
MCP server toolsRemote MCP servertools/list_changed notification (automatic)

Where reload is automatic the runtime does the watching. Where it is opt-in (skills) one call to start_periodic_refresh from your bootstrap turns it on — you still don’t write the watcher.

The inner loop most agent work spends time in — tweak prompt → observe — becomes a config-API round trip instead of a CI run.

Rule 2 — One config plane, one admin console

Section titled “Rule 2 — One config plane, one admin console”

/v1/config/* is the only mutation API for managed runtime configuration. Agents, models, model pools, providers, MCP servers, skills, and plugin-backed policy sections all surface through it.

The admin console is one consumer of that API. CI pipelines are another. The runtime reads from the same source the console writes to.

There is no “ops UI” sub-project, no shadow YAML in production, no out-of-band cache that drifts from the running config.

The runtime provides first-class modules for:

  • OpenTelemetry GenAI traces per phase, per tool, per LLM call.
  • A persistent trace store the admin console queries when a trace store and trace routes are enabled.
  • An eval framework with fixture replay, scoring, baseline diffing.
  • HITL via the permission gate + mailbox suspend/resume.

They plug into the runtime and server module surface instead of living as separate sidecars. Day-one projects use the same execution, config, permission, and replay surfaces as larger deployments; storage-backed features are enabled explicitly where the deployment owns the backend.


Each phase reads an immutable Snapshot and emits a typed MutationBatch. commit applies the batch atomically, even when tools ran in parallel.

Two consequences:

  • Parallel tools never corrupt state. Each typed state key declares a MergeStrategy (Exclusive, Commutative). Merges are checked at compile time.
  • Any snapshot is a time machine. Past runs replay byte-for-byte from saved state — debug incidents, regression-test, run eval over yesterday’s traffic without re-paying LLM cost.

The common alternative is mutable shared state behind locks (or forced serialisation). Both fail silently the moment two plugins touch the same field.

The same runtime is exposed through multiple wire formats:

  • AI SDK v6 for Vercel useChat()
  • AG-UI for CopilotKit (chat + generative UI + HITL)
  • A2A for agent-to-agent calls
  • MCP HTTP for JSON-RPC clients
  • ACP stdio for Agent Client Protocol hosts

Runtime emits one AgentEvent stream; protocol adapters encode for each wire format. Switching clients does not touch agent code; serving multiple does not multiply the runtime.

The common alternative is pick-one-protocol-and-port. That binds agent code to a frontend choice that may not survive next quarter.

Permission is not a UI prompt or a middleware hook. It runs in the typed ToolGate phase (a Phase enum variant in awaken-runtime-contract/src/model/phase.rs) between tool decision and execution — the runtime always enters that phase before any tool runs.

awaken-ext-permission matches each call against rules:

  • Allow — proceed.
  • Deny — short-circuit with a structured error.
  • Ask — suspend the run via mailbox, persist the question, resume on response (web UI, Slack bot, CLI — your choice).

Rules combine glob/regex on the tool name with JSON-path expressions on arguments. Rules live in config (Rule 1 — they tune live).

The common alternative is exception-throwing tools + frontend dialogs. That locks HITL into one frontend and loses suspend/resume semantics for long-running flows.

Agents emit declarative UI (A2UI components, JSON Render trees, OpenUI Lang documents) on the same AgentEvent stream as text. Protocol adapters forward to the frontend; frontends render without per-tool glue.

UI surfaces are first-class state — they have IDs, updates merge, subtrees are debuggable through the same trace store as any other tool output.

The common alternative is “tool returns JSON, frontend writes React per shape.” That binds UI iteration to frontend deploys and breaks the live-tuning loop the moment UI is involved.