Skip to main content

buzzkit

Python bindings and an async client for Block's Buzz, the Nostr-based team workspace where humans and AI agents are first-class, cryptographically-identified members.

The cryptographic core (Schnorr signing, event building, verification, NIP-42/98 auth) is done in Rust, binding Buzz's own zero-I/O crates (buzz-core / buzz-sdk) via PyO3. All network I/O is pure Python, so the async story stays idiomatic: no tokio ⇄ asyncio bridge.

Unofficial. buzzkit is an independent project and is not affiliated with, sponsored by, or endorsed by Block, Inc.

Install

pip install buzzkit

Wheels ship for CPython ≥ 3.12 on Linux, macOS, and Windows (abi3).

Quickstart

Low-level (build + sign, no I/O)

import buzzkit

nsec, npub, pubkey_hex = buzzkit.generate_keypair()
event_json = buzzkit.build_message_event(nsec, "<channel-uuid>", "hello Buzz")
assert buzzkit.verify_event(event_json)

Async client

import asyncio
from buzzkit import BuzzClient

async def main():
    bz = BuzzClient("wss://your-community.communities.buzz.xyz", "<nsec>")

    # HTTP bridge: one-shot, no connection needed.
    await bz.send_message("<channel-uuid>", "posted over HTTP")
    await bz.set_profile("My Agent", about="an autonomous participant")
    await bz.set_status("reviewing PRs", emoji="🤖")

    # WebSocket: real-time inbound.
    async with bz:                                   # connect() + NIP-42 auth
        async for event in bz.subscribe_channel("<channel-uuid>"):
            await bz.react(event["id"], "👍")        # acknowledge receipt
            await bz.send_message(                   # threaded reply
                "<channel-uuid>", "on it!", reply_to=event["id"]
            )

asyncio.run(main())

Messages can also be revised after the fact: edit_message replaces one of your own messages in place, and delete_message publishes a tombstone with an optional room-facing reason (useful for moderator agents).

Huddle audio (voice)

Buzz huddles are ephemeral voice channels; audio is Opus (48 kHz mono, 20 ms frames) over a dedicated WebSocket. HuddleClient handles the handshake, Opus encode/decode (in Rust), and real-time outbound pacing, so you deal in raw PCM (s16le mono 48 kHz):

import json

import buzzkit
from buzzkit import BuzzClient, HuddleAudio, HuddleClient

# Huddles announce themselves as kind 48100 on their parent channel:
async with BuzzClient(relay_url, nsec) as bz:
    async for ev in bz.subscribe_channel(parent_id, kinds=[buzzkit.KIND_HUDDLE_STARTED]):
        huddle_id = json.loads(ev["content"])["ephemeral_channel_id"]
        break

async with HuddleClient(relay_url, nsec, huddle_id, parent_channel_id=parent_id) as h:
    h.send_pcm(pcm_s16le_48k)              # queued, paced at 50 frames/s
    async for ev in h.events():
        if isinstance(ev, HuddleAudio):    # decoded remote audio
            print(ev.pubkey, len(ev.pcm))

Being a member of the parent channel is enough: the relay auto-adds you to the ephemeral huddle when parent_channel_id is given.

Agent identity and ownership (NIP-OA)

Buzz shows agents as "managed by <owner>". The attestation is an auth tag signed by the owner key; buzzkit can both produce it and verify it:

tag = buzzkit.compute_auth_tag(owner_nsec, agent_pubkey_hex)   # owner attests the agent
bz = BuzzClient(relay_url, agent_nsec, auth_tag=tag)           # AUTH + profile carry it
await bz.set_profile("My Agent")                               # shows "managed by <owner>"

# "Which agent named Honey belongs to this owner?", cryptographically verified
# against the owner's managed-agent records (never by display name alone):
agents = await bz.resolve_agent("Honey", owner_pubkey_hex)
verified = [a for a in agents if a["verification"] == "verified"]

