Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
75b7424
feat(spawner): server-hosted agents with identity relocation
siddhartpai Jul 26, 2026
c4c29bb
fix: integrate rebase onto main (global config arg, relocation field …
siddhartpai Jul 27, 2026
efb03b1
fix(spawner): reclaim agent-container names squatted by a retired spa…
siddhartpai Jul 27, 2026
22a52dc
fix(desktop): key server-agent persona lookup by slug, not display name
siddhartpai Jul 27, 2026
5926052
test(desktop): fix server-agents deploy-menu spec
siddhartpai Jul 27, 2026
4344418
fix(desktop): clear trusted spawners on community switch
siddhartpai Jul 27, 2026
8ff170b
fix(spawner): scope container and volume names per spawner identity
siddhartpai Jul 27, 2026
c4f6f82
fix(spawner): defer relay frames that interleave a persona query inst…
siddhartpai Jul 27, 2026
998c8bf
fix(desktop): retire a relocated agent before handing out its key
siddhartpai Jul 27, 2026
5ff3be3
docs(core): correct spawner kind docs; fix advertised capacity and st…
siddhartpai Jul 27, 2026
399cdeb
chore: drop scratch files from the spawner PR
siddhartpai Jul 27, 2026
9dee672
fix(desktop): unwedge spawner subscriptions, guard slug collisions, h…
siddhartpai Jul 27, 2026
2eb7c2f
fix(spawner): install the rustls CryptoProvider before connecting
siddhartpai Jul 28, 2026
9189ab0
fix(deploy): pass the spawner's name and host defaults through compose
siddhartpai Jul 28, 2026
ba02211
docs: design spec for first-party server-agent prompt/model editing
siddhartpai Jul 26, 2026
4c239d1
docs: implementation plan for server-agent prompt/model editing
siddhartpai Jul 26, 2026
f835a81
feat(sdk): spawner AI catalog, prompt_hash status field, PromptMateri…
siddhartpai Jul 26, 2026
3059b8d
feat(spawner): advertise AI catalog, echo applied prompt_hash in status
siddhartpai Jul 26, 2026
3be8463
feat(desktop): Tauri command to build signed spawner prompt-update fr…
siddhartpai Jul 26, 2026
875d8bc
feat(desktop): spawner AI catalog + prompt-hash parsing and prompt-up…
siddhartpai Jul 26, 2026
5f2a127
chore(desktop): lockfile bump for buzz-sdk sha2 dependency
siddhartpai Jul 26, 2026
9386464
feat(desktop): queued, status-acked spawner prompt updates
siddhartpai Jul 26, 2026
2ba6576
fix(desktop): hold off resending delivered spawner prompt updates
siddhartpai Jul 26, 2026
3955ba8
feat(desktop): server-agent edit policy
siddhartpai Jul 26, 2026
ef51abf
feat(desktop): server-agent edit policy - add trim test
siddhartpai Jul 26, 2026
9df03ca
feat(desktop): server-aware Edit agent dialog
siddhartpai Jul 26, 2026
c772beb
fix(desktop): reconcile server agent AI fields with spawner catalog
siddhartpai Jul 26, 2026
a07fa13
feat(desktop): push prompt/model edits to the spawner on save
siddhartpai Jul 26, 2026
9dd08c7
test(spawner): owner_sim exercises prompt-update push and ack
siddhartpai Jul 26, 2026
fc7588a
refactor(desktop): extract server prompt-update push to satisfy file-…
siddhartpai Jul 26, 2026
f54ee4b
fix(desktop): trim prompt material before spawner push
siddhartpai Jul 26, 2026
adda61c
fix(spawner): preserve team instructions across prompt updates
siddhartpai Jul 26, 2026
ced9271
fix(desktop): rehydrate spawner prompt-update queue lazily per relay
siddhartpai Jul 26, 2026
366ff3c
fix(desktop): skip empty prompt pushes and soften the pending chip
siddhartpai Jul 26, 2026
c2706ce
fix(desktop): never hydrate or persist the prompt-update queue withou…
siddhartpai Jul 27, 2026
1329e22
test(desktop): screenshot spec for server-aware agent editing
siddhartpai Jul 27, 2026
4b9e07c
fix(desktop): don't require local API keys when editing server-hosted…
siddhartpai Jul 27, 2026
abc5e48
fix(deploy): pass the spawner AI catalog through compose
siddhartpai Jul 28, 2026
5df6258
docs: design spec for per-owner server agent credentials
siddhartpai Jul 27, 2026
e4d75a5
feat(sdk): credential update/ack attestation frames and needs_credent…
siddhartpai Jul 27, 2026
0b1b022
fix(spawner): handle credential frames in attestation match
siddhartpai Jul 27, 2026
dfb49df
feat(spawner): per-owner credential store with prefix classification
siddhartpai Jul 27, 2026
3827caf
feat(spawner): inject per-owner credential into agent env, displacing…
siddhartpai Jul 27, 2026
f130b5b
feat(spawner): hold agents without owner credential; apply credential…
siddhartpai Jul 27, 2026
96047e4
feat(desktop): tauri commands to sign credential updates and decode acks
siddhartpai Jul 27, 2026
bdd174a
feat(desktop): credential update transport with encrypted ack waiter
siddhartpai Jul 27, 2026
b3fddb0
feat(desktop): spawner credential card and needs-credential badge
siddhartpai Jul 27, 2026
a855c6e
test(desktop): screenshots for spawner credential card and needs-cred…
siddhartpai Jul 27, 2026
ca13862
refactor(desktop): drop manual spawner connect-by-pubkey card
siddhartpai Jul 27, 2026
6aeb296
fix: add relocation field to snapshot fidelity test fixture
siddhartpai Jul 30, 2026
73d7e02
fix: pass targetChannel slot when forwarding definition submit options
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,6 @@ identity.key

# Helm dependency tarballs — regenerable from Chart.lock via `helm dependency build`
deploy/charts/*/charts/*.tgz

# Personal GUI-session launcher (see AGENTS.md); kept out of the repo.
run-dev.command
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,11 @@ reconnects preserve pending avatar verification work):
- `resetAgentObserverStore()` — agent observer relay store
- `resetActiveAgentTurnsStore()` — active agent turn timers
- `resetAgentWorkingSignal()` — agent working indicator signal
- `resetSpawnerAttestationStore()` — pending spawner attestation prompts
- `resetSpawnerStatusStore()` — server-agent status rows
- `resetSpawnerDirectoryStore()` — announced spawner directory
- `resetTrustedSpawners()` — approved-spawner set (identity-scoped: a spawner
trusted under the old identity must not auto-sign under the new one)
- `resetAvatarProfileSync()` — pending verified-avatar profile writes
- `resetAvatarPresentations()` — avatar probes, previews, and Retry toasts
- `resetSidebarRelayConnectionCardState()` — sidebar relay card dismiss state
Expand Down
100 changes: 99 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