Commit Graph

12 Commits

Author SHA1 Message Date
Salman Mohammed
44c1cc7df8 feat(buzz-cli): render an agent-friendly command tree in --help (#7584)
## 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>
2026-09-11 16:20:31 +00:00
Wes
6146c4fd16 feat(git): add default-branch management to relay and CLI (#7562)
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>
2026-09-11 09:10:43 -06:00
Will Pfleger
47d068e210 feat(cli): add buzz gifs command group and NIP-30 emoji tags on messages (#7259)
## What

Two new agent-facing capabilities in `buzz-cli`:

### 1. `buzz gifs` command group (agent KLIPY picker path)

Agents can now search and share GIFs via the relay's authenticated KLIPY
proxy without holding a provider credential.

```bash
buzz gifs search                         # trending GIFs
buzz gifs search --query "celebration"   # search GIFs
buzz gifs share --slug <slug>            # report selection to provider Recents
```

Output is a JSON array of GIF objects. Paste the `cdn_url` field
directly into `buzz messages send --content` — sending a GIF is a plain
message containing the CDN URL, no special send-path handling.

**Implementation details:**
- Gates on NIP-11 `supported_extensions` containing `buzz-gif` and
`gif.provider == "klipy"`
- Uses relay-relative paths from the NIP-11 `gif` descriptor — no
hardcoded paths; safe-path validation mirrors
`desktop/src/features/gifs/api.ts`
- New `post_json_authed` helper in `BuzzClient` handles NIP-98-signed
JSON POSTs and 204 No Content responses
- `customer_id` derived as `SHA-256(secret_key_bytes || '\0' ||
relay_url_bytes)[..16]` → 32 hex chars: stable, relay-scoped, not
computable from public data, no storage needed
- `locale` defaults to `$LANG` (stripped of encoding suffix) or `en_US`

### 2. NIP-30 custom emoji tags on outgoing messages

`buzz messages send` now automatically attaches `["emoji", shortcode,
url]` tags for any `:shortcode:` patterns in the content that resolve in
the workspace palette — identical to the desktop composer behavior.

```bash
buzz messages send --channel <uuid> --content "hello 👋 everyone 🎉"
# → event carries ["emoji", "wave", "..."] and ["emoji", "tada", "..."] tags
```

**Implementation details:**
- Hand-rolled single-pass scanner (no new dependency) implementing
`:([a-z0-9_-]+):` case-insensitively with canonical lowercase output —
mirrors `desktop/src/shared/lib/customEmojiTags.ts` exactly
- Zero extra relay round-trips when content contains no `:` character;
one `query` when candidates exist but none match
- Palette fetch reuses the existing `union_custom_emoji` logic from
`commands/emoji.rs`
- `build_message` in `buzz-sdk` gains a new `emoji_tags: &[Vec<String>]`
parameter (additive — all existing callers pass `&[]`); NIP-30 tag
attachment lives in the SDK alongside `imeta` tags
- MCP send path (`buzz-acp`) continues to pass `&[]` and is not
affected; the MCP gap is noted in a comment

## Files changed

| Crate | File | Change |
|-------|------|--------|
| `buzz-cli` | `src/commands/gifs.rs` | New — search + share handlers,
NIP-11 gating, tests |
| `buzz-cli` | `src/commands/mod.rs` | `pub mod gifs` |
| `buzz-cli` | `src/lib.rs` | `Gifs(GifsCmd)` variant, dispatch arm,
inventory test update |
| `buzz-cli` | `src/client.rs` | `post_json_authed` helper |
| `buzz-cli` | `src/commands/emoji.rs` | `scan_shortcodes` +
`resolve_emoji_tags_for_content` + tests |
| `buzz-cli` | `src/commands/messages.rs` | Emoji scan + tag injection
in `cmd_send_message` + seam tests |
| `buzz-cli` | `README.md` | `buzz gifs` section + emoji-in-messages
note |
| `buzz-sdk` | `src/builders.rs` | `build_message` gains `emoji_tags`
param + tests |
| `buzz-acp` | `src/pool.rs` | Update `build_message` call site (`&[]`)
|
| `buzz-acp` | `src/setup_mode.rs` | Update `build_message` call site
(`&[]`) |
| `countdown-bot` | `src/main.rs` | Update `build_message` call site
(`&[]`) |

Relates to: https://buzz.block.builderlab.xyz — buzz-team channel thread
on agent GIF/emoji support

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
2026-09-02 20:03:38 -04:00
morgmart
84c095f8be feat(cli): accept Buzz message links for thread reads (#6359)
## 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>
2026-08-20 12:17:50 -06:00
John Matthew Tennant
262f2392e3 fix(cli): resolve agents from owner records (#3178)
## 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>
2026-07-30 09:28:10 -04:00
kagan yaldizkaya
60158fce3e feat(cli): add users set-status command for NIP-38 profile status (#3253)
## 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>
2026-07-28 13:44:57 -04:00
Will Pfleger
a041e2d21e Revert "fix(cli,relay): resolve agents by verified owner" (#3168)
Reverts block/buzz#2615
2026-07-27 14:10:16 -04:00
John Matthew Tennant
c3084b36d9 fix(cli,relay): resolve agents by verified owner (#2615)
## 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>
2026-07-27 13:10:42 -04:00
thomaspblock
f94324598d feat(cli): manage repository protection rules (#2193) 2026-07-21 08:57:08 +02:00
Tyler
19919e1810 feat(cli): --author and --since filters on buzz messages search (#1665)
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
2026-07-09 22:05:28 -04:00
Aaron Goldsmith
52b6365e17 docs: update sprout repository references and document buzz mem (#1333)
Signed-off-by: Aaron Goldsmith <aargoldsmith@gmail.com>
2026-06-28 14:53:03 +00:00
Will Pfleger
d99ad131f1 refactor: rename sprout backend to buzz (#958)
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <wpfleger@block.xyz>
Signed-off-by: Will Pfleger <wpfleger@squareup.com>
Signed-off-by: Will Pfleger <wpfleger96@gmail.com>
Co-authored-by: npub1mn7jgtj4w2pd0g0zeuhxsa6jy6p0rewxz4kujt98my82ahfmp72sxjexk7 <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub1fgdl5qqnh3k3f2xkqrvt7cujalhm623x4s7fdjdj5yrtp5fzjl9qrjpucw <4a1bfa0013bc6d14a8d600d8bf6392efefbd2a26ac3c96c9b2a106b0d12297ca@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: npub16v54tttfqacx9ycvc3k0ut0npj564ahcuajzy6qjvh57ntmsf4uq4806j2 <d32955ad69077062930cc46cfe2df30ca9aaf6f8e76422681265e9e9af704d78@sprout-oss.stage.blox.sqprod.co>
Co-authored-by: Will Pfleger <wpfleger96@gmail.com>
2026-06-10 19:29:51 -04:00