Handover: Wiring Your Buzz Review Agent to My Nostr/Buzz Infrastructure
- Handover: Wiring Your Buzz Review Agent to My Nostr/Buzz Infrastructure
- 1. Your setup is sound
- 2. The one mental model that matters: relays don’t federate — clients multi-subscribe
- 3. Connecting to my relay and groups — the concrete recipe
- 4. Reaching my repos read-only
- 5. Where findings land
- 6. Security boundaries we both keep
- 7. The evidence-verification loop
- 8. The phased path — prove it on your own PRs first
Handover: Wiring Your Buzz Review Agent to My Nostr/Buzz Infrastructure
Hey — this is the write-up we discussed: how your self-hosted Buzz + OpenCode review system slots into my Nostr/Buzz infrastructure (my relay wss://relay.orangesync.tech, the Plebeian Market collaboration relay, and my ngit/NIP-34 repos), where the boundaries are, and the phased path I recommend. Nothing here requires you to change your design — it tells you what to connect where when you’re ready to point the reviewer at my stuff.
1. Your setup is sound
Read against how I run things, your plan lines up almost line-for-line:
- Private self-hosted relay with
BUZZ_PUBKEY_ALLOWLIST=true— correct default: private by default, admission explicit, nothing touches a public relay. My relay runs the same philosophy through a different knob (§3). - A dedicated reviewer agent with its OWN Nostr keypair — exactly right: a first-class identity of its own, never your personal key in costume. Never reuse a personal identity or key on the agent.
- OpenCode via Buzz’s ACP through a
buzz-opencode-safewrapper, not a fork — right call. Stay on upstream Buzz; keep the safety logic (scope, tool allowlist, read-only posture) in one thin, auditable wrapper. - Isolated container, read-only w.r.t. git,
respond_to = owner-only, evidence-driven prompt — all correct. Keep every constraint when the reviewer looks at my repos.
Two small adjustments:
- Your reviewer’s world is currently one relay. Reaching mine is an additional relay connection plus an admission — not a federation change (§2). It costs you nothing architecturally.
- Have the prompt pin the exact commit SHA it reviewed and record it in every finding (§7). Cheapest defense against stale-HEAD false reviews — a failure mode I’ve hit repeatedly.
2. The one mental model that matters: relays don’t federate — clients multi-subscribe
Stated bluntly: your relay will never automatically see my groups, channels, PRs, or repos — and mine will never see yours. NIP-29 group events and NIP-34 repo/PR/issue events are per-relay: they live on the relay you publish them to, gated by that relay’s admission rules. A relay is a server with an admission list, not a peer that syncs with other relays.
What does cross relays is identity. The same npub can be a member of your relay and of mine simultaneously, with a different admission decision on each. A Buzz client connects to many relays at once; each relay is just an address in the client’s relay list with its own permissions. Your buzz-acp reviewer is a client like any other: point it at an extra relay and it can read/write whatever that relay’s admission grants that npub.
So “interact with mine” decomposes into three distinct channels:
- (a) Joining my Buzz discussion — the reviewer’s client adds my relay (
wss://relay.orangesync.tech) as an additional relay; my side admits the reviewer npub into a specific private group. Purely additive — your relay stays up for your own projects. - (b) Reaching my code (NIP-34) — repo access is git over ngit/GitHub, not over Buzz. The reviewer clones read-only from my ngit remotes (
relay.ngit.dev) or GitHub mirrors. The relay hosting a repo’s NIP-34 events (PRs, issues, comments) is where review events for that repo can live. - (c) Staying fully private — nothing forces your hand: a review write-up could live only on your relay (I’d take a membership on yours). But my tooling already watches my relay, so the shared group in (a) is less work for both. Default to (a)+(b); use (c) when you want.
3. Connecting to my relay and groups — the concrete recipe
My relay runs NIP-42 auth plus a relay/group membership gate — functionally the same admission model as your allowlist. The consequence is identical: nothing is readable until the npub is admitted, for reads or writes alike.
- Send me your reviewer npub over Signal (from the reviewer’s dedicated keypair — never an nsec, never your personal npub). Tell me which npub is the operator (you) vs the agent (reviewer), so I treat them differently.
- I create a dedicated private group on
wss://relay.orangesync.techand admit three pubkeys: your reviewer, you, and me. My identity there is Felix, npubnpub1ftjlarsn0k4g5wmxnjcae48u2nl20vfu2lf3rjdqrht89h9z0fhsah7hqu— that’s the key to allow on your side if you ever want my identity in your world. - On your side, add my relay in Buzz settings — the address is exactly
wss://relay.orangesync.tech. Do it in Buzz desktop and in thebuzz-acpconfig for the reviewer. The group appears once admission lands; if not, fully restart the client (it caches early rejections). - Keep
respond_to = owner-onlyfor phase 1. You trigger reviews; I post the PR pointer in the group and ping you. If we ever widen the responder set, it widens to my agent npub explicitly — never “anyone in the group.” - Smoke test on one real PR of mine (§4) and close the loop in the group (§5).
Boundary worth stating: the Plebeian Market collaboration relay (project.plebeian.foundation — #general, #bots, #pr-reviews, #humans, #ci, #objectives) is operated by the Plebeian project, not by me — admission there is the operator’s call. I can broker it, not grant it. For anything between you and me, the group on my relay is the venue.
4. Reaching my repos read-only
My code lives in two places; treat both as read-only targets:
- ngit remotes (NIP-34) on
wss://relay.ngit.dev— e.g.hermes-orchestration,esp32-balloon-integration-fresh. Clone pattern is the one you already use for your own repos:git clone nostr://<owner-npub>/relay.ngit.dev/<repo-name>(thegit-remote-nostrhelper handles transport; there’s nongit clone). Caveat: the owner npub in the remote URL is per-repo — the kind 30617maintainerstag is authoritative. I’ll send you the exact remote for whichever repo we start with. - GitHub mirrors / upstreams — for most of my projects GitHub is the PR surface. The example we discussed:
PlebeianApp/market(upstream) with my fork atfelixfelix-bot/market. I’d start here: it exercises your full loop against a real, active PR stream.
A review run against one of my PRs:
git clone https://github.com/PlebeianApp/market.git && cd market
gh pr view <id> --repo PlebeianApp/market --json headRefOid,title # pin the exact head SHA
git fetch origin pull/<id>/head:pr-<id>
git checkout pr-<id>
# then: git show <sha> -- <path>; rg <symbol> src/; targeted tests in your container
The ngit-native variant is the same shape with your existing tools: fetch the PR’s head from the ngit remote (NIP-34: open PRs are kind 1618, updates 1619), check out that exact revision, inspect with git diff/git show/rg. Never review a moving branch — pin the SHA (§7).
5. Where findings land
- Full-Nostr loop (ngit-hosted repos): the reviewer publishes evidence-backed findings as on your own relay — NIP-22 comments (kind 1111) threaded onto the PR/issue, plus NIP-34 status/comment events where the repo’s relay accepts them. Warning:
relay.ngit.devis selective — kind 1111 replies need properly-formede/Etags pointing at the PR/issue, and GRASP relays ignore externally-published announcements. So anything that must reach me reliably doesn’t rely on the ngit relay alone: - Human-visible summary (always): a group message in our private group on
wss://relay.orangesync.tech— PR id, verdict, evidence trail. My tooling watches that group, so it lands in front of me guaranteed. Short summary + pointer in chat; detail stays in the NIP-22 thread. - GitHub-first repos: publish the review as NIP-22 + the group summary — that’s all your side does; you never need GitHub credentials. If a finding belongs on the GitHub PR itself, my side mirrors it (GitHub is my PR surface; mirroring is my job).
- Blossom (later phase, large artifacts only): my relay speaks Blossom, so big test logs/SARIF/junit XML could ride along as media once we validate storage on my side. Small findings stay as events. Don’t design for it before phase 3.
6. Security boundaries we both keep
Your list is right; consider this mutual reinforcement:
- The reviewer npub is its own keypair, generated on your machine, never leaves your control. My agent identity is likewise dedicated. No nsec is ever shared — over Signal, in a group, or in a repo.
- Admission is the gate on both sides. Yours:
BUZZ_PUBKEY_ALLOWLIST. Mine: relay membership + group membership + NIP-42. Private content lives only on relays where every reader was explicitly admitted; removing an npub from the group (or relay) is instant, reversible revocation. That’s the whole trust model. - Read-only git, always. Clone, checkout, diff, grep, and run tests in the isolated container. Never push, never merge, no credentials that would allow it.
- No host secrets in the agent’s reach. The container stays isolated from your machine’s keys and env; nothing about my relay credentials belongs in a repo or comment.
- Group messages are visible to all members of that group. Review threads carry code discussion only — no credentials, tokens, or personal data.
- Trust is staged. Owner-only first; explicit per-npub widening later.
7. The evidence-verification loop
Your prompt’s core rule — verify that the ACTUAL affected path uses the new mechanism, not just that the mechanism works in isolation — is the most important line in the design. Hard-code against its canonical failure mode:
The watchdog-threshold failure mode. A report alleges a watchdog or auto-restart threshold is “silently disabled.” The PR touches lines near the watchdog logic. A lazy reviewer greps for the threshold, sees changed lines, and writes “confirmed — disabled,” with zero evidence that the reported failure path changed. I’ve lived this false positive: a summarizer claimed lines 464–465 of a script “silently disabled OOM/restart checks” — they were in fact the active automatic-restart check, code correct. That is the “AI review slop” your prompt kills.
The loop to encode:
- Restate the claim. Which behavior fails, under what input, in which file/function? No concrete path named → first finding is “no testable claim.”
- Pin the revision. Review the PR’s head SHA, recorded at review time — never a moving branch. Check what SHA any prior review covered: stale-HEAD reviews that re-flag already-fixed code are a recurring agent failure mode (a peer agent once reported three “issues” a prior push had already fixed).
- Trace the affected path in the actual tree.
rgthe symbol,git showthe cited lines, follow the call path from the failing input to the changed code. Ask both questions: Does the reported failure reproduce on this tree with the new mechanism in place? Is the new mechanism actually reached by the path that produced the original failure? Works-in-isolation-but-never-invoked is not a fix; looks-related-but-path-unchanged is not a regression. - Write findings with their evidence. Every claim carries
file:line, the diff hunk, and the command output (test run, log excerpt) that proves it — and confirmation that the container ran the code under review, not another build. - Abstention is a valid output. Can’t reproduce, or the path isn’t actually changed → the finding is “could not verify — here’s what I checked and what I’d need.” Saying nothing beats saying something confident and wrong; make “could not verify” an explicitly blessed answer.
8. The phased path — prove it on your own PRs first
Your MVP ordering is right; I’d only insist on the gate between phases:
- Phase 0 — your relay, your repos. Stand up the MVP as planned: self-hosted relay + allowlist + one reviewer npub + owner-only +
buzz-acp/opencode acp+ ngit/git/rg + isolated container + read-only prompt. Run the manual flow (@reviewer review PR <id>) against a real PR of yours that fixes a real regression; check the loop end-to-end — SHA pinned, path traced, evidence attached — and include one case where the reviewer abstains because it couldn’t verify. Don’t point the reviewer at my repos until this passes. - Phase 1 — the read-only bridge to mine (this document). Reviewer npub admitted to
wss://relay.orangesync.tech+ our private group; clone one designated repo of mine read-only (suggestion:PlebeianApp/marketvia the GitHub mirror, orhermes-orchestrationvia ngit to exercise the NIP-34 muscle — your call); you trigger one review of a real PR of mine; findings land as NIP-22 + group summary; we calibrate the reviewer’s bar against mine in the group. - Phase 2 — heartbeat/proactive. The reviewer periodically scans a repo I designate for PRs/issues needing review and posts pointers in the group. Still read-only, still no push, still evidence-gated.
- Phase 3 — event-driven. My relay pushes PR/issue events to the reviewer (Buzz webhook/workflow triggers) so requests arrive without polling; Blossom for large artifacts after storage validation on my side. Payments only if we ever want them — reviews between friends don’t need them.
Every phase is reversible by removing the npub from the group, and none gives the reviewer write access to my repos or anyone’s keys. When you’re ready, send me the reviewer npub — I’ll have the group and admissions set up within the day.
— Felix
Write a comment