Skip to content

Commit 9b35a13

Browse files
JAORMXclaude
andauthored
Add declarative bring-your-own agent support (#191 Phase 1) (#200)
* Add declarative bring-your-own agent support (#191 Phase 1) 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 * Address review: boot canonical BYO agent, tighten MCP merge, UX - custom_agent.go: ValidateCustomAgent skips the egress_hosts gate when mcp.mode=env so the issue #191 canonical aider example passes - sandbox.go: at runtime, mcp.mode=env + hostless non-permissive profile yields an empty (gateway-only) restricted policy instead of failing egress.Resolve, so the canonical example actually boots (all external egress still blocked; proxy is the only path out) - sandbox.go: Prepare enforces env_required presence before booting the VM, failing fast with a pointer to 'bbox agents doctor' - config.go: mergeAgentOverride ignores workspace-local MCP.Mode (#2, CWE-862) and makes per-agent MCP.Enabled tighten-only (#3, CWE-862) - main.go: not-found path for declared-but-skipped agents points at 'bbox agents doctor' instead of the generic available-agents list - agents.go: TYPE column in list; provenance brackets for EnvForward and Egress profile; MISSING marker and doctor missing-env name the remedy; unknown-agent errors point at 'bbox agents list' - tests: new runtime boot test, canonical-example validation test, tighten-only MCP.Enabled test; renamed MCPModeOverride test to LocalMCPModeIgnored --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e3ffe7a commit 9b35a13

21 files changed

Lines changed: 3414 additions & 169 deletions

File tree

CLAUDE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ This project follows DDD layered architecture with dependency injection **strict
114114
2. Add the entry to `pkg/clients/builtins.go`.
115115
3. Add a Dockerfile in `images/<name>/` and a Taskfile target `image-<name>` (and include it in `image-all`).
116116

117+
### Custom (bring-your-own) agents — no Go code
118+
119+
A custom agent can be declared entirely in global config under `agents:` (no `pkg/clients/` package, no Dockerfile in this repo). `config.AgentFromOverride` (pure, `pkg/domain/config`) maps the `AgentOverride` into an `agent.Agent`; `config.ValidateCustomAgent` runs the load-time checks (the image-ref parser is injected as a closure from the composition root to keep the domain free of go-containerregistry). Manage them with `bbox agents list|inspect|doctor`.
120+
121+
- **Safer defaults than built-ins**: `env_forward` empty (forward nothing), egress profile `standard` (must declare `egress_hosts` for it or set `permissive`), MCP authz `safe-tools` when MCP is enabled.
122+
- **Universal `BBOX_*` env** (`pkg/domain/agent.BuildUniversalEnv`) is injected into *every* VM — `BBOX_AGENT_NAME`, `BBOX_WORKSPACE`, `BBOX_HOME`, `BBOX_SESSION_ID`, `BBOX_GIT_TOKEN_AVAILABLE`, `BBOX_SSH_AGENT_AVAILABLE`, plus `BBOX_MCP_URL`/`BBOX_MCP_AUTHZ_PROFILE` when MCP is active. Applied **after** forwarded host vars so it is authoritative (the env_forward allowlist can't clobber it). `BBOX_MCP_URL` uses `config.MCPEndpointPath` (`/mcp`) — the single source of truth shared by the proxy and all clients.
123+
- **`mcp.mode: env`**: enables the proxy but runs no config-file injector; the agent discovers it via `BBOX_MCP_URL`. (`mcp.mode: config` is not yet supported.)
124+
- **Security**: workspace-local `.broodbox.yaml` can **never** add a custom agent or introduce new credential paths, and can't repoint an existing agent's image/command or widen its `env_forward` — local config is tighten-only (`mergeAgentOverride`).
125+
117126
## Conventions
118127

119128
- **SPDX headers required** on every `.go` and `.yaml` file:

0 commit comments

Comments
 (0)