## Summary
`crates/buzz-acp/src/base_prompt.md` carries a hand-maintained `Group |
Key commands` table of the `buzz` CLI. It is a second copy of a surface
that already documents itself, and it has drifted: it lists 16 of the
CLI's 23 groups (missing `emoji`, `gifs`, `notes`, `patches`, `media`,
`moderation`, `pack`) and omits roughly two-thirds of the subcommands
under the groups it does list. its hard to keep it in sync.
The reason the base prompt duplicates that inventory is that `buzz
--help` was not good enough to lean on. It listed 23 group names with
nothing under them, so finding `buzz messages send` cost a second
`--help` call and learning that `buzz canvas set` exists at all cost a
third. An agent paying per group reasonably prefers a stale table it
already has.
This PR fixes the help output so the prompt can point at it instead.
`buzz --help` now prints the whole tree — every group, its subcommands,
and their descriptions — in one invocation:
**Before**
```
Commands:
messages Send, read, search, and manage messages
channels Create, configure, and manage channels
canvas Get and set channel canvas documents
```
**After**
```
Commands:
messages Send, read, search, and manage messages
send Send a message to a channel
send-diff Send a code diff / patch to a channel
edit Edit a previously sent message
...
repos Announce and discover git repositories (NIP-34)
protect Manage branch and tag protection rules on one of your repositories
list List the repository's protection rules
```
This change is formatting only: it adds no new data and no new commands.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Authored by Brain and opened on behalf of Wes (`wesbillman`).
## Summary
Add `buzz repos default-branch get/set` and the relay operation it
needs. Git push changes branch tips but cannot select the server's
symbolic HEAD. This selects an existing branch without deleting
branches, moving refs, or changing packs.
- Reuse immutable Git manifests and captured-ETag CAS; concurrent
pushes/default changes conflict, including stale no-ops.
- Require request-specific NIP-98, body binding, fail-closed replay
protection, host tenancy, current channel membership and
repository-management authority. Push/project roles alone are
insufficient.
- Send the CLI mutation once, without redirects; ambiguous delivery
retains the observed digest and is non-retryable.
- Document the narrow HTTP exception to Nostr-first, delegation scope
and admission-time ACL revocation. Kind:30618 remains derived; the
manifest CAS is authoritative.
- Register the Postgres/Redis/MinIO route and fresh-clone tests in the
existing Backend Integration lane.
## Review fixes — `7457bda50afa6b52e36315572fa96928b2e21db6`
- Reject signed valueless `payload` tags when verifying a body; preserve
the shared verifier's intentional absent-payload compatibility. The real
settings route now proves 401, unchanged manifest pointer, and unchanged
kind:30618 event IDs for malformed and other invalid credentials.
- Require a nonempty returned branch and `head == refs/heads/{branch}`;
SET additionally requires the returned branch to equal the attempted
branch. Malformed/mismatched mutation responses remain non-retryable
`DeliveryUnknown`, retaining the attempted branch and original digest.
Invalid reads fail before any POST.
- Strengthen the later-push/fresh-clone regression to select
`release/v1` while `main` exists.
## Verification
At `7457bda50afa6b52e36315572fa96928b2e21db6`:
- Full pre-push passed (all 14 Rust test groups, serialized Tauri
tests/clippy, file-size and branch-skew gates; 522 seconds). No hooks
disabled.
- All four isolated Postgres/Redis/MinIO settings tests pass, including
real Smart HTTP `ls-remote --symref` and fresh clone on `release/v1`.
- All 15 focused NIP-98 verifier tests and three default-branch CLI
tests pass; malformed credentials and missing-branch responses were
reproduced failing before the fixes.
- Five targeted mutants are killed: restoring the valueless-payload
bypass, weakening canonical HEAD validation, accepting an empty branch,
dropping requested-branch confirmation, and omitting hydrated HEAD for
the selected non-main branch. Mutations ran in a separate worktree and
target directory; original patch bytes were verified restored.
- `cargo clippy -p buzz-auth -p buzz-cli -p buzz-relay --all-targets --
-D warnings`, formatting, diff and file-size checks pass on the fixed
tree.
Earlier validation at `bb195b140`: seven Git authorization database
regressions and 28 existing transport tests passed (three infrastructure
cases in that module not selected); four mutations killed
management/replay/CAS/redirect regressions. Full pre-push passed with
`RUST_TEST_THREADS=1` (all 14 Rust groups, Tauri clippy and 3,173 tests,
size/branch-skew gates). Serial execution avoids an unrelated
process-global Desktop discovery counter flake; no hooks disabled or
Desktop changes.
Carl and Jude's review findings are addressed in the new head; **fresh
reviewer and exact-head security confirmation remain required**. The
earlier source review is not approval of this revision. No claim of
green new-head CI.
## Rollout
Merge and **deploy the relay support first**, then build/use the updated
CLI and explicitly set/verify the desired default. No schema migration.
This PR does not deploy anything or change a live repository.
Originating conversation (channel
`8e2fda80-9142-4df8-8e14-da288bea6471`):
buzz://message?channel=8e2fda80-9142-4df8-8e14-da288bea6471&id=8a7a9cf12737abc1e16605f241300be940a1691ef0992b35197afe26c563108d
---------
Signed-off-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz>
## Summary
- let `buzz messages thread` accept a canonical `buzz://message` link
directly
- treat the selected message ID as authoritative, verify its channel,
and derive its containing thread root from the event
- reject stale or forged `thread` hints that disagree with the selected
message
- preserve the existing `--channel` / `--event` form while allowing it
to target any message in a thread
## Why
Agent skills should be able to hand first-class Buzz links to the public
Buzz CLI instead of carrying their own URL parsing wrappers. Link
handling belongs with the CLI that owns the protocol; identity and relay
selection remain explicit through the existing Buzz CLI environment and
do not read Buzz Desktop private state.
## Verification
- `cargo test -p buzz-cli` — 360 passed
- `cargo clippy -p buzz-cli -- -D warnings`
- `cargo fmt --all -- --check`
- repository pre-push gates, including 5,070 Desktop tests
- final architecture/code review — no must-fix findings
A relay-backed manual smoke test was not run because this session did
not have `BUZZ_RELAY_URL` and `BUZZ_PRIVATE_KEY` configured; the change
has focused parser, CLI argument, channel/root binding, and mismatch
tests.
---------
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
## Context
`buzz users get --name Honey` searches relay-wide profiles and can
return an identically named agent owned by someone else. This caused
agents from the wrong owner to be added to a channel.
## Summary
This bug fix scopes exact-name agent lookup to owner-authored
managed-agent records, then cryptographically verifies each returned
profile's NIP-OA `auth` tag before asserting ownership. The relay and
database contracts remain unchanged.
### Related issue
None found.
## Changes
- Adds `buzz users get --name Honey --owner me|<hex>|<npub>`.
- Resolves `me` to the NIP-OA owner when the CLI runs as an agent,
otherwise to the CLI identity.
- Matches kind `30177` managed-agent record names exactly and
case-insensitively under the requested owner.
- Requires exactly one valid NIP-OA `auth` tag whose verified owner
equals the requested owner and whose `kind` and `created_at` conditions
apply to the profile event before returning `owner_pubkey` or
`owned_by_me: true`.
- Keeps missing, malformed, stale, condition-mismatched, or unverifiable
owner-record candidates visible with `owned_by_me: false` and an
explicit `verification` value.
- Returns every same-name record for the owner so callers can require
explicit selection when duplicates remain.
- Preserves the existing output shape and client-side name filter for
unscoped searches.
- Documents the distinct owner-scoped managed-agent lookup and unscoped
NIP-50 lookup modes.
### Testing
The reviewer-reproducible red and green commands below exercise the
ownership bug against the target branch and this branch.
## Screenshots
Not applicable. This is a CLI-only change.
## Reviewer-reproducible examples
The lookups below were run against the live relay from `main` and this
branch.
### Red: unscoped lookup returns the 100-profile relay-wide cap and
excludes John's agents
On `main`:
```bash
cargo run -q -p buzz-cli -- users get --name Honey \
| jq '{count: length, first_three: .[:3] | map(.pubkey), johns_agents: map(select(.pubkey == "31b29bcbe69d6716fbb7ba33602b89200bfc9ddfdabcfd1ea6fbfa70b816dfc7" or .pubkey == "4597ac725bba33fc7dd0454c1e2316a5ed770426acf667837d46f6553b3fcf54"))}'
```
Observed output:
```json
{
"count": 100,
"first_three": [
"20d27fc6c0ab4f50b66d1a32a64c5ca1fb985254143ce911f61ab7733333c3d7",
"00644478cdd9032c563ddc712b3687d8345d948945aab3c18bab95afbf6f519a",
"93c16697d0e58007bc11fb953208bc6b1cff387b2dee094abc10bf82dfee5424"
],
"johns_agents": []
}
```
`main` also rejects the owner-scoped command:
```bash
cargo run -q -p buzz-cli -- users get --name Honey --owner me
```
```text
error: unexpected argument '--owner' found
Usage: buzz users get --name <NAME>
```
### Green: owner-scoped lookup distinguishes verified and unresolved
records
On this branch:
```bash
cargo run -q -p buzz-cli -- users get --name Honey --owner me \
| jq 'map({pubkey,display_name,owner_pubkey,owned_by_me,verification})'
```
Observed output:
```json
[
{
"pubkey": "0ca77314d7ac8b3fcf6c647cc8cb9c3afd840db3b2a8ff2079f09a168de1827e",
"display_name": null,
"owner_pubkey": null,
"owned_by_me": false,
"verification": "missing_profile"
},
{
"pubkey": "31b29bcbe69d6716fbb7ba33602b89200bfc9ddfdabcfd1ea6fbfa70b816dfc7",
"display_name": "Honey",
"owner_pubkey": "67252b09c31a995daa63aada26569fbc6a3d12f573113f001ce7432f870da820",
"owned_by_me": true,
"verification": "verified"
},
{
"pubkey": "4597ac725bba33fc7dd0454c1e2316a5ed770426acf667837d46f6553b3fcf54",
"display_name": "Honey",
"owner_pubkey": "67252b09c31a995daa63aada26569fbc6a3d12f573113f001ce7432f870da820",
"owned_by_me": true,
"verification": "verified"
}
]
```
Only the two profiles with valid NIP-OA proofs assert ownership. The
owner-authored record whose profile is absent remains visible but cannot
be selected as verified ownership.
---------
Signed-off-by: npub1qye6rec0htgg3np8yt6plpyyg8cyffaq66emt3kmk05eylckkzhq0hnf2k <0133a1e70fbad088cc2722f41f848441f044a7a0d6b3b5c6dbb3e9927f16b0ae@buzz.block.builderlab.xyz>
Co-authored-by: npub1qye6rec0htgg3np8yt6plpyyg8cyffaq66emt3kmk05eylckkzhq0hnf2k <0133a1e70fbad088cc2722f41f848441f044a7a0d6b3b5c6dbb3e9927f16b0ae@buzz.block.builderlab.xyz>
## Summary
The desktop client renders a persistent user status (NIP-38 kind:30315,
`d:general`) as the status line on profiles, but the CLI had no way to
set it — only ephemeral presence (`set-presence`, kind:20001).
Integrations that want a scriptable, durable status line (for example a
now-playing music bridge that shows the current TIDAL track on a
profile) had no entry point.
## Screenshots
<img width="1455" height="960" alt="1"
src="https://github.com/user-attachments/assets/f1669ec6-212b-4f6e-ad53-07df9aacffc9"
/>
<img width="1455" height="960" alt="2"
src="https://github.com/user-attachments/assets/5bf70f47-e5b5-4eb0-a426-b5f1ef90d2ec"
/>
This adds:
```bash
buzz users set-status --text "Working on the relay" --emoji "🔧"
buzz users set-status --text "" --emoji "🎶" # intentional emoji-only status
buzz users set-status --clear # removes the status
```
- Signs and submits the replaceable kind:30315 event via the HTTP bridge
(no WS needed — unlike presence, user status is a stored event).
- Uses the `d:general` coordinate the desktop client already reads for
the profile status line, and the same `emoji` tag shape
`SetStatusDialog` publishes.
- Event construction lives in `buzz_sdk::build_user_status()`, keyed off
`buzz_core::kind::KIND_USER_STATUS`, so the CLI command is a thin
sign/submit wrapper. Text and emoji are trimmed; a blank emoji is
omitted rather than emitted as an empty tag.
- Clearing is the explicit `--clear` flag, mutually exclusive with
`--text`/`--emoji`. It publishes an empty-content event carrying only
`d:general`, which the desktop treats as no status. `--text ""` with an
`--emoji` is an emoji-only status, not a clear.
---------
Signed-off-by: Kagan Yaldizkaya <kagan@squareup.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
## Context
`buzz users get --name Honey` searches relay-wide profiles and returns
up to 100 identically named results without verified ownership metadata.
An agent resolving “my Honey” cannot distinguish the requesting human's
agent from another owner's agent, and the owned match can be excluded by
the result limit. This caused the wrong Honey and Bumble pubkeys to be
added to a channel.
## Summary
This bug fix makes personal-agent resolution owner-aware. Callers can
filter profiles by a verified owner identity before result limits are
applied, and all profile results expose enough ownership context to
diagnose duplicate names.
## Changes
- Adds `buzz users get --owner me|<hex>|<npub>` for name and pubkey
lookups.
- Resolves `me` to the NIP-OA owner identity when the CLI runs as an
agent.
- Filters profiles by the relay's verified `agent_owner_pubkey`
relationship before applying the result limit.
- Returns `owner_pubkey`, `owner_display_name`, and client-relative
`owned_by_me` in compact and JSON output.
- Returns an empty result when no owned profile matches instead of
removing the ownership constraint.
- Rejects malformed owner values instead of silently running an unscoped
query; explicit `null` remains equivalent to no owner filter for
ordinary CLI lookups.
- Rejects owner constraints on specialized channel-window, feed, and
thread filters that cannot enforce author filtering.
- Scopes owner filtering and enrichment to the active community.
- Adds a partial `(community_id, agent_owner_pubkey)` index for owner
lookups.
- Documents the safe `users get --name Honey --owner me` lookup.
## Reviewer-reproducible examples
The relay-backed test creates two same-name agents with different
verified owners, queries through the HTTP `/query` route, verifies only
the selected owner's agent is returned with verified owner metadata, and
verifies a missing owner returns `[]`.
```bash
cargo test -p buzz-relay query_agent_owner_returns_only_verified_owner_matches --lib -- --ignored
```
The owner/author intersection and unsupported-specialized-filter
contracts also have infrastructure-free relay tests:
```bash
cargo test -p buzz-relay agent_owner --lib
```
The CLI surface is visible in command help:
```bash
cargo run -q -p buzz-cli -- users get --help | grep -- --owner
```
```text
--owner <OWNER> Filter agents by verified owner (`me`, 64-char hex, or npub)
```
## Validation
- `cargo test -p buzz-cli` (252 passed)
- `cargo test -p buzz-db` (84 passed, 122 infrastructure tests ignored)
- `cargo test -p buzz-relay --lib` (owner-filter tests pass; the full
local suite is blocked by unrelated Postgres pool timeouts in
media/admin tests)
- `cargo test -p buzz-relay
query_agent_owner_returns_only_verified_owner_matches --lib --
--ignored` (passed)
- `cargo check --workspace --all-targets`
- `cargo fmt --all -- --check`
- Pre-push Rust, Desktop, and Desktop Tauri suites passed
- Pre-push mobile suite could not start because `flutter` is not
installed
- `pnpm check:file-sizes` (passed after rebasing onto current `main`)
---------
Signed-off-by: npub1qye6rec0htgg3np8yt6plpyyg8cyffaq66emt3kmk05eylckkzhq0hnf2k <0133a1e70fbad088cc2722f41f848441f044a7a0d6b3b5c6dbb3e9927f16b0ae@buzz.block.builderlab.xyz>
Co-authored-by: npub1qye6rec0htgg3np8yt6plpyyg8cyffaq66emt3kmk05eylckkzhq0hnf2k <0133a1e70fbad088cc2722f41f848441f044a7a0d6b3b5c6dbb3e9927f16b0ae@buzz.block.builderlab.xyz>