Summary
Add first-class support for bring your own AI agent/client/harness in Brood Box, so users can run and register arbitrary AI coding tools without forking this repo, adding a pkg/clients/<name> package, or maintaining an upstream Dockerfile here.
The north-star UX should be:
bbox agents import ghcr.io/acme/aider-bbox:latest
bbox agents doctor aider
bbox aider
And for simple/power-user cases:
agents:
my-harness:
image: ghcr.io/me/my-harness:latest
command: ["my-harness"]
env_forward: ["MY_HARNESS_*", "OPENAI_API_KEY"]
mcp:
mode: env
No Go code, no Brood Box fork, no custom infra package, and no built-in Dockerfile should be required for the common path.
Background / current state
Brood Box already has the right internal seam:
pkg/domain/agent.Agent is the declarative runtime spec: image, command, env forwarding, defaults, egress hosts, credential paths, settings manifest.
pkg/domain/agent.ClientEntry pairs an Agent with an optional Plugin.
pkg/domain/agent.Plugin currently supports behavior that cannot be expressed declaratively, especially:
MCPConfig() agent.MCPInjector
Seeder() credential.Seeder
- Built-ins live under
pkg/clients/<name> and expose New() agent.ClientEntry.
- The in-memory registry supports both:
- data-only agents via
Registry.Add(agent.Agent)
- full client entries via
Registry.AddEntry(agent.ClientEntry).
- Global config currently supports unknown/custom agents through
agents.<name> but only for a limited data-only subset: image, command, env, CPUs, memory, etc.
The pain point: each first-class harness currently needs custom code and often custom image wiring in this repo:
pkg/clients/claudecode
pkg/clients/codex
pkg/clients/gemini
pkg/clients/hermes
pkg/clients/opencode
images/<name>/Dockerfile
- Taskfile image targets
That does not scale to arbitrary agents like Aider, Goose, Cursor Agent CLI, custom internal harnesses, research agents, etc.
Design principle
Treat this as two layers:
- Declarative BYO agents for the common CLI path.
- Trusted behavioral clients for built-ins and SDK consumers.
Do not start with arbitrary host-side plugin loading as the normal CLI extension mechanism. Dynamic plugins introduce trust, signing, ABI/API stability, supply-chain, and host-execution concerns. The default UX should be data-driven.
Keep the current distinction internally:
- Agent = declarative VM runtime spec.
- ClientEntry = Agent + optional trusted behavior.
- Plugin = implementation detail for built-ins / SDK consumers.
User-facing docs can continue to say agent.
Proposed UX tiers
1. Run any image once
Good for experimentation without editing config:
bbox run-image ghcr.io/me/aider-bbox:latest -- aider --model gpt-5
Useful flags:
bbox run-image ghcr.io/me/aider-bbox:latest \
--name aider \
--env OPENAI_API_KEY \
--env 'AIDER_*' \
--memory 4g \
--cpus 4 \
--mcp \
--mcp-authz-profile safe-tools \
--egress-profile standard \
--allow-host api.openai.com:443 \
-- aider
This mode should be explicitly ephemeral:
- no credential persistence by default
- no settings import by default
- no custom config-file injection unless requested
- no env forwarding unless requested
2. Register durable custom agents in config
Minimal valid custom agent:
agents:
aider:
image: ghcr.io/acme/aider-bbox:latest
command: ["aider"]
Richer example:
agents:
aider:
description: "Aider coding assistant"
image: ghcr.io/acme/aider-bbox:latest
command: ["aider"]
env_forward:
- OPENAI_API_KEY
- ANTHROPIC_API_KEY
- OPENROUTER_API_KEY
- AIDER_*
env_required:
- OPENAI_API_KEY
default_env:
AIDER_YES_ALWAYS: "false"
cpus: 4
memory: 4g
tmp_size: 2g
egress_profile: standard
egress_hosts:
locked:
- name: api.openai.com
ports: [443]
standard:
- name: api.openai.com
ports: [443]
- name: github.com
ports: [443, 22]
credentials:
persist:
- .aider/
- .config/aider/
settings:
entries:
- category: settings
host_path: .aider.conf.yml
guest_path: .aider.conf.yml
kind: file
optional: true
mcp:
enabled: true
mode: env
Then users run it like a built-in:
3. Import/export reusable agent manifests
Support an agent manifest as a standalone file and, later, embedded in an OCI image.
Example manifest:
# broodbox-agent.yaml
name: aider
image: ghcr.io/acme/aider-bbox:latest
command: ["aider"]
env_forward:
- OPENAI_API_KEY
- AIDER_*
env_required:
- OPENAI_API_KEY
mcp:
mode: env
egress_profile: standard
Commands:
bbox agents import ./broodbox-agent.yaml
bbox agents import ghcr.io/acme/aider-bbox:latest
bbox agents export aider > aider.broodbox-agent.yaml
bbox agents inspect aider
bbox agents doctor aider
Optional image convention:
LABEL org.stacklok.broodbox.agent=/usr/share/broodbox/agent.yaml
COPY broodbox-agent.yaml /usr/share/broodbox/agent.yaml
Proposed CLI surface
Agent management
bbox agents list
bbox agents add NAME --image IMAGE --command COMMAND [--env ENV_PATTERN...]
bbox agents init
bbox agents inspect NAME
bbox agents doctor NAME
bbox agents import SOURCE
bbox agents export NAME
Keep bbox list as an alias for bbox agents list.
Inspect output should show
- image
- command
- env vars that will be forwarded, names only, never values
- missing required env vars
- resource defaults
- egress profile and allowed hosts
- MCP mode and authz profile
- credential paths
- settings mappings
- source of each effective field: built-in, global config, workspace config, CLI
Doctor checks should include
- config schema validity
- agent name validity
- OCI image reference parse / pullability or cache presence
- command configured; optionally command exists in image if cheap to inspect
- required env vars present
- env patterns valid; reject empty, bare
*, leading-star patterns
- egress hostnames valid; reject IP literals where policy disallows them
- MCP injection config valid
- credential/settings paths safe and relative to guest home
- workspace-local config did not attempt unsafe overrides
Universal runtime contract
For all agents, especially BYO agents, Brood Box should inject stable BBOX_* env vars:
BBOX_AGENT_NAME=aider
BBOX_WORKSPACE=/workspace
BBOX_HOME=/home/sandbox
BBOX_MCP_URL=http://192.168.127.1:4483/mcp
BBOX_MCP_AUTHZ_PROFILE=safe-tools
BBOX_SESSION_ID=...
BBOX_GIT_TOKEN_AVAILABLE=true|false
BBOX_SSH_AGENT_AVAILABLE=true|false
This gives custom harness authors a stable integration point and avoids config-file mutation for tools that can read env vars.
Generic MCP support
Current built-ins often need custom MCPInjector code because every agent has a different config file format/layout.
For BYO, prefer two generic modes:
mcp.mode: env
Only expose BBOX_MCP_URL and related env vars. The harness reads them.
mcp:
enabled: true
mode: env
mcp.mode: config
Declaratively patch a JSON/JSONC/TOML/YAML config file in the guest home:
mcp:
enabled: true
mode: config
inject:
- guest_path: .config/aider/mcp.json
format: json
merge:
mcpServers:
broodbox:
type: streamable-http
url: "${BBOX_MCP_URL}"
The generic implementation can live in infra; the config shape should remain pure domain data. Built-ins with special formats can keep custom Plugin.MCPConfig().
Declarative settings import
Expose the existing settings manifest concept to config-defined agents. Example:
settings:
entries:
- category: rules
host_path: .aider/rules
guest_path: .aider/rules
kind: directory
optional: true
- category: settings
host_path: .aider/config.json
guest_path: .aider/config.json
kind: merge-file
format: json
allow_keys:
- model
- editor
- theme
This generalizes what built-ins currently hardcode for Claude/Codex/OpenCode/Gemini/Hermes.
Declarative credential persistence
Expose credential persistence paths for custom agents, but with strong constraints:
credentials:
persist:
- .aider/
Security recommendation:
- Global config may define credential persistence for custom agents.
- Workspace-local
.broodbox.yaml should not be allowed to introduce new credential paths.
- Paths must be relative to the sandbox user home and must not escape it.
- No host-side credential seeding for custom agents by default.
Image authoring UX
Document three image paths.
Option 1: Use Brood Box base image
FROM ghcr.io/stacklok/brood-box/base:latest
RUN pip install aider-chat
USER sandbox
Option 2: Bring any compatible Linux image
Document the minimum contract the image must satisfy. For example:
- compatible with Brood Box / go-microvm boot flow
- expected sandbox user/home behavior
- shell/command available
- agent binary on PATH or explicit
command
Option 3: Self-describing image
Embed /usr/share/broodbox/agent.yaml and allow bbox agents import IMAGE.
Suggested defaults for custom agents
Custom/BYO agents should be safer than built-ins by default:
env_forward: []
egress_profile: standard
mcp:
enabled: true
authz:
profile: safe-tools
settings:
enabled: false
credentials:
persist: []
Rationale:
- no env forwarding by default avoids accidental secret exposure
safe-tools is better than full-access for unknown harnesses
- credential/settings import should be explicit
standard egress is a practical middle ground
Proposed implementation phases
Phase 1: Better data-only custom agents
Extend current agents.<name> config for unknown/custom agents to support more declarative fields, likely including:
description
default_env
env_required
tmp_size
credential_paths or credentials.persist
settings / settings manifest entries
- per-profile
egress_hosts
- generic
mcp.mode: env
- universal
BBOX_* env vars
This should build on the existing data-only custom agent path rather than requiring plugins.
Phase 2: Agent management CLI
Add:
bbox agents list
bbox agents add
bbox agents init
bbox agents inspect
bbox agents doctor
Phase 3: Generic MCP config injection
Add mcp.mode: config with declarative JSON/JSONC/TOML/YAML merge targets.
Phase 4: Import/export manifests
Support:
bbox agents import ./broodbox-agent.yaml
bbox agents export aider
Phase 5: OCI image manifests
Support:
bbox agents import ghcr.io/acme/aider-bbox:latest
by reading an embedded manifest path declared by OCI label or a well-known path.
Phase 6: Advanced trusted plugins, if still needed
For advanced behavior that cannot be data-driven:
- Keep Go SDK support via
agent.ClientEntry + Plugin.
- Consider CLI-side external drivers only later, with explicit trust boundaries.
- Prefer a signed executable driver protocol over loading arbitrary Go plugins.
Architecture constraints
Preserve strict DDD layering:
- Pure config/domain types belong in
pkg/domain/config, pkg/domain/agent, pkg/domain/settings, etc.
- Generic config-file mutation/injection implementations belong in
internal/infra.
- Sandbox orchestration belongs in
pkg/sandbox and should depend only on domain interfaces/types.
- Built-in special cases may remain in
pkg/clients/<name>.
- SDK consumers should continue to be able to construct custom
agent.ClientEntry values and pass them to a registry.
Acceptance criteria
A first useful iteration should allow this without adding Go code or a Dockerfile to this repo:
agents:
aider:
image: ghcr.io/acme/aider-bbox:latest
command: ["aider"]
env_forward:
- OPENAI_API_KEY
- AIDER_*
mcp:
mode: env
Then:
bbox agents doctor aider
bbox aider
The run should:
- boot the configured image
- run the configured command
- forward only explicitly configured env vars
- expose stable
BBOX_* env vars, including MCP URL when MCP is enabled
- preserve snapshot isolation and review behavior
- respect egress/MCP tighten-only security semantics
- require no
pkg/clients/<name> package
- require no
images/<name>/Dockerfile in this repo
Notes / open questions
- Should the richer config remain under
agents: for backward compatibility, or should we introduce a separate clients: section and normalize both internally?
- Should custom agent default egress be
standard or permissive for compatibility?
- Should BYO default MCP authz be
safe-tools even though built-ins default to full-access today?
- How much image inspection should
agents doctor do locally vs only validating config?
- What is the exact minimum image contract for
run-image / imported OCI images?
- Should workspace-local config be able to add custom agents at all, or only tighten existing/global agents? This affects trust semantics for untrusted repos.
Summary
Add first-class support for bring your own AI agent/client/harness in Brood Box, so users can run and register arbitrary AI coding tools without forking this repo, adding a
pkg/clients/<name>package, or maintaining an upstream Dockerfile here.The north-star UX should be:
And for simple/power-user cases:
No Go code, no Brood Box fork, no custom infra package, and no built-in Dockerfile should be required for the common path.
Background / current state
Brood Box already has the right internal seam:
pkg/domain/agent.Agentis the declarative runtime spec: image, command, env forwarding, defaults, egress hosts, credential paths, settings manifest.pkg/domain/agent.ClientEntrypairs anAgentwith an optionalPlugin.pkg/domain/agent.Plugincurrently supports behavior that cannot be expressed declaratively, especially:MCPConfig() agent.MCPInjectorSeeder() credential.Seederpkg/clients/<name>and exposeNew() agent.ClientEntry.Registry.Add(agent.Agent)Registry.AddEntry(agent.ClientEntry).agents.<name>but only for a limited data-only subset: image, command, env, CPUs, memory, etc.The pain point: each first-class harness currently needs custom code and often custom image wiring in this repo:
pkg/clients/claudecodepkg/clients/codexpkg/clients/geminipkg/clients/hermespkg/clients/opencodeimages/<name>/DockerfileThat does not scale to arbitrary agents like Aider, Goose, Cursor Agent CLI, custom internal harnesses, research agents, etc.
Design principle
Treat this as two layers:
Do not start with arbitrary host-side plugin loading as the normal CLI extension mechanism. Dynamic plugins introduce trust, signing, ABI/API stability, supply-chain, and host-execution concerns. The default UX should be data-driven.
Keep the current distinction internally:
User-facing docs can continue to say agent.
Proposed UX tiers
1. Run any image once
Good for experimentation without editing config:
Useful flags:
bbox run-image ghcr.io/me/aider-bbox:latest \ --name aider \ --env OPENAI_API_KEY \ --env 'AIDER_*' \ --memory 4g \ --cpus 4 \ --mcp \ --mcp-authz-profile safe-tools \ --egress-profile standard \ --allow-host api.openai.com:443 \ -- aiderThis mode should be explicitly ephemeral:
2. Register durable custom agents in config
Minimal valid custom agent:
Richer example:
Then users run it like a built-in:
3. Import/export reusable agent manifests
Support an agent manifest as a standalone file and, later, embedded in an OCI image.
Example manifest:
Commands:
Optional image convention:
Proposed CLI surface
Agent management
bbox agents list bbox agents add NAME --image IMAGE --command COMMAND [--env ENV_PATTERN...] bbox agents init bbox agents inspect NAME bbox agents doctor NAME bbox agents import SOURCE bbox agents export NAMEKeep
bbox listas an alias forbbox agents list.Inspect output should show
Doctor checks should include
*, leading-star patternsUniversal runtime contract
For all agents, especially BYO agents, Brood Box should inject stable
BBOX_*env vars:This gives custom harness authors a stable integration point and avoids config-file mutation for tools that can read env vars.
Generic MCP support
Current built-ins often need custom
MCPInjectorcode because every agent has a different config file format/layout.For BYO, prefer two generic modes:
mcp.mode: envOnly expose
BBOX_MCP_URLand related env vars. The harness reads them.mcp.mode: configDeclaratively patch a JSON/JSONC/TOML/YAML config file in the guest home:
The generic implementation can live in infra; the config shape should remain pure domain data. Built-ins with special formats can keep custom
Plugin.MCPConfig().Declarative settings import
Expose the existing settings manifest concept to config-defined agents. Example:
This generalizes what built-ins currently hardcode for Claude/Codex/OpenCode/Gemini/Hermes.
Declarative credential persistence
Expose credential persistence paths for custom agents, but with strong constraints:
Security recommendation:
.broodbox.yamlshould not be allowed to introduce new credential paths.Image authoring UX
Document three image paths.
Option 1: Use Brood Box base image
Option 2: Bring any compatible Linux image
Document the minimum contract the image must satisfy. For example:
commandOption 3: Self-describing image
Embed
/usr/share/broodbox/agent.yamland allowbbox agents import IMAGE.Suggested defaults for custom agents
Custom/BYO agents should be safer than built-ins by default:
Rationale:
safe-toolsis better thanfull-accessfor unknown harnessesstandardegress is a practical middle groundProposed implementation phases
Phase 1: Better data-only custom agents
Extend current
agents.<name>config for unknown/custom agents to support more declarative fields, likely including:descriptiondefault_envenv_requiredtmp_sizecredential_pathsorcredentials.persistsettings/ settings manifest entriesegress_hostsmcp.mode: envBBOX_*env varsThis should build on the existing data-only custom agent path rather than requiring plugins.
Phase 2: Agent management CLI
Add:
Phase 3: Generic MCP config injection
Add
mcp.mode: configwith declarative JSON/JSONC/TOML/YAML merge targets.Phase 4: Import/export manifests
Support:
bbox agents import ./broodbox-agent.yaml bbox agents export aiderPhase 5: OCI image manifests
Support:
by reading an embedded manifest path declared by OCI label or a well-known path.
Phase 6: Advanced trusted plugins, if still needed
For advanced behavior that cannot be data-driven:
agent.ClientEntry+Plugin.Architecture constraints
Preserve strict DDD layering:
pkg/domain/config,pkg/domain/agent,pkg/domain/settings, etc.internal/infra.pkg/sandboxand should depend only on domain interfaces/types.pkg/clients/<name>.agent.ClientEntryvalues and pass them to a registry.Acceptance criteria
A first useful iteration should allow this without adding Go code or a Dockerfile to this repo:
Then:
The run should:
BBOX_*env vars, including MCP URL when MCP is enabledpkg/clients/<name>packageimages/<name>/Dockerfilein this repoNotes / open questions
agents:for backward compatibility, or should we introduce a separateclients:section and normalize both internally?standardorpermissivefor compatibility?safe-toolseven though built-ins default tofull-accesstoday?agents doctordo locally vs only validating config?run-image/ imported OCI images?