Managoat is the hosted Fountain. Fountain is the open-source engine, and its name is on the CLI, the API, the SDK and this manual. Everything here applies to Managoat unless a page says it is for a self-hosted server.
OpenClaw (Agent Client Protocol)
OpenClaw is a self-hosted personal assistant. It fronts a set of chat surfaces, which include Telegram, Discord, Slack, Signal and iMessage. It routes them to coding harnesses over the Agent Client Protocol, ACP.
Fountain already speaks ACP as an agent, through fountain acp. Read
Editors. So OpenClaw can drive a Fountain agent the same way it
drives Claude Code or Codex. You talk to it from a chat channel, and the turn
runs in a Fountain sandbox.
There is nothing new to build. OpenClaw is an ACP client, and fountain acp
is an ACP agent. Its acpx plugin can point at any custom command that
speaks ACP over stdio. So the integration is a config block, and not code.
OpenClaw (acpx) ──spawns──▶ fountain acp ──HTTPS──▶ Fountain ──ACP──▶ sandbox
(a chat channel) (ACP over stdio) (the agent)
At a glance
| Direction | Inbound. OpenClaw drives Fountain. |
| Talks over | fountain acp, through OpenClaw's acpx plugin. |
| Configured on | The OpenClaw host. |
| Credential | Whatever fountain auth login saved there. |
| Needs | Node 22.22.3 or newer. Also 24.15+ or 25.9+. |
| Operator setup | None. The configuration is client-side. |
What this is, and is not
It is a chat front-end for a remote conversation. OpenClaw handles the channel, which is a Telegram thread or a Discord room. Fountain runs the agent in a sandbox, on a checkout that the sandbox made, on a machine that is not the one OpenClaw runs on.
The reply streams back to the channel over ACP. OpenClaw delivers the agent's message chunks to the chat as they arrive, so there is no publish tool and no extra wiring.
It is not a way for the agent to touch OpenClaw's host, or the files on
it. The adapter declares no filesystem access and no terminal access. The
paths a tool call reports are paths in the sandbox, and they travel under
_meta.fountain.sandboxLocations, and not as locations you can click. For a
chat surface that is a clean fit and not a caveat. There is no local project
to confuse them with.
Three reasons to reach for this, and not for a harness that OpenClaw hosts locally.
- The work outlives the channel. Close the chat mid-turn, and the turn continues. Reopen it, and the server replays the transcript.
- The unit is a Fountain agent. That is an environment, vault overrides, skills, MCP servers and inference credentials, none of which touch the OpenClaw host.
- The same conversation is open in the Fountain conversations app, for you or for a teammate, while it runs from the channel.
Setup
OpenClaw runs on Node, and needs Node ≥ 22.22.3, or ≥ 24.15, or ≥ 25.9.
-
Install the Fountain CLI on the OpenClaw host, and log in.
brew install BinaryBourbon/tap/fountainfountain auth loginFor a self-hosted instance, point at it first. The CLI defaults to the hosted one.
FOUNTAIN_BASE_URL=https://fountain.example.com fountain auth loginOpenClaw spawns
fountain acpas a child process, and that process inherits the environment. So the session authenticates with the credentials thatfountain auth loginsaved. No key goes into OpenClaw's config. -
Install the ACP backend plugin, and turn it on.
openclaw plugins install @openclaw/acpxopenclaw config set plugins.entries.acpx.enabled true -
Register Fountain as a custom ACP agent. Choose an agent, and
fountain agent listshows yours. One entry names one agent, so add one entry for each agent you want to reach.plugins: {entries: {acpx: {enabled: true,config: {agents: {// the id you spawn/bind, mapped to the command OpenClaw runsfountain: { command: "fountain", args: ["acp", "--agent", "researcher"] }},// the agent's own policy runs the turn; nobody has measured an// `ask` policy through acpx yet (see Limits)permissionMode: "approve-all"}}}} -
Give OpenClaw an agent of its own that runs on that entry. The block above is acpx's harness alias. OpenClaw's routes, its
sessions_spawnand its channel bindings address an OpenClaw agent id.runtime.type: "acp"ties the two together. The same name in both places keeps it readable.acp: { enabled: true, backend: "acpx" },agents: {list: [{ id: "fountain",runtime: { type: "acp",acp: { agent: "fountain", backend: "acpx", mode: "persistent" } } }]}mode: "persistent"matters on OpenClaw ≤ 2026.7.1. Read the two-conversations note under Limits. If you setacp.allowedAgents, add"fountain"to it. An empty list means no restriction.The 2026.8 beta keys agents by id, as
agents.entries.fountain = { runtime: … }, and not byagents.list[].openclaw doctor --fixmigrates a config in the list style. -
Spawn it from a channel, or bind a channel to it.
/acp spawn fountain// pin a Discord channel to this agentbindings: [{ type: "acp", agentId: "fountain",match: { channel: "discord", peer: { kind: "channel", id: "…" } } }]A bound channel goes straight to the harness, and no OpenClaw model takes part. The other two front doors go through OpenClaw's own model first, which then delegates. Those are
sessions_spawn(runtime: "acp", agentId: "fountain")from a turn, andopenclaw agent --agent fountain. Both need OpenClaw's model provider configured, and the harness never does.To bind a thread, you also need the channel's thread bindings on. That is
session.threadBindings, and the setting for each adapter, such aschannels.discord.threadBindings.spawnSessions. OpenClaw's ACP agents page holds the detail for each channel.
A secret for one entry
--vault <name-or-id> attaches a vault to each
conversation the entry opens. Vault values override the agent's environment.
So a secret that belongs to this entry goes here. An identity the agent
posts under is one example, and a token scoped to one channel is another.
fountain: { command: "fountain", args: ["acp", "--agent", "researcher", "--vault", "researcher-identity"] }
The difference matters as soon as you have two entries. Each agent attached to an environment shares it. A vault attaches to one conversation, so two entries stay apart even when they point at the same agent.
An environment for one entry
--environment <name-or-id> provisions each conversation the entry opens from
that environment, and not from the agent's own.
Use it when one agent config must run under several baselines. The same
"engineer" then runs against a fountain environment in one entry and a
buzz environment in another, and you duplicate no agent. The vault, if there
is one, still wins on a key collision. An agent can also restrict which
environments can stand in for its own, with allowed_environment_ids.
What you get
| ACP | What happens |
|---|---|
initialize |
The capability handshake. Protocol version 1. |
authenticate |
Uses the credentials that fountain auth login saved on the host. Fountain skips it when you are already logged in. |
session/new |
Creates a conversation for the agent you configured. |
session/prompt |
Runs a turn. Messages, thoughts and tool calls stream back to the channel as they happen. |
session/cancel |
/acp cancel interrupts the turn that runs. |
session/load |
Replays the conversation when you resume a session. |
session/set_config_option |
Accepted, and not applied. At each spawn OpenClaw pushes the model its brain chose, and a thinking level it derives from that. We verified this on 2026.7.1 and on 2026.8.1-beta.2. A Fountain agent carries its model on the agent, so Fountain acknowledges the push and ignores it. The reply's _meta.fountain.applied: false says so. |
Limits, stated rather than discovered
-
No access to the files on the OpenClaw host, as above.
-
One identity for each host. OpenClaw is single-user and self-hosted, so each session authenticates as the host's Fountain login. This integration gives you no Fountain identity for each channel user.
-
We have not measured a permission prompt in a channel. Fountain forwards
session/request_permissionto an ACP client (#708), and the setup above keepspermissionMode: "approve-all"because nobody has driven anaskpolicy through OpenClaw yet. An unanswered prompt blocks the tool for 5 minutes, and Fountain then refuses it. Leave the default until somebody measures it. -
The model, and the thinking level, belong to the Fountain agent. Fountain accepts and ignores OpenClaw's
--model, themodelandthinkingonsessions_spawn, and the/acpmodel controls. A Fountain agent carries its model on the agent, and each conversation it runs shares it. Change it there. OpenClaw's own docs say the same for any harness withoutsession/set_model. -
On OpenClaw ≤ 2026.7.1, with acpx 0.11, a one-shot spawn opens two conversations and uses one. OpenClaw ensured the acpx session twice, once when it initialised the spawn and again when the turn ran. In
oneshotmode acpx answered each with a freshsession/new. On Fountain that was two conversations for each spawn, each with a sandbox. Nobody prompted the first, and it satpendinguntil the idle reaper parked it.We re-ran it on 2026.8.1-beta.2, with acpx 0.13, and it no longer happens. There is one
session/newfor each spawn. We reported it upstream as openclaw#124852 and acpx#504. On the older versions,mode: "persistent", as in Setup, reuses its record. It then pays that cost once for each channel thread, and not once for each message. -
A reclaimed sandbox loses the agent's memory. If Fountain reclaimed a conversation's sandbox while you were away, a resume still replays the full transcript. The agent itself does not remember it (#649).
Verification
The ACP path here is the one that the Editors integration uses. We proved it from start to finish against production.
The spawn was identical to acpx's, fountain acp --agent <id>. It inherited
the host environment, and spoke line-delimited JSON-RPC 2.0 over stdio.
It completed initialize, then session/new, then session/prompt. It ran
the turn in a real sandbox. It streamed the agent's reply back as
agent_message_chunk updates, with a real stop reason. That is exactly what
acpx does when it spawns the command above.
The full gateway round trip is proven too. OpenClaw's own brain runs
openclaw agent, which calls
sessions_spawn(runtime: "acp", agentId: "fountain"), which reaches acpx,
then fountain acp, then the sandbox. The gateway relays the reply back.
We ran that against the real acpx, at 0.11.2 and 0.13.0, and OpenClaw, at
2026.7.1 and 2026.8.1-beta.2. The brain pushed its model and a thinking
level at the harness on the way. That is the case that used to abort the turn
(#759,
#760).
When you test through openclaw agent, or with a prompt that must delegate,
check that the harness truly ran. OpenClaw's own model will happily answer a
"reply with X" prompt itself, and report success. The tell is a
sessions_spawn call in the tool summary, and a new conversation on the
Fountain agent. From the Fountain side, fountain conv list shows it, with
the turn.
If a session does not start, look at stderr. fountain acp writes the
protocol to stdout and everything else to stderr. OpenClaw's acpx log
shows that. /acp doctor reports the backend's health.
To run the command by hand is a fair diagnostic. It waits for JSON-RPC on stdin, which tells you that the process starts and finds its credentials.
fountain acp --agent researcher --log-level debug
| Message | Meaning |
|---|---|
no Fountain agent configured |
The entry has no --agent. |
agent "x" runs the … runtime, which does not speak ACP |
All four runtimes speak ACP. This names a conversation whose runtime column holds a name that no adapter covers. |
credentials for … were rejected |
Run fountain auth login on the host. The message names the instance it tried. |
could not resolve agent "x" on … |
The wrong name, or the right name on a different instance. |
How it works
Two ADRs cover the design. 0014 made Fountain an ACP client of the coding agents it runs in sandboxes. 0015 makes it an ACP agent for any ACP client, such as an editor, Buzz, or OpenClaw.
Together they make Fountain a proxy. The same block vocabulary arrives from a sandbox on one side and leaves for the client on the other. So the adapter forwards an update and translates nothing. OpenClaw is one more client on that far side. Read the 2026-08-16 addendum to 0015.
Related
fountain acp, the protocol surface in full.- Editors, the same adapter from an editor.
- Plug into Fountain.