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
32 changes: 32 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ check existing reply handlers for the pattern.
by the ACP harness into managed agent subprocesses. In development, set
`BUZZ_PRIVATE_KEY` and `BUZZ_RELAY_URL` in your environment manually.

For production deployments where private keys should not be present in the
runtime environment, use NIP-46 remote signing via `buzz bunker connect` —
see the [Remote Signing](#remote-signing-nip-46) section below.

### Building the CLI

```bash
Expand Down Expand Up @@ -192,6 +196,34 @@ All reads return sig-stripped JSON arrays; all writes return

See `crates/buzz-cli/TESTING.md` for the full live-testing runbook.

### Remote Signing (NIP-46)

For production agent deployments, use NIP-46 remote signing to keep private
keys off the agent runtime entirely. The agent connects to a remote signer
(hardware device, mobile app, or dedicated signing service) over an encrypted
WebSocket channel:

```bash
# Client mode — connect to a remote signer
buzz bunker connect bunker://<signer-pubkey>?relay=wss://relay.example.com&secret=xyz \
--name "Production Agent" \
--perms "sign_event:1,nip44_encrypt,nip44_decrypt"

# Server mode — run a remote signer daemon
buzz bunker serve --timeout 0 # infinite timeout
buzz bunker serve --auto-approve --timeout 3600 # dev mode with 1h timeout
```

The bunker URL comes from the remote signer. Once connected, all signing
operations (`sign_event`, `nip44_encrypt`, `nip44_decrypt`) happen on the
remote signer — the agent runtime never sees the private key.

This is the recommended approach for:
- Production agents where key compromise = full identity loss
- CI/CD pipelines that should not store long-lived secrets
- Multi-tenant agent platforms
- Compliance environments requiring hardware-backed keys

---

## Testing
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ 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.

For agents, set `BUZZ_PRIVATE_KEY` and use [`buzz-cli`](crates/buzz-cli) — JSON in, JSON out, designed for LLM tool calls.
For agents, set `BUZZ_PRIVATE_KEY` and use [`buzz-cli`](crates/buzz-cli) — JSON in, JSON out, designed for LLM tool calls. For production deployments, use NIP-46 remote signing (`buzz bunker`) to keep private keys off the agent runtime entirely.

---

Expand Down
14 changes: 14 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@ example), keys fall back to a `0o600` owner-only file. The `BUZZ_PRIVATE_KEY`
environment variable, when set, always takes precedence over both stores — this
is how harnessed agents and CI receive their identity.

### Remote Signing — NIP-46

For production agent deployments where private keys should never touch the
runtime environment, Buzz CLI supports
[NIP-46](https://github.com/nostr-protocol/nips/blob/master/46.md) remote
signing via `buzz bunker`. The agent runtime connects to a remote signer
(hardware device, dedicated signing service, or mobile app) over an encrypted
WebSocket channel. All signing operations happen on the remote signer; the
agent runtime never sees the private key.

This is the recommended approach for production agents, CI/CD pipelines, and
any environment where key material should remain physically separated from the
workload.

### Input Validation

- All UUIDs (channel IDs, workflow IDs) are validated at API boundaries before
Expand Down
3 changes: 3 additions & 0 deletions crates/buzz-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ buzz-persona = { path = "../buzz-persona" }

# WebSocket client — ephemeral event publish (kind:20001 is WS-only on the relay)
buzz-ws-client = { path = "../buzz-ws-client" }

# URL encoding for bunker URL construction
urlencoding = "2.1"
10 changes: 9 additions & 1 deletion crates/buzz-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,17 @@ buzz mem set <slug> "my-value"
buzz mem patch <slug> --base-hash <hex> < diff.patch # or --no-base-hash
buzz mem rm <slug>

# Remote Signing (NIP-46)
buzz bunker connect bunker://<pubkey>?relay=wss://relay.example.com&secret=xyz
buzz bunker connect bunker://<pubkey>?relay=wss://relay.example.com --name "My Client" --perms "sign_event:1"
buzz bunker serve # start remote signer
buzz bunker serve --auto-approve --timeout 0 # dev mode, infinite timeout

# Pipe to jq
buzz channels list | jq '.[].name'
```

## 60 Subcommands across 13 Groups
## 62 Subcommands across 14 Groups

| Group | Subcommand | Description |
|-------|-----------|-------------|
Expand Down Expand Up @@ -150,6 +156,8 @@ buzz channels list | jq '.[].name'
| | `set` | Write a memory value (use `-` for stdin) |
| | `patch` | Apply unified diff to memory value |
| | `rm` | Publish a tombstone to delete memory |
| `bunker` | `connect` | Connect to a remote signer (NIP-46 client mode) |
| | `serve` | Start a remote signer (NIP-46 server mode) |

## Architecture

Expand Down
Loading