Host external ACP agents
Contenox speaks the Agent Client Protocol (ACP) in both directions. The editor guides cover the upward direction — contenox running as the agent your editor drives. This page covers the inverse: contenox as the client that registers, spawns, and drives another ACP agent, then hands you the same gated surface you already use for your own chains.
An agent here is an external program that speaks ACP over stdio — Claude Code
(via claude-code-acp), Goose, or a binary of your own. Contenox never installs
one: it invokes a binary you already have on PATH, or lets a runtime fetcher
(npx/uvx) pull it down. Once registered, an agent is driveable three ways:
contenox agent check— a one-shot live turn from the CLI to verify it works.- Beam — chat with it in the browser, gated by your HITL policy (below).
GET /api/agents— the read-only REST list, also rendered in the/docsOpenAPI UI.
This page assumes contenox is already on PATH. If not, do the
Quickstart first.
Register an agent
There are exactly two ways to register one, and no --transport/--env/--args
flag soup: seed from the ACP registry catalog, or give a bare command.
From the registry catalog
Browse the catalog and register an entry by id. Contenox resolves the catalog
entry for your OS/arch into a run spec — npx/uvx entries become the fetcher
invocation; a binary entry becomes the binary basename (which you must already
have on PATH).
contenox agent search # list the whole catalog
contenox agent search claude # filter by id / name / description
contenox agent add claude-acp # register it (named after the registry id)
contenox agent add goose --name my-goose # …under an alias
The catalog is cached locally next to the database (agent-registry.json); pass
--refresh on search or add to force a re-fetch.
From a bare command
Everything after -- is the argv contenox will spawn. This is the only
raw-command path.
contenox agent add local-bot -- /usr/local/bin/my-acp-agent --stdio
The name is the positional before --; the command and its arguments come
after it.
Customize later
Both forms register a JSON run spec (config_json). To change the command, args,
environment, working directory, transport, or the forwarded MCP servers, edit
that JSON directly — there is no per-field flag:
contenox agent edit my-goose # opens $EDITOR, validates on save
contenox agent edit my-goose --config-file cfg.json # or non-interactively
The CLI reference
documents every field. Provenance (whether it came from the registry or a bare
command, and which catalog entry) is system-managed and shown by agent show /
agent list, but is never part of the editable JSON.
Verify it with agent check
Right after registering, drive one live turn to confirm the agent actually answers:
contenox agent check my-goose # a plain connection check
contenox agent check claude Say hello # everything after the name is the prompt
check spawns the agent as a subprocess and runs a full
initialize → session/new → session/prompt turn against it — the same
client-host path (runtime/agenthost) the runtime uses when you chat with the
agent in Beam, not a lighter fake — and streams the reply to stdout. It then
prints the stop reason and any slash-commands the agent advertised:
Checking agent "my-goose": npx -y @acme/goose-acp
Hello! I'm connected and ready.
Turn completed (agent goose 1.4.0, stopReason=end_turn).
Agent advertises 2 command(s): /compact /review
The turn is rooted in the current directory and drives one plain-text prompt.
Agent-initiated callbacks (file system, terminal, permission requests) are
declined, so an agent that insists on them may stop early — a simple prompt
should not need any. A normal turn that produces no displayable output fails the
check rather than reporting a false success on a silent agent. Use --timeout
(default 2m) to bound a slow agent.
agent check is the user-facing twin of the make acp-host-e2e harness that
pins this path in CI — see the ACP client library
for the full verification story.
Forwarding MCP servers
An agent’s config can declare an mcp_servers allowlist: registered MCP server
names (contenox mcp list) that contenox forwards to the agent in ACP
session/new. This is the mirror of what contenox consumes when it is on the
agent side of the same exchange.
{
"transport": "stdio",
"command": "claude-code-acp",
"mcp_servers": ["filesystem", "notion"]
}
Forwarding is an explicit, per-agent consent boundary, named server by named server:
- There is deliberately no wildcard — you list each server the agent may reach, one by one.
- Forwarding a server hands the agent everything it needs to connect to it: argv for a stdio server, the URL and configured headers (which may carry auth) for an http/sse server.
- Contenox-side auth synthesis —
authToken/authEnvKey, OAuth, injected hidden params — is never translated into the forwarded payload. Forwarding the server at all is the consent; contenox does not additionally hand over its own credential machinery. - Names resolve loudly: a missing name fails the turn rather than silently shrinking the agent’s declared context. A server whose transport the agent’s advertised capabilities cannot consume is reported as not-forwarded, not silently dropped.
agent check exercises this too — it prints a Forwarding MCP servers: line and
notes any the agent could not consume — so you can confirm the allowlist before
the agent runs for real.
Drive it from Beam
Enabled agents appear in Beam:
the sidebar’s New chat with an agent chevron opens a picker listing the
native contenox chain plus every registered agent. Pick one and the session binds
to that agent — its turns stream into the transcript, its tool calls render as
cards, and any permission it requests raises the same inline
approval card your own chains do, gated by
the session’s contenox HITL policy. The session row is labelled Agent: {name}
so you can tell which sessions drove a foreign agent.
Manage the roster
contenox agent list # id, name, source, kind, enabled
contenox agent show my-goose # provenance + run command + config_json
contenox agent disable my-goose # keep it registered but hide it from the picker
contenox agent enable my-goose
contenox agent remove my-goose # (alias: rm) — removes only the local registration
remove deletes the local registration only; it never touches the binary or
package the agent would spawn. disable keeps the registration but drops the
agent from Beam’s picker.
Next steps
contenox agentCLI reference — every subcommand and config field- Beam guide — chatting with a registered agent
- MCP servers — register the servers you forward with
mcp_servers - The ACP client library — how the host path and its harnesses are built