block / block/buzz

Publish Buzz mobile to Zapstore (Nostr-native Android app store)

Open
#2,845 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## Summary

Publish the Buzz Android app to [Zapstore](https://zapstore.dev), the open Nostr-native app store, as an additional distribution channel alongside the existing store lanes.

Zapstore distributes Android apps as signed Nostr events: developers publish release metadata and binary hashes to relays, and the client verifies the APK signature against a Nostr identity before installing. There is no review queue, no listing fee, and no revenue share. For a Nostr-native project like Buzz, shipping through a Nostr-native app store is a natural fit — it also puts us in front of the exact audience already running Nostr clients, and gives users a permissionless install path that does not depend on Google Play.

## Why this fits Buzz

- Buzz is already a Nostr application with signing keys, relays, and a Lightning-capable identity — Zapstore's publishing model reuses all of it.
- Zapstore's audience overlaps almost entirely with Buzz's early-adopter audience.
- Users get cryptographic verification of the APK against the publisher identity, rather than trusting a store operator.
- Zero-cost channel: no listing fee, no revenue share, no approval gate.

## How Zapstore publishing works

Publishing is done with [`zsp`](https://github.com/zapstore/zsp) (Go CLI, `go install github.com/zapstore/zsp@latest`), driven by a `zapstore.yaml` at the repo root:

```yaml
repository: https://github.com/block/buzz
name: Buzz
summary:
description: |

tags: [nostr, chat, agents]
license: Apache-2.0
icon: ./mobile/assets/images/buzz-icon.png
images:
- ./screenshots/<...>.png
release_notes: ./mobile/CHANGELOG.md
supported_nips: ["01", "29", "42", "17"]
```

`zsp publish` emits three event kinds (the software-application events proposed in [nostr-protocol/nips#1336](https://github.com/nostr-protocol/nips/pull/1336), commonly referred to as NIP-82):

| Kind | Event | Contents |
|------|-------|----------|
| `32267` | Software Application | name, description, icon, screenshots, platforms, license, repo |
| `30063` | Software Release | version, release notes, references to assets |
| `3063` | Software Asset | APK hash, size, signing-certificate info, download URL, platform |

Defaults: relay `wss://relay.zapstore.dev`, Blossom CDN `https://cdn.zapstore.dev` (both overridable via `RELAY_URLS` / `BLOSSOM_URL`).

Signing is via the `SIGN_WITH` env var — `nsec`, hex key, NIP-46 bunker URL, or NIP-07 browser signer. **For CI, use a NIP-46 bunker URL stored as a secret, not a raw `nsec`.** On first publish, the APK signing certificate is cryptographically linked to the publishing Nostr identity (NIP-C1) via `zsp identity --link-key `; this requires access to the release keystore.

Whitelisting: when the app event reaches the relay, Zapstore fetches `zapstore.yaml` from the declared repository and verifies the publishing pubkey matches — so the config must be committed to `block/buzz` before the first publish.

## Known blocker: no public APK artifact

This is the main thing to solve before anything else. Per [RELEASING.md](https://github.com/block/buzz/blob/main/RELEASING.md), the mobile lane publishes **only** annotated `mobile-vX.Y.Z-rc.N` git tags — no GitHub Release and no public APK. Signed APKs are produced by the private Buildkite pipeline (`squareup/buzz-releases` / `sprout-releases`) and promoted to store workflows.

`zsp` needs an actual APK (local file, or one fetched from a GitHub/GitLab/Codeberg/F-Droid release). So one of these has to happen:

1. **Publish from the private pipeline** — run `zsp` inside the Buildkite job that already holds the signed APK and keystore. Keeps signing material where it lives today; requires a change in a private repo, so OSS CI stays uninvolved.
2. **Attach the signed APK to a public GitHub Release** — then a public workflow (or a manual run) can `zsp publish` against it. Requires a policy decision about publishing a signed APK publicly and a new mobile GitHub Release step, which today's mobile lane deliberately does not have.

Option 1 is the smaller change and matches the current release contract. Worth confirming with whoever owns the mobile release pipeline.

Related open questions:

- Which Nostr identity publishes? A dedicated Buzz publisher key vs. an existing project identity — whichever it is, it needs a NIP-46 bunker for CI and a Lightning address on its profile if we want zap/tip support.
- `applicationId` is `xyz.block.buzz.mobile`; confirm this is the ID we want listed.
- Does releasing on Zapstore need Block release/legal sign-off, given it is an additional public distribution channel?

## Scope

- [ ] Decide the publishing identity and provision a NIP-46 bunker + CI secret
- [ ] Resolve the APK-source blocker (private pipeline vs. public GitHub Release)
- [ ] Add `zapstore.yaml` to the repo root with Buzz metadata, icon, and screenshots
- [ ] Link the Android release signing certificate to the Nostr identity (`zsp identity --link-key`, NIP-C1)
- [ ] Wire `zsp publish` into the mobile release flow, gated on an exact `mobile-vX.Y.Z-rc.N` tag
- [ ] Add a `zsp publish --check` validation step so config drift fails fast without publishing
- [ ] Do a first manual publish and verify install + update from the Zapstore Android client
- [ ] Document the lane in `RELEASING.md`

## Out of scope

- **iOS.** Zapstore's iOS client is still in development and `zsp` handles Android APKs only.
- **Desktop.** Same reason — `zsp` currently supports APKs, so the macOS/Linux desktop artifacts are not publishable this way today. Revisit if desktop-binary support ships.
- **Relay-side NIP-82 support.** Teaching `buzz-core`/`buzz-relay` to register and serve kinds `32267`/`30063`/`3063` so a Buzz community could host app releases is a separate feature; the spec is also still an open PR ([nips#1336](https://github.com/nostr-protocol/nips/pull/1336)). File separately if we want it.

## References

- [Zapstore](https://zapstore.dev/) · [Publishing docs](https://zapstore.dev/docs/publish) · [Developer FAQ](https://zapstore.dev/docs/faq)
- [`zapstore/zsp`](https://github.com/zapstore/zsp) — publishing CLI
- [`zapstore/zapstore`](https://github.com/zapstore/zapstore) — the client
- [nostr-protocol/nips#1336](https://github.com/nostr-protocol/nips/pull/1336) — software application events (open)
- [Can Nostr fix app distribution?](https://zapstore.dev/blog/can-nostr-fix-app-distribution)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.