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:
-
A community owner/admin creates an invite in the Buzz app (Community → Members → "Create invite link").
-
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)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| buzzkit-0.3.1.tar.gz | 71.9 kB | Without provenance | Details for buzzkit-0.3.1.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| buzzkit-0.3.1-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details for buzzkit-0.3.1-cp312-abi3-win_amd64.whl |
| buzzkit-0.3.1-cp312-abi3-manylinux_2_28_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ x86-64 | Details for buzzkit-0.3.1-cp312-abi3-manylinux_2_28_x86_64.whl |
| buzzkit-0.3.1-cp312-abi3-manylinux_2_28_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.28+ ARM64 | Details for buzzkit-0.3.1-cp312-abi3-manylinux_2_28_aarch64.whl |
| buzzkit-0.3.1-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details for buzzkit-0.3.1-cp312-abi3-macosx_11_0_arm64.whl |
| buzzkit-0.3.1-cp312-abi3-macosx_10_12_x86_64.whl | CPython 3.12 | abi3 | macOS 10.12+ x86-64 | Details for buzzkit-0.3.1-cp312-abi3-macosx_10_12_x86_64.whl |
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
|
Security for buzzkit 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.