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.
The layers at a glance
Section titled “The layers at a glance”| Layer | Package | What it adds | Knows about CRO? |
|---|---|---|---|
| L1 | @alphacro/agent | The unopinionated harness: a durable, dual-mode session over the portable host seams. Model-as-string, backends, MCP, the turn engine. | No |
| L2 | @alphacro/coframe-agent | The Coframe opinions: company prompt, common tools, planning + requirements spine, sub-agent delegation, evidence wiring, Jarvis MCP. | Yes |
| L3 | apps/agent-cli, apps/agent-evals, apps/editor-web | The 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 │└─────────────────────────────────────────────────────────────┘L1 — @alphacro/agent (the framework)
Section titled “L1 — @alphacro/agent (the framework)”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 durableagent.session(id)and drive it with.send()(run-to-completion) or.stream()(a UI message stream).- Backends:
memory()(the zero-config default) andfilesystem({ dir })(from the@alphacro/agent/nodesubpath, 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 (
buildSessionBundlefrom@alphacro/agent-session), - sub-agent delegation,
- tool-call-alias evidence wiring (so
complete_taskcan 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.
L3 — the apps
Section titled “L3 — the apps”| App | How it consumes the agent |
|---|---|
apps/agent-cli | Fully dogfoods defineCoframeAgent — an interactive Ink UI over a single company-agent session (in-memory for fake mode, filesystem for live). |
apps/agent-evals | Fully dogfoods defineCoframeAgent — the eval harness drives the company composition against a sandbox and scripted/scenario models. |
apps/editor-web | Owns 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 portability seam
Section titled “The portability seam”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 symbols — DurableObject, 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.
Where to go next
Section titled “Where to go next”- 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.