feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled

Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
2026-08-13 18:34:25 +08:00
parent 61c3fa1df9
commit 9dfa06ffee
3785 changed files with 1085458 additions and 2 deletions
+529
View File
@@ -0,0 +1,529 @@
# Contributing to Buzz
Welcome, and thank you for your interest in contributing! Buzz is an
open-source project and we're glad you're here. This guide will help you
get from zero to a merged pull request.
If you have questions that aren't answered here, [open an issue](https://github.com/block/buzz/issues/new).
---
## Table of Contents
1. [Code of Conduct](#code-of-conduct)
2. [Before You Open a PR](#before-you-open-a-pr)
3. [Setting Up the Development Environment](#setting-up-the-development-environment)
4. [Running Tests](#running-tests)
5. [Code Style](#code-style)
6. [Making a Pull Request](#making-a-pull-request)
7. [Architecture Overview](#architecture-overview)
8. [Ecosystem](#ecosystem)
9. [How to Add a New Event Kind](#how-to-add-a-new-event-kind)
10. [How to Add a New MCP Tool](#how-to-add-a-new-mcp-tool)
11. [How to Add a New API Endpoint](#how-to-add-a-new-api-endpoint)
12. [License and CLA](#license-and-cla)
---
## Code of Conduct
This project follows the [Contributor Covenant v2.1](CODE_OF_CONDUCT.md).
By participating you agree to uphold these standards. Please report
unacceptable behavior to **conduct@buzz-relay.org**.
---
## Before You Open a PR
Before starting, search [open PRs](https://github.com/block/buzz/pulls) and [open issues](https://github.com/block/buzz/issues) for duplicates — someone may already be working on the same thing. When you open your PR, link the closest existing one in the description (or say "none found").
For anything beyond a small fix, opening an issue first is strongly recommended. Describe the problem and proposed solution so a maintainer can acknowledge the approach before you build — it avoids two people building the same thing in parallel.
Buzz is an agent platform, so AI-assisted PRs are welcome. No need to disclose the tools you used, but you own and must have reviewed the final code. Submissions that are clearly unreviewed may be closed with a pointer here.
We squash-merge, so your PR title becomes the commit subject in `main`. Use [Conventional Commits](https://www.conventionalcommits.org/) format: `feat(mcp): add get_feed_actions tool`. The type prefix (`feat`, `fix`, `docs`, `refactor`, `test`, `chore`) is required. See the [Commit Messages](#commit-messages) section for the full reference.
### Sign Your Commits
```bash
git commit -s
```
Every commit needs a Developer Certificate of Origin (DCO) sign-off. The `-s` flag appends a `Signed-off-by` trailer that certifies you wrote the change and can contribute it under the project license. The **DCO Check** will block your PR without it.
#### Fix unsigned commits already pushed
```bash
git rebase --signoff main
git push --force-with-lease
```
#### Auto-setup for future commits
```bash
just hooks
```
This installs a `commit-msg` hook that adds the sign-off trailer automatically for `git commit` and `git merge`. Other flows (`git rebase`, `git cherry-pick`) still need their own flag — `--signoff` and `-s` respectively.
We review as capacity allows — focused PRs that follow this guide move fastest.
---
## Setting Up the Development Environment
### Prerequisites
| Tool | Version | Notes |
|------|---------|-------|
| Rust | 1.88+ | Install via [rustup](https://rustup.rs/) |
| Node.js | 24+ | Required for desktop app commands and `just ci` |
| pnpm | 10+ | Required for desktop app commands and `just ci` |
| Flutter | 3.41+ | Required for mobile app — install via [flutter.dev](https://docs.flutter.dev/get-started/install) |
| Docker | 24+ | For Postgres, Redis, MinIO |
| `just` | latest | Task runner — `cargo install just` |
| `lefthook` | 2.1.3 (Hermit-pinned) | Auto-installed by `just hooks` — no manual install needed |
| `sqlx` migrations | workspace crate | `just migrate` applies embedded migrations from `migrations/` |
This repo uses [Hermit](https://cashapp.github.io/hermit/) for toolchain
pinning. Activate it once per shell session:
```bash
. ./bin/activate-hermit
```
Hermit pins Rust, `just`, Node, pnpm, and other tools to the versions in
`bin/`. Each tool is downloaded on first use. You can also run `just bootstrap`
(which `just setup` calls automatically) to pre-download all required tools
upfront. If you don't use Hermit, ensure your toolchain meets the minimum
versions in the table above.
#### Linux: Tauri system libraries
Hermit pins language toolchains, not system libraries. On Linux, the desktop
app's Rust crates link against GTK and WebKitGTK, so `just ci` (and any
`just desktop-tauri-*` recipe) needs these installed system-wide first. On
Debian/Ubuntu:
```bash
sudo apt-get install -y --no-install-recommends \
build-essential curl file libasound2-dev libayatana-appindicator3-dev \
libgtk-3-dev librsvg2-dev libssl-dev libwebkit2gtk-4.1-dev libxdo-dev \
patchelf wget
```
This is the same list CI installs (see `.github/workflows/ci.yml`), so matching
it locally keeps your results comparable to CI. Other distributions ship these
under different package names — see the
[Tauri prerequisites](https://tauri.app/start/prerequisites/) for the
equivalents.
Without them, `just ci` fails partway through `just check` with a pkg-config
error such as:
```
The system library `gdk-pixbuf-2.0` required by crate `gdk-pixbuf-sys` was not found.
```
If you're only touching the relay, CLI, or other server-side crates, you can
skip this and run the narrower recipes instead — `just fmt-check`, `just
clippy`, `just test-unit`, and `just test` need no GTK.
### First-Time Setup
```bash
# 1. Clone the repo
git clone https://github.com/block/buzz.git
cd buzz
# 2. Activate Hermit (optional but recommended)
. ./bin/activate-hermit
# 3. Bootstrap tools + infrastructure
just setup
# 4. Install Git hooks (optional, recommended)
just hooks
```
`just setup` runs `just bootstrap` first — it copies `.env.example` to `.env`
if it doesn't already exist, and invokes `cargo`, `node`, and `pnpm` to trigger
Hermit's lazy tool download (each tool is fetched once on first invocation and
cached thereafter). You can also run `just bootstrap` independently at any time;
it is safe to re-run.
`just setup` then starts Docker services (Postgres on `:5432`, Redis on `:6379`,
Adminer on `:8082`, Keycloak on `:8180` for local OAuth/OIDC testing, MinIO on
`:9000` for media storage, and Prometheus on `:9090` for metrics) and runs all
pending database migrations.
### Running the Relay and Desktop App
```bash
just dev # starts the relay + desktop app in one command
```
`just dev` builds all agent tools, starts the relay (`ws://localhost:3000`) in
the background, and launches the Tauri desktop app. The relay process is
automatically killed when you quit the app or press Ctrl+C.
For a split-terminal workflow (relay logs visible separately from Vite output):
```bash
just relay # terminal 1 — relay on ws://localhost:3000
just desktop-dev # terminal 2 — Vite dev server only (no Tauri shell)
```
### Stopping / Resetting
```bash
just down # Stop Docker services, keep data
just reset # Wipe all dev state and recreate it; installed Buzz is preserved
```
Development desktop state uses separate bundle identifiers
(`xyz.block.buzz.app.dev` and per-worktree variants), a separate keyring service
(`buzz-desktop-dev`), and `~/.buzz-dev`. `just reset` removes those dev-only
locations and the local Docker volumes. It does not touch the installed app's
`xyz.block.buzz.app` data, `buzz-desktop` keyring service, or `~/.buzz` nest.
---
## Running Tests
### Unit Tests (no infrastructure required)
```bash
just test-unit
```
Unit tests are self-contained and run without Docker. They cover event
parsing, filter matching, auth logic, workflow YAML parsing, and more.
### Integration Tests (requires running infrastructure)
```bash
just test
```
Integration tests spin up the relay and exercise the full stack — WebSocket
connections, NIP-42 auth, event ingestion, search indexing, and workflow
execution. `just test` starts Docker services automatically if they're not
already running.
### End-to-End Tests
End-to-end tests live in `crates/buzz-test-client/tests/`:
- `e2e_relay.rs` — WebSocket relay tests
- `e2e_mcp.rs` — MCP tool tests
- `e2e_nostr_interop.rs` — Nostr protocol interoperability tests
- `e2e_media.rs` — media upload/download tests
- `e2e_media_extended.rs` — extended media tests (GIF, image processing)
Run them with (requires running infrastructure):
```bash
cargo test -p buzz-test-client -- --ignored
```
See `TESTING.md` for the full multi-agent E2E testing guide.
### CI Gate
Before opening a PR, run the full CI gate locally:
```bash
just ci
# Runs: check + unit tests + desktop build + Tauri check + mobile tests
```
This is the same check that runs in CI. PRs that fail `just ci` will not be
merged. If `just ci` fails on formatting, `just fix-all` fixes it in one shot (`rustfmt` + Tauri fmt + desktop, web, and mobile formatters).
---
## Code Style
### Formatting
We use `rustfmt` with default settings. Format your code before committing:
```bash
cargo fmt --all
```
To check without modifying:
```bash
cargo fmt --all -- --check
```
### Linting
We use `clippy` with warnings-as-errors:
```bash
cargo clippy --all-targets --all-features -- -D warnings
```
Fix all clippy warnings before submitting a PR. If you believe a warning is
a false positive, add a targeted `#[allow(...)]` with a comment explaining
why.
### No Unsafe Code
All crates enforce `#![deny(unsafe_code)]`. Do not add unsafe blocks. If you
believe unsafe is genuinely necessary, open an issue first to discuss the
approach.
### Error Handling
- Use `thiserror` for library error types.
- Use `anyhow` for binary / application-level error propagation.
- Do not use `unwrap()` or `expect()` in production code paths. Use `?` or
explicit error handling. `unwrap()` is acceptable in tests.
### Logging and Tracing
Use the `tracing` crate for all instrumentation. Prefer structured fields
over string interpolation:
```rust
// Good
tracing::info!(channel_id = %id, event_kind = kind, "Event ingested");
// Avoid
tracing::info!("Event ingested: channel={id} kind={kind}");
```
### Commit Messages
Follow [Conventional Commits](https://www.conventionalcommits.org/):
```
feat(mcp): add get_feed_actions tool
fix(auth): reject expired NIP-42 challenges
docs(agents): document workflow MCP tools
refactor(db): extract channel queries into channel.rs
test(workflow): add approval gate integration test
```
The type prefix (`feat`, `fix`, `docs`, `refactor`, `test`, `chore`) is
required. The scope (in parentheses) is optional but encouraged.
---
## Making a Pull Request
### What a Good PR Looks Like
1. **Focused** — one logical change per PR. If you're fixing a bug and
refactoring a module, split them into two PRs.
2. **Tested** — new behavior has tests. Bug fixes include a regression test.
If a test is impractical, explain why in the PR description.
3. **Documented** — public APIs, new event kinds, new MCP tools, and new
config variables are documented. Update `README.md`, `AGENTS.md`, or
`VISION.md` as appropriate.
4. **CI passing**`just ci` passes locally before you push.
5. **Clear description** — the PR description explains:
- What problem this solves (or what feature it adds)
- How it was implemented (key decisions, trade-offs)
- How to test it manually (if applicable)
- Any follow-up work deferred to a future PR
6. **Shows the UI** — any PR that changes the desktop or mobile UI includes
before/after screenshots (or a short recording for interactions) in the
description. We can't run every branch locally — screenshots let us review
UI changes same-day instead of waiting for someone to build your branch.
### PRs We're Unlikely to Merge
Some kinds of PRs usually get closed — not because they're bad ideas, but
because we can't safely review them without prior discussion:
- **Large refactors or dependency swaps** without a prior issue agreeing on
the direction
- **Cosmetic renames or style-only churn** that doesn't fix a bug or improve
clarity
- **Entirely new features** with no prior discussion
- **Drive-by changes bundled into an unrelated fix** — split them out
If you're considering any of these, open an issue first and we'll tell you
quickly whether it's a direction we'd merge. That saves your time as much as
ours.
### What to Expect After You Open a PR
- Maintainers triage new PRs on a best-effort cadence. Focused PRs that
follow this guide move fastest.
- Duplicates and PRs that skip this guide may be closed with a pointer here
rather than a full review. A close isn't a rejection of you or the idea —
address the gaps and reopen (or open a fresh PR) anytime.
- Address review comments by pushing new commits (don't force-push during
review; it makes it hard to see what changed).
- Once approved, a maintainer will squash-merge your PR.
---
## Architecture Overview
See [ARCHITECTURE.md](ARCHITECTURE.md) for the full system design and
[AGENTS.md](AGENTS.md#repo-structure) for the complete crate map. The key
design principles:
**The relay is the single source of truth.** All state flows through the
event store. Crates communicate through the database and Redis pub/sub — not
through direct function calls across crate boundaries (with the exception
of `buzz-core` types, which are shared everywhere).
**Event kinds are the only switch.** Every action in the system — a message,
a reaction, a workflow step, a canvas update — is a Nostr event with a kind
integer. Adding a new feature means defining a new kind. No breaking changes
to existing clients.
---
## Ecosystem
Buzz is developed across multiple repositories. This repo (`block/buzz`)
is the open-source home for all application code — the relay, desktop app,
mobile app, CLI, and agent harness. Internal repositories handle
enterprise-signed builds and infrastructure deployment.
See [AGENTS.md § Ecosystem](AGENTS.md#ecosystem) for the full repo table and
dependency diagram.
**External contributors:** Fork `block/buzz`, open a PR, and CI runs
automatically. No special access is required.
**Block team members:** See the internal
[sprout-releases CONTRIBUTING.md](https://github.com/squareup/sprout-releases/blob/main/CONTRIBUTING.md)
for team access setup, onboarding, and the full repo inventory. See
[RELEASING.md](RELEASING.md) for the release process.
---
## How to Add a New Event Kind
1. **Define the kind constant** in `buzz-core/src/kind.rs`:
```rust
/// My new event kind — description of what it represents.
pub const KIND_MY_FEATURE: u32 = 4XXXX;
```
Pick a kind number in the appropriate sub-range defined in `kind.rs`.
Check the `ALL_KINDS` array for collisions. Each sub-range is documented
with comments in the file.
2. **Define the payload type** in the appropriate module in `buzz-core/src/`
(e.g., alongside `event.rs`) if the content field is structured JSON:
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct MyFeaturePayload {
pub field_one: String,
pub field_two: Option<u64>,
}
```
3. **Register the kind's required scope** in
`crates/buzz-relay/src/handlers/ingest.rs` inside
`required_scope_for_kind()`. This controls which auth scope a caller
needs to submit the event:
```rust
KIND_MY_FEATURE => Ok(Scope::MessagesWrite),
```
4. **Handle post-storage side effects** by adding a match arm in
`crates/buzz-relay/src/handlers/side_effects.rs` inside
`handle_side_effects()`:
```rust
KIND_MY_FEATURE => handle_my_feature(event, state).await?,
```
`handle_side_effects()` runs after the event is stored — use it for
notifications, cache invalidation, or derived data. If the new kind
also needs an HTTP bridge surface (for example, a protocol helper that
cannot practically use WebSocket), add a handler in
`crates/buzz-relay/src/api/` and register it in
`crates/buzz-relay/src/router.rs`.
5. **Persist to the database** — if the event needs to be queryable, add a
handler in `buzz-db/src/` (e.g., `buzz-db/src/my_feature.rs`) with
the appropriate `INSERT` and `SELECT` queries.
6. **Index for search** (if applicable) — Postgres FTS indexes persisted
events automatically via the `events.search_tsv` generated column. To
exclude a privacy-sensitive kind from search, add it to the `CASE WHEN
kind IN (...)` exclusion in the `search_tsv` definition (see the initial
schema migration) rather than wiring a separate indexer.
7. **Audit** — the audit log captures all events automatically; no changes
needed unless you need custom audit metadata.
8. **Write tests** — add a unit test for payload serialization in
`buzz-core` and an integration test in `buzz-test-client` that sends
the new event kind and verifies the expected behavior.
9. **Document** — `kind.rs` is the authoritative registry of all kind numbers.
Update `README.md` if it's a user-facing feature.
---
## How to Add a New API Endpoint
Prefer a signed Nostr event and the existing WebSocket/`POST /events` ingest
path over adding endpoint-specific JSON APIs. The relay intentionally exposes
only a narrow HTTP surface: NIP-11/NIP-05 metadata, `/events`, `/query`,
`/count`, `/hooks/{id}`, Blossom media, git smart HTTP, git policy hooks, and
health probes.
If an HTTP endpoint is still necessary:
1. **Define the handler** in the appropriate module under
`crates/buzz-relay/src/api/`. Resolve the request tenant before any auth or
data lookup, use NIP-98 when the endpoint accepts user credentials, and keep
community scoping explicit.
2. **Register the route** in `crates/buzz-relay/src/router.rs` using the
narrowest path possible. Do not add new `/api/*` compatibility routes unless
the product decision explicitly calls for one.
3. **Add database queries** in `buzz-db/src/` only when the endpoint cannot be
expressed through the existing event query paths.
4. **Handle errors** using the `api_error()`, `internal_error()`, and
`not_found()` helpers in `buzz-relay/src/api/mod.rs`. Return
`(StatusCode, Json<Value>)` tuples.
5. **Write tests** with the `buzz-test-client` harness in
`crates/buzz-test-client/tests/`, covering auth, community scoping, and the
relevant success path.
6. **Document** any public endpoint in `ARCHITECTURE.md` and user-facing docs.
---
## License and CLA
Buzz is licensed under the **Apache License, Version 2.0**. See
[LICENSE](LICENSE) for the full text.
By submitting a pull request, you agree that your contribution is licensed
under the Apache 2.0 license and that you have the right to submit it.
If your employer has rights to intellectual property you create, you may need
their sign-off. When in doubt, check with your legal team.
---
*Thank you for contributing to Buzz. Every bug report, documentation fix,
and code contribution makes the project better for everyone. 🐝*