Add declarative bring-your-own agent support (#191 Phase 1)#200
Open
JAORMX wants to merge 1 commit into
Open
Conversation
Let users run arbitrary coding agents from global config with no Go code,
no fork, and no Dockerfile in this repo — the issue's "first useful
iteration" acceptance criteria:
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` and `bbox aider` work.
Changes:
- Extend AgentOverride with description, default_env, env_required,
credentials.persist, settings entries, per-profile egress_hosts, and
mcp.mode. Add AgentFromOverride (pure config->Agent mapping) and
ValidateCustomAgent (pure load-time checks; image-ref parser injected
as a closure to keep the domain free of go-containerregistry).
- Inject universal BBOX_* env vars into every VM via
agent.BuildUniversalEnv, applied authoritatively after forwarded host
vars. BBOX_MCP_URL uses a new shared config.MCPEndpointPath ("/mcp")
constant, de-duplicating the path previously hardcoded in the proxy and
all five built-in clients.
- mcp.mode: env enables the proxy without a config-file injector; the
agent discovers it via BBOX_MCP_URL. mcp.mode: config is rejected.
- Add `bbox agents list|inspect|doctor`. inspect shows field provenance
and env names only (never values); doctor exits non-zero on invalid
config or missing required env. `bbox list` stays a shared alias.
- Safer defaults for custom agents: empty env_forward, egress profile
standard, MCP authz safe-tools.
- Security: workspace-local config can never add a custom agent or new
credential paths, repoint an existing agent's image/command, or widen
its env_forward — tighten-only (mergeAgentOverride). Validate
credential/settings paths are relative and cannot escape the home dir.
- Add a guard test pinning go-microvm's gateway IP to the literal
pkg/sandbox uses for BBOX_MCP_URL.
Deferred to follow-ups: agents import/export, OCI-embedded manifests,
mcp.mode: config, agents add/init, and trusted host-side plugins.
Implemented via an architect -> implement -> 5-axis panel review -> fix
orchestration loop.
Fixes #191
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VP887qH8BMW4PMUXBuEqGc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Phase 1 of #191 — run arbitrary coding agents from global config with no Go code, no fork, and no Dockerfile in this repo. This is the issue's "first useful iteration" acceptance criteria:
What's included
AgentOverride(pkg/domain/config):description,default_env,env_required,credentials.persist,settingsentries, per-profileegress_hosts,mcp.mode.AgentFromOverride(config→agent.Agent) andValidateCustomAgentare pure, table-tested domain functions. The image-ref parser is injected as a closure from the composition root, keepinggo-containerregistryout of the domain layer.BBOX_*env (agent.BuildUniversalEnv) injected into every VM:BBOX_AGENT_NAME,BBOX_WORKSPACE,BBOX_HOME,BBOX_SESSION_ID,BBOX_GIT_TOKEN_AVAILABLE,BBOX_SSH_AGENT_AVAILABLE, plusBBOX_MCP_URL/BBOX_MCP_AUTHZ_PROFILEwhen MCP is active. Applied after forwarded host vars so it's authoritative.BBOX_MCP_URLuses a new sharedconfig.MCPEndpointPath(/mcp) constant — de-duplicating the path previously hardcoded in the proxy and all five built-in clients.mcp.mode: env: enables the proxy without a config-file injector; the agent discovers it viaBBOX_MCP_URL. (mcp.mode: configis rejected with a clear message.)bbox agents list | inspect | doctor:inspectshows field provenance (built-in/global/workspace) and env names only, never values;doctorexits non-zero on invalid config or missing required env.bbox listremains a shared alias.Defaults & security
env_forward(forward nothing), egress profilestandard(must declare hosts or setpermissive), MCP authzsafe-tools..broodbox.yamlis tighten-only: it can never add a custom agent or new credential paths, repoint an existing agent's image/command, or widenenv_forward(subset-coverage enforcement prevents secret exfiltration). Credential/settings paths are validated relative and cannot escape the home dir.topology.GatewayIPto the literalpkg/sandboxuses forBBOX_MCP_URL, catching drift.Out of scope (deliberate follow-ups)
agents import/export, OCI-embedded manifests,mcp.mode: config,agents add/initscaffolding, and trusted host-side plugins.Verification
task fmtclean,task lint0 issues, fulltask test(race) passes.agents listshows custom agents;inspectrenders provenance +MISSINGrequired-env markers without leaking values;doctorpasses with required env set (exit 0), fails without it (exit 1), and rejectsmcp.mode: config(exit 1);bbox listunchanged.How it was built
Produced via a multi-agent orchestration loop: architect → implement → 5-axis panel review (architecture / security / correctness / api-ux / tests) → fix, iterated 3 rounds. All findings were resolved; the final state was independently re-verified and reviewed before this PR.
🤖 Generated with Claude Code