diff --git a/.goreleaser.yml b/.goreleaser.yml index 55719a2..dcd8bdf 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -20,16 +20,17 @@ builds: - -s -w -X github.com/nnemirovsky/peerbus/internal/version.Version={{ .Version }} archives: - # One archive per os/arch bundling the single binary plus LICENSE + README. + # Single static binary — no archive wrapping. Users grab the raw binary, + # chmod +x, and run it. Matches the sluice release style; no LICENSE/README + # bundling because the binary is the artifact and both files are already in + # the repo / release notes. name_template intentionally omits the version + # (sluice convention) so `latest/download/peerbus__` always works. - id: peerbus ids: - peerbus formats: - - tar.gz - name_template: "peerbus_{{ .Version }}_{{ .Os }}_{{ .Arch }}" - files: - - LICENSE - - README.md + - binary + name_template: "peerbus_{{ .Os }}_{{ .Arch }}" changelog: disable: true diff --git a/Dockerfile b/Dockerfile index b47144c..91c9451 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,24 @@ -# Multi-stage build for the peerbus broker. +# Multi-stage build for the peerbus binary. # -# BROKER ONLY. peerbus's topology is one long-lived broker + many thin, -# ephemeral adapter processes. Adapters are spawned by each agent runtime -# (Claude Code spawns `peerbus adapter --adapter=cc` per session; a -# drain-agent spawns `peerbus adapter --adapter=generic` as its own stdio MCP -# child) and are NEVER containerized here. Containerizing an adapter — or -# worse, running the broker per session — is exactly the cc2cc orphaned -# -server failure mode the broker/adapter split designs out. This image is the -# managed, long-lived broker service only. +# The image bakes in the full `peerbus` multi-command binary (v0.2.0+); the +# ENTRYPOINT is `peerbus` and CMD defaults to `["serve"]`, so by default the +# container is the long-lived broker service. CMD is overridable for ops +# tasks: +# docker run --rm peerbus:latest --version +# docker run --rm -v peerbus-data:/data peerbus:latest audit verify \ +# --db /data/peerbus.db # -# As of v0.2.0 peerbus ships ONE multi-command binary (git/kubectl style); the -# image bakes in `peerbus serve` as the default entrypoint+command so the -# container runs ONLY the `serve` subcommand by design. Only the build target -# (`./cmd/peerbus` instead of `./cmd/peerbus-broker`) changed — the supervision -# contract is identical. +# Adapter mode (`adapter --adapter=cc|generic`) is technically runnable too, +# but adapters are stdio MCP children of the agent runtime (Claude Code spawns +# the cc adapter per session; a drain-agent spawns the generic adapter). Running +# an adapter as a long-lived container service has no agent stdio to attach to +# and ends up either orphaned or replicated per session — the cc2cc failure +# mode the broker/adapter split designs out. Use the release binary, not the +# container, for adapters. # -# Pure Go: the durable store uses modernc.org/sqlite (no cgo), so the build -# is CGO_ENABLED=0 and the final image is distroless/static (no libc, no -# shell). One static binary, nothing else. +# Pure Go: the durable store uses modernc.org/sqlite (no cgo), so the build is +# CGO_ENABLED=0 and the final image is distroless/static (no libc, no shell). +# One static binary, nothing else. FROM golang:1.25 AS build WORKDIR /src @@ -29,7 +30,7 @@ RUN CGO_ENABLED=0 go build -ldflags '-s -w' -o /out/peerbus ./cmd/peerbus FROM gcr.io/distroless/static-debian12 LABEL org.opencontainers.image.source="https://github.com/nnemirovsky/peerbus" -LABEL org.opencontainers.image.description="peerbus broker — agent-agnostic durable message bus (broker only)" +LABEL org.opencontainers.image.description="peerbus — agent-agnostic durable message bus (broker by default; CMD overridable for audit/version)" LABEL org.opencontainers.image.licenses="MIT" COPY --from=build /out/peerbus /usr/local/bin/peerbus # Durable SQLite store (queue + blake3 audit chain) lives on a mounted diff --git a/README.md b/README.md index 163c25c..9a745f8 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ PEERBUS_TOKENS=... PEERBUS_HMAC_SECRET=... ./peerbus serve ./peerbus audit verify # walk the blake3 audit chain ``` -`deploy/peerbus-broker.run` (s6) is an alternative to compose. The container image is the repo-root `Dockerfile` (broker only, pure-Go static, distroless). Do **not** run the broker per session. +`deploy/peerbus-broker.run` (s6) is an alternative to compose. The container image is the repo-root `Dockerfile` (pure-Go static, distroless); it bakes in the full `peerbus` binary with `serve` as the default CMD, so `docker run peerbus:latest` is the broker. CMD is overridable (e.g. `docker run --rm -v peerbus-data:/data peerbus:latest audit verify --db /data/peerbus.db`) but adapters are stdio children of the agent runtime — don't run them as a container service. Do **not** run the broker per session either. ### 2. Wire an adapter diff --git a/deploy/compose.yml b/deploy/compose.yml index 8565b90..a031f06 100644 --- a/deploy/compose.yml +++ b/deploy/compose.yml @@ -1,6 +1,6 @@ -# peerbus broker — managed, long-lived service (broker ONLY) +# peerbus broker — managed, long-lived service (default `serve` role) # -# WHY THIS COMPOSE FILE RUNS ONLY THE BROKER, NEVER AN ADAPTER: +# WHY THIS COMPOSE FILE RUNS THE BROKER, NEVER AN ADAPTER: # # peerbus's topology is one long-lived broker + many thin, ephemeral adapter # processes. The broker holds the durable SQLite queue and the blake3 @@ -40,8 +40,9 @@ services: # The canonical broker image is the repo-root Dockerfile (the same one # the Docker release workflow publishes to ghcr.io). The image ships the # single `peerbus` multi-command binary with `serve` as the default - # command — the broker-only role is baked into the image's CMD, not into - # the binary. + # command — the binary itself is multi-role (subcommands `serve`, + # `audit verify`, `adapter --adapter=`), but this manifest pins it + # to `serve` because adapters belong to agent runtimes, not containers. build: context: .. dockerfile: Dockerfile