Skip to content

Agent architecture — the three layers

The agent that powers the editor is built as three layers. Each layer adds exactly one kind of opinion, so you can pick the level that matches what you’re building — a bare prompt loop, the full Coframe conversion-rate-optimization agent, or your own app on top of either.

LayerPackageWhat it addsKnows about CRO?
L1@alphacro/agentThe unopinionated harness: a durable, dual-mode session over the portable host seams. Model-as-string, backends, MCP, the turn engine.No
L2@alphacro/coframe-agentThe Coframe opinions: company prompt, common tools, planning + requirements spine, sub-agent delegation, evidence wiring, Jarvis MCP.Yes
L3apps/agent-cli, apps/agent-evals, apps/editor-webThe apps. They pick a backend, a model, and a transport — and ship a UX.
┌─────────────────────────────────────────────────────────────┐
│ L3 apps agent-cli · agent-evals · editor-web │
│ pick a backend + model + transport │
├─────────────────────────────────────────────────────────────┤
│ L2 @alphacro/coframe-agent defineCoframeAgent(...) │
│ company prompt · common tools · planning/requirements │
│ spine · delegation · evidence aliases · Jarvis MCP │
├─────────────────────────────────────────────────────────────┤
│ L1 @alphacro/agent defineAgent(...) / runAgent() │
│ durable dual-mode session · backends · model-as-string │
│ · declarative MCP · the turn engine │
└─────────────────────────────────────────────────────────────┘

The unopinionated front door. defineAgent({}) knows no tools, no planning, no prompt — it is a progressive-disclosure façade over the portable host seams:

  • runAgent(opts) — run one prompt to completion (the hello world).
  • defineAgent(config) => Agent — a reusable agent; open a durable agent.session(id) and drive it with .send() (run-to-completion) or .stream() (a UI message stream).
  • Backends: memory() (the zero-config default) and filesystem({ dir }) (from the @alphacro/agent/node subpath, for a durable on-disk agent).
  • The model is a plain catalog string (e.g. "anthropic:claude-sonnet-4-6"), resolved through the same factory the Worker and CLI use, and MCP servers are declared as data.

It knows nothing about CRO. Those opinions belong to the layer above. See Stand up an agent for copy-pasteable usage.

L2 — @alphacro/coframe-agent (the company agent)

Section titled “L2 — @alphacro/coframe-agent (the company agent)”

One defineCoframeAgent(options) call bundles the Coframe opinions on top of L1, exactly as the apps used to assemble them by hand:

  • the company base prompt (COFRAME_AGENT_BASE_PROMPT),
  • the common, host-agnostic tool suite (buildCommonAgentTools),
  • the seeded planning + requirements spine (buildSessionBundle from @alphacro/agent-session),
  • sub-agent delegation,
  • tool-call-alias evidence wiring (so complete_task can cite tool calls), and
  • declarative Jarvis MCP.

It returns a Layer 1 Agent, so durability, dual-mode (.send() / .stream()), backends, and model-as-string all come from the harness unchanged. Most apps should start here — import the company agent and choose only a backend, a model, and a transport.

AppHow it consumes the agent
apps/agent-cliFully dogfoods defineCoframeAgent — an interactive Ink UI over a single company-agent session (in-memory for fake mode, filesystem for live).
apps/agent-evalsFully dogfoods defineCoframeAgent — the eval harness drives the company composition against a sandbox and scripted/scenario models.
apps/editor-webOwns its Cloudflare Durable Object runtime in-app and shares the company recipe — the planning slice (createSessionPlanningSlice) and session bundle — rather than constructing defineCoframeAgent directly.

The reason the layers split cleanly is a hard rule from AGENTS.md:

The model loop, tool registry, workspace contract, and state reducers compile and run without Cloudflare-specific symbols. The Cloudflare runtime is one adapter; a Node CLI is another.

So L1 and L2 contain no Cloudflare symbolsDurableObject, R2Bucket, WorkflowEntrypoint, and container handles live only in the runtime adapter (@alphacro/agent-runtime-cloudflare) or an app’s worker entrypoint. L1’s core is additionally Node-symbol-free: the filesystem() backend (which imports node:fs) is isolated behind the @alphacro/agent/node subpath, so importing @alphacro/agent never pulls node:fs into an edge bundle. editor-web supplies its own Cloudflare backend over the same Backend contract.

This is what lets the agent be tested against real models in a Node CLI without paying for edge cold starts on every iteration.

  • Stand up an agent — the app-developer front door, with real snippets for defineCoframeAgent, sessions, backends, models, and MCP.
  • Plugin system guide — the extension surface beneath L1/L2. This is how planning, requirements, delegation, skills, and permissions are actually built, and how you add your own capability.