Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9f21cfd
feat(spawner): server-hosted agents with identity relocation
siddhartpai Jul 26, 2026
203034a
docs: design spec for first-party server-agent prompt/model editing
siddhartpai Jul 26, 2026
bcf9fdf
docs: implementation plan for server-agent prompt/model editing
siddhartpai Jul 26, 2026
245973c
feat(sdk): spawner AI catalog, prompt_hash status field, PromptMateri…
siddhartpai Jul 26, 2026
c46b480
feat(spawner): advertise AI catalog, echo applied prompt_hash in status
siddhartpai Jul 26, 2026
157e8ad
feat(desktop): Tauri command to build signed spawner prompt-update fr…
siddhartpai Jul 26, 2026
4ba3abb
feat(desktop): spawner AI catalog + prompt-hash parsing and prompt-up…
siddhartpai Jul 26, 2026
ef1fb4e
chore(desktop): lockfile bump for buzz-sdk sha2 dependency
siddhartpai Jul 26, 2026
ab145f7
feat(desktop): queued, status-acked spawner prompt updates
siddhartpai Jul 26, 2026
c793107
fix(desktop): hold off resending delivered spawner prompt updates
siddhartpai Jul 26, 2026
a125c01
feat(desktop): server-agent edit policy
siddhartpai Jul 26, 2026
08857d8
feat(desktop): server-agent edit policy - add trim test
siddhartpai Jul 26, 2026
b6b9c1d
feat(desktop): server-aware Edit agent dialog
siddhartpai Jul 26, 2026
af9906c
fix(desktop): reconcile server agent AI fields with spawner catalog
siddhartpai Jul 26, 2026
c1c28be
feat(desktop): push prompt/model edits to the spawner on save
siddhartpai Jul 26, 2026
9920e92
test(spawner): owner_sim exercises prompt-update push and ack
siddhartpai Jul 26, 2026
7751cec
refactor(desktop): extract server prompt-update push to satisfy file-…
siddhartpai Jul 26, 2026
7574114
fix(desktop): trim prompt material before spawner push
siddhartpai Jul 26, 2026
b22848a
fix(spawner): preserve team instructions across prompt updates
siddhartpai Jul 26, 2026
339edc2
fix(desktop): rehydrate spawner prompt-update queue lazily per relay
siddhartpai Jul 26, 2026
c15ccbd
fix(desktop): skip empty prompt pushes and soften the pending chip
siddhartpai Jul 26, 2026
4338b75
fix(desktop): never hydrate or persist the prompt-update queue withou…
siddhartpai Jul 27, 2026
5855835
test(desktop): screenshot spec for server-aware agent editing
siddhartpai Jul 27, 2026
c289e5b
fix(desktop): don't require local API keys when editing server-hosted…
siddhartpai Jul 27, 2026
ca2d637
docs: design spec for per-owner server agent credentials
siddhartpai Jul 27, 2026
8ec0e5d
feat(sdk): credential update/ack attestation frames and needs_credent…
siddhartpai Jul 27, 2026
530402a
fix(spawner): handle credential frames in attestation match
siddhartpai Jul 27, 2026
91ff326
feat(spawner): per-owner credential store with prefix classification
siddhartpai Jul 27, 2026
aa24d22
feat(spawner): inject per-owner credential into agent env, displacing…
siddhartpai Jul 27, 2026
f8c6661
feat(spawner): hold agents without owner credential; apply credential…
siddhartpai Jul 27, 2026
7eb062e
feat(desktop): tauri commands to sign credential updates and decode acks
siddhartpai Jul 27, 2026
50f741e
feat(desktop): credential update transport with encrypted ack waiter
siddhartpai Jul 27, 2026
64e9374
feat(desktop): spawner credential card and needs-credential badge
siddhartpai Jul 27, 2026
b326f3d
test(desktop): screenshots for spawner credential card and needs-cred…
siddhartpai Jul 27, 2026
35911b2
docs(deploy): note per-owner credential requirement; fmt fixes
siddhartpai Jul 27, 2026
45cd4ba
docs: self-hosted backend guide (relay + spawner) linked from README
siddhartpai Jul 27, 2026
d9ee4a8
fix: integrate rebase onto main (global config arg, relocation field …
siddhartpai Jul 27, 2026
32bd315
docs: complete the local spawner command (agent relay URL, local image)
siddhartpai Jul 27, 2026
555c1a4
docs: self-hosted guide — same-host rule, agent relay URL, local imag…
siddhartpai Jul 27, 2026
bc40947
fix(spawner): reclaim agent-container names squatted by a retired spa…
siddhartpai Jul 27, 2026
89f7c41
docs: design for agent access to internal systems via buzz-ops-mcp
siddhartpai Jul 28, 2026
16449c3
fix: add relocation field to snapshot fidelity test fixture
siddhartpai Jul 30, 2026
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
99 changes: 98 additions & 1 deletion 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
@@ -1,6 +1,7 @@
[workspace]
members = [
"crates/buzz-relay",
"crates/buzz-spawner",
"crates/buzz-core",
"crates/buzz-conformance",
"crates/buzz-push-gateway",
Expand Down
106 changes: 106 additions & 0 deletions Dockerfile.acp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# syntax=docker/dockerfile:1.7
#
# The agent runtime image: one `buzz-acp` harness per container, spawned by
# `buzz-spawner`. This is the server-side equivalent of what the desktop app
# launches locally via `managed_agents/runtime.rs::spawn_agent_child`.
#
# `sprig` is a multicall binary (crates/sprig/src/main.rs) that dispatches on
# argv[0], so one build produces the harness, the built-in agent, and the dev
# MCP tools. The symlinks below are how the harness finds them — it spawns its
# ACP agent by name over stdio.
ARG RUST_VERSION=1.95
ARG DEBIAN_VERSION=bookworm

FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS chef
RUN cargo install cargo-chef --locked --version 0.1.71
WORKDIR /build

FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential pkg-config libssl-dev ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=planner /build/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --locked -p sprig --bin sprig \
&& cargo build --release --locked -p buzz-cli --bin buzz \
&& strip target/release/sprig target/release/buzz

FROM debian:${DEBIAN_VERSION}-slim AS runtime
LABEL org.opencontainers.image.title="Buzz ACP Agent" \
org.opencontainers.image.description="buzz-acp harness runtime for server-hosted Buzz agents" \
org.opencontainers.image.source="https://github.com/block/buzz" \
org.opencontainers.image.licenses="Apache-2.0"

# git and ca-certificates are not optional: agents clone and push repositories
# through the relay's smart-HTTP transport, authenticated by git-credential-nostr.
#
# node and curl exist for the optional Claude Code runtime below: the ACP adapter
# ships as an npm package and the CLI installs via a shell script.
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl git \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid 1000 agent \
&& useradd --system --uid 1000 --gid 1000 --home-dir /home/agent --create-home --shell /bin/bash agent

COPY --from=builder /build/target/release/sprig /usr/local/bin/sprig
COPY --from=builder /build/target/release/buzz /usr/local/bin/buzz

# Multicall dispatch: sprig routes on argv[0].
RUN for name in buzz-acp buzz-agent buzz-dev-mcp git-credential-nostr git-sign-nostr; do \
ln -s /usr/local/bin/sprig "/usr/local/bin/$name"; \
done

# Claude Code and its ACP adapter, for running agents on a Claude subscription
# instead of a metered API key.
#
# # Authentication in a container
#
# The subscription flow is browser-based and interactive, which a container
# cannot do. The non-interactive equivalent is a long-lived token from
# `claude setup-token` (run once on a machine with a browser), supplied as
# `CLAUDE_CODE_OAUTH_TOKEN`. `buzz-acp` does not clear the environment when it
# spawns the adapter, so the token reaches the CLI unchanged.
#
# Forward it with the spawner's own passthrough, which takes variable *names*:
#
# BUZZ_SPAWNER_AGENT_ENV=CLAUDE_CODE_OAUTH_TOKEN
# BUZZ_SPAWNER_AGENT_COMMAND=claude-agent-acp
#
# The alternative — bind-mounting a pre-authenticated `~/.claude` — is not
# supported by the spawner and would share one credential store across every
# agent on the host.
ARG CLAUDE_ACP_VERSION=0.62.0
# The installer takes only [stable|latest|VERSION] and always installs into
# $HOME/.local/bin, so it runs with HOME pointed at the agent's home (this RUN
# is root, whose $HOME the agent user cannot read) and the result is symlinked
# onto PATH. `HOME=... bash` rather than `HOME=... curl`: the variable has to
# reach the shell that does the installing, not the download.
RUN npm install -g "@agentclientprotocol/claude-agent-acp@${CLAUDE_ACP_VERSION}" \
&& npm cache clean --force \
&& curl -fsSL https://claude.ai/install.sh | HOME=/home/agent bash -s -- stable \
&& ln -sf /home/agent/.local/bin/claude /usr/local/bin/claude \
&& chown -R agent:agent /home/agent \
&& /usr/local/bin/claude --version

# The nest. buzz-spawner mounts a per-agent named volume here, so an agent's
# workspace survives restarts and config changes but is invisible to every
# other agent on the host.
#
# `.claude` is created up front and owned by the agent: the CLI writes state
# there, and it must not fall back to a root-owned path or a read-only home.
RUN mkdir -p /home/agent/.buzz /home/agent/.claude && chown -R agent:agent /home/agent

USER agent:agent
WORKDIR /home/agent/.buzz
ENV HOME=/home/agent
# Default to the in-house agent, which needs only an API key. Override with
# BUZZ_SPAWNER_AGENT_COMMAND=claude-agent-acp to use a Claude subscription.
ENV BUZZ_ACP_AGENT_COMMAND=buzz-agent
ENTRYPOINT ["/usr/local/bin/buzz-acp"]
43 changes: 43 additions & 0 deletions Dockerfile.spawner
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# syntax=docker/dockerfile:1.7
ARG RUST_VERSION=1.95
ARG DEBIAN_VERSION=bookworm

FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS chef
RUN cargo install cargo-chef --locked --version 0.1.71
WORKDIR /build

FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential pkg-config libssl-dev ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=planner /build/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --locked -p buzz-spawner --bin buzz-spawner \
&& strip target/release/buzz-spawner

FROM debian:${DEBIAN_VERSION}-slim AS runtime
LABEL org.opencontainers.image.title="Buzz Spawner" \
org.opencontainers.image.description="Reconciles Nostr agent specs into Docker-isolated buzz-acp containers" \
org.opencontainers.image.source="https://github.com/block/buzz" \
org.opencontainers.image.licenses="Apache-2.0"
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid 1000 buzz \
&& useradd --system --uid 1000 --gid 1000 --home-dir /var/lib/buzz-spawner --create-home --shell /usr/sbin/nologin buzz
COPY --from=builder /build/target/release/buzz-spawner /usr/local/bin/buzz-spawner

# Runs as root, unlike the relay and push gateway. Talking to the Docker socket
# requires membership in the host's docker group, whose GID varies per host, so
# baking a fixed GID here would break on most machines. The socket mount is
# already root-equivalent on the host (see deploy/compose/README.md) — dropping
# to a non-root user inside the container would not change that, only obscure
# it. An operator who wants real privilege reduction should point the spawner at
# a rootless Docker or Podman socket via DOCKER_HOST.
WORKDIR /var/lib/buzz-spawner
ENTRYPOINT ["/usr/local/bin/buzz-spawner"]
Loading