Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ secrets/
Thumbs.db

# CI artifacts and tooling that the image doesn't need
.hermit/
.cache/
coverage/
dist/
Expand Down
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ members = [
"crates/buzz-dev-mcp",
"crates/buzz-voice",
"crates/buzz-backend-kubernetes",
"crates/buzz-backend-fly",
"examples/countdown-bot",
]
exclude = ["desktop/src-tauri"]
Expand Down
49 changes: 49 additions & 0 deletions Dockerfile.fly-agent
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# syntax=docker/dockerfile:1.7
# Buzz cloud-agent image: the pinned Sprig runtime plus a pinned bridge for
# remote Streamable HTTP/SSE MCP servers.
FROM rust:1.95-alpine3.22@sha256:064dfc925d68d1a63f4fd2871bd7dc6e6ea56692989a487185855d62885d90aa AS builder

RUN apk add --no-cache \
build-base \
cmake \
git \
musl-dev \
openssl-dev \
openssl-libs-static \
perl \
pkgconf \
protoc
WORKDIR /build
COPY . .
RUN cargo build --locked --profile sprig -p sprig \
&& strip target/sprig/sprig

FROM alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce

# mcp-remote is pinned: cloud agents must not execute the newest npm package
# merely because a Machine restarted. Update this version through the normal
# image review and rollout path.
RUN apk add --no-cache bash ca-certificates curl git nodejs npm su-exec \
&& npm install --global --ignore-scripts mcp-remote@0.1.38 \
&& npm cache clean --force \
&& adduser -D -h /home/agent agent \
&& install -d -o agent -g agent /workspace /home/agent \
&& git config --system gpg.format x509 \
&& git config --system gpg.x509.program /usr/local/bin/git-sign-nostr \
&& git config --system commit.gpgSign true \
&& git config --system tag.gpgSign true

COPY --from=builder --chmod=0755 /build/target/sprig/sprig /usr/local/bin/sprig
COPY --chmod=0755 scripts/sprig-entrypoint.sh /usr/local/bin/sprig-entrypoint
COPY --chmod=0755 scripts/fly-agent-entrypoint.sh /usr/local/bin/fly-agent-entrypoint
RUN for name in \
buzz-acp buzz-agent buzz-dev-mcp rg tree buzz \
git-credential-nostr git-sign-nostr; do \
ln -s sprig "/usr/local/bin/$name"; \
done

ENV HOME=/home/agent \
MCP_REMOTE_CONFIG_DIR=/home/agent/.mcp-auth \
PATH=/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin
WORKDIR /home/agent
ENTRYPOINT ["/usr/local/bin/fly-agent-entrypoint"]
37 changes: 37 additions & 0 deletions crates/buzz-acp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ All configuration is via environment variables (or CLI flags — every env var h
| `BUZZ_ACP_AGENT_COMMAND` | no | `goose` | Agent binary to spawn. |
| `BUZZ_ACP_AGENT_ARGS` | no | `acp` | Agent arguments (comma-separated). |
| `BUZZ_ACP_MCP_COMMAND` | no | `""` (empty) | Path to an optional MCP server binary to provide to the agent subprocess. |
| `BUZZ_ACP_MCP_SERVERS` | no | — | JSON array of additional stdio MCP servers. Supports `name`, `command`, `args`, literal `env`, `inherit_env` names resolved from the harness environment, and optional exact `allowed_tools`. Maximum 16 total including `BUZZ_ACP_MCP_COMMAND`. |
| `BUZZ_ACP_IDLE_TIMEOUT` | no | `620` | Idle timeout: max seconds of silence before cancelling a turn. Resets on any agent stdout activity. |
| `BUZZ_ACP_MAX_TURN_DURATION` | no | `7200` | Absolute wall-clock cap per turn (safety valve). |
| `BUZZ_API_TOKEN` | no | — | API token (required if relay enforces token auth). |
Expand All @@ -119,6 +120,42 @@ All configuration is via environment variables (or CLI flags — every env var h

**Legacy env vars:** `BUZZ_ACP_PRIVATE_KEY`, `BUZZ_ACP_API_TOKEN`, and `BUZZ_ACP_TURN_TIMEOUT` (replaced by `BUZZ_ACP_IDLE_TIMEOUT`) are still accepted as fallbacks.

### Additional MCP servers

`BUZZ_ACP_MCP_SERVERS` lets one agent attach multiple account-scoped MCP
servers without rebuilding `buzz-acp`. Keep credential values in the process
environment and name them through `inherit_env`; the harness resolves those
values only when it starts the corresponding child process.

```bash
export CRM_AUTH_HEADER='Bearer account-specific-token'
export BUZZ_ACP_MCP_SERVERS='[
{
"name": "crm",
"command": "mcp-remote",
"args": [
"https://crm.example/mcp",
"--header", "Authorization:${CRM_AUTH_HEADER}",
"--transport", "http-only"
],
"inherit_env": ["CRM_AUTH_HEADER"],
"allowed_tools": ["search_contacts", "create_note"]
},
{
"name": "local_reporting",
"command": "/opt/mcp/reporting-server",
"args": ["--read-only"]
}
]'
```

The server command must already exist in the agent image or host. Remote HTTP
connections therefore use a pinned proxy such as `mcp-remote` only when that
proxy is part of the trusted image; avoid pulling an unpinned package at agent
startup. When `allowed_tools` is non-empty, Buzz Agent exposes only those exact
bare tool names from that server. Omitting it preserves the ACP default of
exposing every server tool.

### Parallel Agents & Heartbeat

| Flag | Env Var | Default | Description |
Expand Down
5 changes: 5 additions & 0 deletions crates/buzz-acp/src/acp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ pub struct McpServer {
pub command: String,
pub args: Vec<String>,
pub env: Vec<EnvVar>,
/// Buzz extension: exact bare tool names this server may expose. Empty
/// preserves the ACP default of exposing every server tool.
#[serde(rename = "allowedTools", skip_serializing_if = "Vec::is_empty")]
pub allowed_tools: Vec<String>,
}

/// A single environment variable for an MCP server.
Expand Down Expand Up @@ -2442,6 +2446,7 @@ mod tests {
value: "nsec1abc".into(),
},
],
allowed_tools: vec![],
};
let serialized = serde_json::to_value(&server).unwrap();
assert_eq!(serialized["name"].as_str(), Some("test-mcp"));
Expand Down
Loading