Skip to content
Closed
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
62 changes: 62 additions & 0 deletions .github/workflows/nix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: Nix

on:
push:
branches: [main, release]
paths:
- ".github/workflows/nix.yml"
- "Cargo.lock"
- "Cargo.toml"
- "crates/**"
- "desktop/**"
- "flake.lock"
- "flake.nix"
- "nix/**"
- "package.json"
- "patches/**"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "rust-toolchain.toml"
pull_request:
paths:
- ".github/workflows/nix.yml"
- "Cargo.lock"
- "Cargo.toml"
- "crates/**"
- "desktop/**"
- "flake.lock"
- "flake.nix"
- "nix/**"
- "package.json"
- "patches/**"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "rust-toolchain.toml"

concurrency:
group: nix-${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

permissions:
contents: read

jobs:
build:
name: Build packages
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: DeterminateSystems/nix-installer-action@ef8a148080ab6020fd15196c2084a2eea5ff2d25 # v22

- name: Check Nix formatting
run: nix fmt -- --check flake.nix nix/buzz.nix nix/versions.nix nix/modules/buzz-relay.nix

- name: Evaluate all supported systems
run: nix flake show --all-systems

- name: Build relay and NixOS module check
run: nix flake check --print-build-logs

- name: Build desktop and sidecars
run: nix build --print-build-logs .#buzz-desktop .#buzz-sidecars
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,17 @@ Relay on `ws://localhost:3000`. Desktop app pops up. You're in.

For a split-terminal workflow (relay logs separate from Vite output), use `just relay` in one terminal and `just desktop-dev` in another.

Using Nix, the flake exposes the desktop app, relay server, administration CLI,
agent sidecars, and a NixOS relay module:

```bash
nix run .#buzz-desktop
nix run .#buzz-relay
```

See the [NixOS deployment guide](deploy/nixos/README.md) for package names,
module options, secrets, and reverse-proxy configuration.

Want a single-node / VPS relay instead of the local-dev stack? Use the production Compose bundle in [`deploy/compose/`](deploy/compose/README.md) (`docker compose` + Postgres, Redis, MinIO, optional Caddy/TLS). The root [`docker-compose.yml`](docker-compose.yml) is for day-to-day development only.

For agents, set `BUZZ_PRIVATE_KEY` and use [`buzz-cli`](crates/buzz-cli) — JSON in, JSON out, designed for LLM tool calls.
Expand Down Expand Up @@ -244,6 +255,7 @@ A Rust workspace of focused crates. Single source of truth: the relay. See [ARCH
- **[VISION.md](VISION.md)** · **[VISION_SOVEREIGN.md](VISION_SOVEREIGN.md)** · **[VISION_PROJECTS.md](VISION_PROJECTS.md)** · **[VISION_AGENT.md](VISION_AGENT.md)** — the four vision docs
- **[ARCHITECTURE.md](ARCHITECTURE.md)** — system design, kind ranges, subsystem boundaries
- **[TESTING.md](TESTING.md)** — multi-agent E2E test suite
- **[deploy/nixos](deploy/nixos/README.md)** · **[deploy/compose](deploy/compose/README.md)** · **[deploy/charts/buzz](deploy/charts/buzz/README.md)** — relay deployment guides
- **[CONTRIBUTING.md](CONTRIBUTING.md)** · **[CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)** · **[SECURITY.md](SECURITY.md)** · **[GOVERNANCE.md](GOVERNANCE.md)**

<details>
Expand Down
2 changes: 2 additions & 0 deletions deploy/compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

This is the single-node/VPS deployment bundle. It is intentionally separate from
the root `docker-compose.yml`, which remains local development infrastructure.
For NixOS deployments, use the NixOS module guide in
[`../nixos/README.md`](../nixos/README.md).

## Quick start

Expand Down
270 changes: 270 additions & 0 deletions deploy/nixos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
# Buzz on NixOS

The repository flake builds the Buzz desktop app, relay server, administration
CLI, and agent sidecars. It also exports a NixOS module for running the relay as
a hardened systemd service.

## Build and run

From a Buzz checkout:

```bash
nix build .#buzz-desktop
nix build .#buzz-relay
nix build .#buzz-sidecars
nix build .#buzz-cli
nix build .#git-credential-nostr
nix build .#buzz-git-tools

nix run .#buzz-desktop
nix run .#buzz-relay
nix run .#buzz-admin -- --help
nix run .#buzz -- --help
```

The `buzz-relay` package contains both `buzz-relay` and `buzz-admin`. The named
apps select the appropriate executable. `buzz-git-tools` provides the complete
client-side git workflow in one package: Git 2.46 or newer, the `buzz` CLI, and
the `git-credential-nostr` NIP-98 helper. On Linux, the Nix desktop package also
puts Git on its runtime `PATH`; the CLI and credential helper are bundled
sidecars.

## Clone a Buzz-hosted repository

Enter the complete client toolset, announce a repository bound to a channel,
then use normal Git commands. The relay URL is HTTP(S) for Git even when the
Buzz WebSocket URL uses WS(S).

```bash
nix shell .#buzz-git-tools

export BUZZ_RELAY_URL=https://buzz.example.com
export BUZZ_PRIVATE_KEY=nsec1...
export NOSTR_PRIVATE_KEY="$BUZZ_PRIVATE_KEY"

buzz channels create --name example --type stream --visibility private
# Copy channel_id from the response, and use your 64-character hex pubkey below.
export CHANNEL_ID=00000000-0000-0000-0000-000000000000
export OWNER_PUBKEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
export CLONE_URL="$BUZZ_RELAY_URL/git/$OWNER_PUBKEY/example"

buzz repos create --id example --clone "$CLONE_URL" --channel "$CHANNEL_ID"
git -c credential.helper=nostr -c credential.useHttpPath=true clone "$CLONE_URL"
```

The repository announcement creates the empty remote repository. The channel
binding is its access-control boundary, and the credential helper signs Git's
HTTP requests with `NOSTR_PRIVATE_KEY`. Buzz Desktop configures the helper
ephemerally for managed agents, so its project and agent flows can use ordinary
`git clone`, `git fetch`, and `git push` without global Git configuration.

## Development shells

The default shell intentionally contains only the pinned Rust toolchain and
`just`, so `nix develop` does not pull the large desktop GUI and audio closure:

```bash
nix develop
```

Use the explicit desktop shell when working on the Tauri application:

```bash
nix develop .#desktop
```

On a cold Linux Nix store, the desktop shell can download more than 1 GiB of
GTK, WebKit, and audio dependencies. Check the plan first with
`nix build --dry-run .#devShells.x86_64-linux.desktop` on constrained systems.

### Codex ACP adapter

The desktop package includes Buzz's own agent sidecars, but external managed
agent runtimes and their ACP adapters must also be available on `PATH`.

Despite having the same `codex-acp` executable name, `pkgs.codex-acp` at this
flake's pinned nixpkgs revision is version 0.13.0 from the legacy
`@zed-industries/codex-acp` project. Buzz requires the official
`@agentclientprotocol/codex-acp` adapter at or above the minimum version
enforced by the desktop app (currently 1.1.7). NixOS configurations should
package that upstream adapter explicitly rather than install the nixpkgs
package with the matching name. The Codex CLI must also be on `PATH`, or its
executable can be selected with `CODEX_PATH`.

## Import the NixOS module

Pin Buzz as a flake input and import its relay module:

```nix
{
inputs.buzz.url = "github:block/buzz";

outputs =
{
nixpkgs,
buzz,
...
}:
{
nixosConfigurations.relay = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
buzz.nixosModules.buzz-relay
./configuration.nix
];
};
};
}
```

The module supports x86-64 and ARM64 Linux.

## Configure the relay

The module runs the relay but does not provision PostgreSQL, Redis, object
storage, DNS, or TLS. Those services may run on the same host or be provided
externally. In particular, the module does not depend on or install MinIO;
choose a maintained S3-compatible service appropriate for the deployment.

```nix
{
services.buzz-relay = {
enable = true;

relayUrl = "wss://buzz.example.com";
host = "127.0.0.1";
port = 3000;

databaseUrl = "postgres://buzz@localhost:5432/buzz";
redisUrl = "redis://localhost:6379";
s3Endpoint = "https://s3.example.com";
s3Bucket = "buzz-media";
s3Region = "eu-west-2";
s3AddressingStyle = "path";
mediaBaseUrl = "https://buzz.example.com/media";

environmentFile = "/run/secrets/buzz-relay.env";
autoMigrate = true;
};
}
```

URLs containing credentials can be supplied through `environmentFile` instead
of normal Nix options, which are copied into the Nix store.

Example runtime secret file:

```env
DATABASE_URL=postgres://buzz:CHANGE_ME@localhost:5432/buzz
BUZZ_RELAY_PRIVATE_KEY=CHANGE_ME_32_BYTE_HEX_PRIVATE_KEY
BUZZ_S3_ACCESS_KEY=CHANGE_ME
BUZZ_S3_SECRET_KEY=CHANGE_ME
BUZZ_GIT_HOOK_HMAC_SECRET=CHANGE_ME_AT_LEAST_32_CHARACTERS
```

Keep `BUZZ_RELAY_PRIVATE_KEY` stable across rebuilds and restores. A changed key
gives the relay a new identity.

Unmodeled relay settings can be passed through `environment` when they are not
secret:

```nix
{
services.buzz-relay.environment = {
BUZZ_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN = 120;
BUZZ_MEDIA_UPLOADS_PER_MINUTE = 20;
};
}
```

Deployments with a Postgres read replica can size its pool independently and
opt into bounded-staleness routing:

```nix
{
services.buzz-relay = {
readDatabaseUrl = "postgres://buzz@reader.example.com:5432/buzz";
readDatabasePoolSize = 25;
replicaReadMaxAgeMs = 1000;
};
}
```

Replica routing remains disabled when `replicaReadMaxAgeMs` is zero.

## Closed relays

Membership enforcement requires a stable relay key and an owner pubkey:

```nix
{
services.buzz-relay = {
requireRelayMembership = true;
ownerPubkey = "64_character_lowercase_hex_nostr_pubkey";
environmentFile = "/run/secrets/buzz-relay.env";
};
}
```

The environment file must provide `BUZZ_RELAY_PRIVATE_KEY`.

## Reverse proxy

The public HTTP and WebSocket traffic shares one port. A typical deployment
binds Buzz to localhost and terminates TLS with nginx:

```nix
{
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;

virtualHosts."buzz.example.com" = {
forceSSL = true;
enableACME = true;

locations."/" = {
proxyPass = "http://127.0.0.1:3000";
proxyWebsockets = true;
};
};
};

security.acme = {
acceptTerms = true;
defaults.email = "ops@example.com";
};
}
```

`openFirewall` opens only the public relay port. Health and metrics ports remain
private unless configured separately.

## Operations

The module creates a `buzz-relay` system user and persists git data beneath
`dataDir`, which defaults to `/var/lib/buzz`.

```bash
systemctl status buzz-relay
journalctl -u buzz-relay -f
curl --fail http://127.0.0.1:8080/_liveness
curl --fail http://127.0.0.1:8080/_readiness
```

Prometheus metrics are exposed on port `9102` by default.

For horizontally scaled relay deployments, disable in-process huddle audio:

```nix
services.buzz-relay.huddleAudioAvailable = false;
```

Back up PostgreSQL, the S3 bucket, `dataDir`, and all secret files before
upgrades. If `autoMigrate` is disabled, run `buzz-admin migrate` from the same
pinned Buzz revision before starting the new relay:

```bash
nix run github:block/buzz#buzz-admin -- migrate
```
Loading