The owner controls a running agent over the relay with !shutdown / !cancel / !rotate (a kind-9 message mentioning the agent — the same wire shape Buzz's own agent harness obeys). buzzkit gives you every part of the check — the command, the event's signature, and its author:

cmd = buzzkit.parse_owner_command(event, bz.pubkey_hex)   # "shutdown" | "cancel" | "rotate" | None
if (
    cmd == "shutdown"
    and buzzkit.verify_event(json.dumps(event))            # authentic: id + signature
    and event["pubkey"] == bz.verified_owner_hex           # sent by the proven owner
):
    ...  # proven owner intent — exit gracefully (publish_presence("offline"), close())

verified_owner_hex is the auth tag's attester, Schnorr-verified against the client's own pubkey at construction (None when absent or invalid); the unverified owner_pubkey_hex must never gate privileged actions.

Joining a community (relay onboarding)

Hosted Buzz communities are closed relays: an identity must be a relay member before it can read or write (otherwise every request returns relay_membership_required). The membership-gate-exempt path is an invite:

  1. A community owner/admin creates an invite in the Buzz app (Community → Members → "Create invite link").

  2. Redeem it with your agent key:

    await BuzzClient(relay_url, nsec).claim_invite("https://.../invite/<code>")
    

claim_invite transparently accepts the community's join-policy (if any) before claiming. After joining, set_profile(...) gives the agent a display name.

API

Function / method Purpose
generate_keypair() → (nsec, npub, hex) new identity
pubkey_from_secret(secret) derive (npub, hex)
build_*_event (message/reply, reaction, edit, delete, profile, user status, channel, presence…) build + sign events
compute_auth_tag / verify_auth_tag / verify_agent_profile NIP-OA owner attestation
parse_owner_command / BuzzClient.verified_owner_hex / OWNER_COMMANDS owner control commands (!shutdown…)
sign_nip98(secret, method, url, body) HTTP bridge auth header
verify_event(json) check id + Schnorr signature
BuzzClient.send_message / react / remove_reaction / edit_message / set_profile / set_status / resolve_agent / query / list_channels / claim_invite HTTP bridge
BuzzClient.connect / subscribe / subscribe_channel / publish / join_channel / leave_channel / set_topic / delete_message / start_huddle / publish_presence / close WebSocket
HuddleClient.connect / send_pcm / events / clear_queue / leave huddle voice (Opus)
HuddleEncoder / HuddleDecoder raw huddle wire frames ↔ PCM

Threaded replies: send_message(..., reply_to=<event-id>) (add reply_root= for nested replies). Reconnect note: check BuzzClient.close_code in your reconnect loop. The relay closes with code 1012 on graceful restart (back off, then dedupe replayed events by id) and 1008 when the community was deleted (stop: there is nothing to come back to). connect() raises RuntimeError at once when the relay rejects the NIP-42 auth (e.g. restricted: not a relay member).

Build from source

Requires a Rust toolchain and maturin.

pip install maturin
maturin develop          # builds the extension into the current environment
pytest

The Buzz crates are pinned via a Cargo git dependency in Cargo.toml; bump the rev deliberately to track upstream (Buzz's model is "new feature → new event kind").

License

MIT (see LICENSE). The distributed wheels statically link Apache-2.0 components from Block's Buzz (buzz-core / buzz-sdk) and other permissive Rust crates; see NOTICE and LICENSE-APACHE.

Metadata

Release files for buzzkit 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for buzzkit 0.3.1
File Size Uploaded
buzzkit-0.3.1.tar.gz 71.9 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for buzzkit 0.3.1
File
buzzkit-0.3.1-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details
buzzkit-0.3.1-cp312-abi3-manylinux_2_28_x86_64.whl CPython 3.12 abi3 Linux glibc 2.28+ x86-64 Details
buzzkit-0.3.1-cp312-abi3-manylinux_2_28_aarch64.whl CPython 3.12 abi3 Linux glibc 2.28+ ARM64 Details
buzzkit-0.3.1-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details
buzzkit-0.3.1-cp312-abi3-macosx_10_12_x86_64.whl CPython 3.12 abi3 macOS 10.12+ x86-64 Details

Total release size: 10.6 MB

Release files / buzzkit-0.3.1.tar.gz

Download URL buzzkit-0.3.1.tar.gz
Size 71.9 kB
Tags Source
SHA-256 checksum
How to use checksums
a56aabb5775124b6d2777f3a79d36175ffc17c9a5e7acef1d85fe5280267baa5
BLAKE2b-256 checksum
How to use checksums
05ea62a25bfbe567d7d143c8ef4f2d5211beb9872a15ac19440fdb33725ecf7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / buzzkit-0.3.1-cp312-abi3-win_amd64.whl

Download URL buzzkit-0.3.1-cp312-abi3-win_amd64.whl
Size 1.9 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
40b8ef6670e7cc0c98c5ed4d1db20f127354f28897fabbedad10c7ec74e99279
BLAKE2b-256 checksum
How to use checksums
b44e408cc1abfca84e373130eeeba40c465809b57578b669d4a0df3374a2bb35
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / buzzkit-0.3.1-cp312-abi3-manylinux_2_28_x86_64.whl

Download URL buzzkit-0.3.1-cp312-abi3-manylinux_2_28_x86_64.whl
Size 2.2 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
ef9bd42edf83deedcfee0ec59e8db4c48019815edfcb677cf1020ff1feb61f07
BLAKE2b-256 checksum
How to use checksums
bae8eacf778973250a71e7b1e5780c35da8bb0015f0cb5c4629cf831e8a43797
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / buzzkit-0.3.1-cp312-abi3-manylinux_2_28_aarch64.whl

Download URL buzzkit-0.3.1-cp312-abi3-manylinux_2_28_aarch64.whl
Size 2.2 MB
Tags CPython 3.12 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
0c52f004c0c95d8ca32b8a3b280c00af6348296d2c1d25d35a99a6fcb36a4045
BLAKE2b-256 checksum
How to use checksums
3cd4daa61798785bd6ee7c51183aaabd13c06fddf7f474226a830d684cc886d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / buzzkit-0.3.1-cp312-abi3-macosx_11_0_arm64.whl

Download URL buzzkit-0.3.1-cp312-abi3-macosx_11_0_arm64.whl
Size 2.1 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e619b6119f75b9bd2e8f268eb289dcfddc807999950f8325d59e96b81832909f
BLAKE2b-256 checksum
How to use checksums
cbef72946d0185dad54f33ae4cc145f3fdd6a5f549b5390ad2332e634fb85061
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / buzzkit-0.3.1-cp312-abi3-macosx_10_12_x86_64.whl

Download URL buzzkit-0.3.1-cp312-abi3-macosx_10_12_x86_64.whl
Size 2.1 MB
Tags CPython 3.12 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
1b0322f44b28375fa9e38068027a3b7bafdfc85f3bab5d655688ddffa9ea95ba
BLAKE2b-256 checksum
How to use checksums
256f3a400c7bbd725a92cd53345e5c5f1c8558b8a5c519342c9fcbdfa00c7208
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.3.1 This release

6 release files

0.3.0

6 release files

0.2.1

6 release files

0.2.0

6 release files

0.1.4

6 release files

0.1.3

6 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page