{
  "generated": "2026-07-10",
  "site": "nostr.trespies.dev",
  "counts": {
    "docs": 36,
    "by_kind": {
      "manual": 16,
      "nip": 14,
      "nip-meta": 6
    },
    "by_lang": {
      "en": 26,
      "es": 10
    }
  },
  "docs": [
    {
      "id": "manual/00-overview",
      "kind": "manual",
      "lang": "en",
      "title": "00 \u2014 Overview: The Soapbox Stack Operator Manual",
      "url": "/manual/#ch00",
      "md_url": "/manual/md/00-overview.md",
      "sha256": "0ea160c61853b58d28042134366b4399608d99855f96c3051ec8847bd61542c4",
      "bytes": 10451,
      "headings": [
        "About this manual (build-in-public)",
        "The four original questions",
        "The stack at a glance",
        "Verdicts in brief",
        "How to read this manual",
        "Chapter index"
      ],
      "body": "One manual answering: can TresPies/DojoGenesis run community ops, company ops, funding, client sites, and publishing on the Soapbox.pub / Nostr stack \u2014 and where do we build? About this manual (build-in-public) Built and maintained by TresPies Design / DojoGenesis. Researched and written via orchestrated AI agent waves \u2014 recon agents \u2192 adversarial kill-passes \u2192 writer agents \u2192 human-operator direction \u2014 not a single pass, and not one model. Provenance: every chapter carries its own Verified/Amended dates and per-claim confidence tiers; a public correction-log discipline means errors found in our own working documents get logged, not hidden. Platform-agnostic by design: nothing here assumes a specific agent or model lane \u2014 bring Claude Code, Cursor, Windsurf, OpenCode, DojoGenesis Gateway, or a plain terminal. How to adapt: fork the reading order, keep the protocol chapters as reference, swap the worked-example specifics (a firm's niche, a team's hooks) for your own. Canonical home: nostr.trespies.dev/manual \u00b7 agent-readable faces at /manual/llms.txt and /manual/index.json (per-chapter sha256). Verified: 2026-07-09. Research: 8 parallel agents (chapters 01\u201306, 08\u201309), each primary-sourced with numbered citations. Synthesis (this file + ch. 07): main thread, per the amended orchestrator gate (operator-ratified 2026-07-09). One mid-flight adjudication is recorded honestly: Armada was first verdicted nonexistent, then found at the repo level, verified, and corrected (ch. 02) \u2014 the product is 26 days old and simply unindexed. Delta pass 2026-07-10 (ch. 05 + ch. 10): NostrHub velocity 866 commits/29 days; no bounty/contest program exists anywhere in the 60-post blog index; new MCP/agent-surface addendum \u2014 the \"acting NostrHub MCP server\" niche is verified empty; \u26a0 nostrdeploy.com is DNS-dead (Stacks deploy lane tripwired, affects ch. 04's route too); Stacks 1.0 = the generic template platform, MKStack = one published stack on it. The four original questions Asked Verdict (one line) Where \"Armada for community and company operations \u2014 can it do filesharing?\" Armada is real (b. 2026-06-13): E2E Discord-shaped chat on the new Concord protocol \u2014 pilot for internal ops; Ditto is the mature public-community layer. Filesharing: media yes (Ditto plaintext, Armada E2E) \u2014 folders/ACLs/versioning no; keep Drive 02 \"Agora for funding\" Yes, today, permissionless: $0 platform fee, non-custodial wallet-to-wallet BTC (on-chain, not Lightning). Caveats: activist brand gravity, donors need BTC, no tax-receipt path for anonymous gifts 03 \"Shakespeare for sites and funnels \u2014 free mockups?\" Mockups: effectively free (free Gemini tier / BYO cheap key / local models; Soapbox takes no cut). Funnels: top-of-funnel native (forms, Lightning/Cashu); conversion capture wires to Beehiiv/ManyChat/Cal.com/Stripe 04 \"Get deep into NostrHub \u2014 I have credentials\" Dev hub relaunched as 2.0 on 2026-06-28: NIPs + apps + git-over-Nostr, \"configurable meritocracy.\" Sign in with NIP-07 extension or NIP-46 bunker \u2014 never paste your nsec. Publishing = kinds 30617 (repo), 31990 (app), 30023 (long-form) 05 The stack at a glance Full portfolio (45+ products incl. Toybox experiments): master map in ch. 01. Verdicts in brief Dimension Verdict Confidence Company durability Alive and shipping (same-day commits; 12 humans; OpenSats/HRF grants since 2023) \u2014 risk is grant non-renewal, not product death; Ditto/Shakespeare fork-survivable, Armada not yet High Licensing boundary Apps AGPL-3.0 (client-facing mods must be published); Nostrify MIT confirmed; MKStack template ships NO license file (ask Soapbox before closed commercial reuse \u2014 ch. 10); mkstack-nsp AGPLv3 High Community ops Ditto now (themes, 50+ Mastodon apps, real self-host: Deno+Postgres); no native DMs, no NIP-29 yet High Internal/company ops Armada pilot only \u2014 E2E by default, serverless over public relays, unaudited 0.x moving daily Med Filesharing Media-in-feed/chat yes; Drive/Dropbox replacement no (no folders/ACLs/versions; Blossom Drive deprecated \u2192 Bouquet) High Funding Agora: permissionless, $0 fees, on-chain BTC only; fiat off-ramp + receipts are your problem Med-High Sites/funnels Near-$0 mockups; native Lightning/Cashu; conversion stack external; no CMS for client self-edit High Publishing NostrHub = discovery/credibility layer (metadata only, no artifact hosting); interop with gitworkshop/ngit verified High i18n readiness Stack is EN-only except Agora (i18next, 16 locales, es 99.96%) \u2014 fork that pattern; no ratified Nostr language-tag NIP High Visualization Recharts ships inside MKStack; Atlas-class census dashboards run zero-server (MapLibre+PMTiles+DuckDB-WASM); Ditto has no widget surface; 30023 forbids HTML High How to read this manual Operator quick path: this page \u2192 07 \u2014 Integration Playbook (runbooks + a worked-example integration blueprint). Builder path (v2, added 2026-07-10): 11 \u2014 Nostrify \u2192 12 \u2014 Building Consumer Apps \u2192 06 \u2014 Foundations as reference \u2192 15 \u2014 Production before anything ships. Relay decisions: 13; shipping channels: 14. Product deep-dives: 01 (company) \u00b7 02 (Ditto+Armada) \u00b7 03 (Agora) \u00b7 04 (Shakespeare) \u00b7 05 (NostrHub) \u00b7 10 (MKStack \u2014 the framework layer and agent contract). Protocol layer: 06 \u2014 Nostr Foundations \u2014 read \u00a71 (keys) before touching your credentials; master NIP table at the end. Steering direction (build phase): 08 \u2014 i18n \u2192 09 \u2014 Visualization \u2192 07 \u00a79 blueprint. Chapter index Ch. File One line 01 01-soapbox-company.md Who Soapbox is: history, funding, licenses, 45-product master map, durability 02 02-community-ops.md Ditto (public community) + Armada (E2E team chat) + the filesharing verdict 03 03-agora.md Non-custodial BTC fundraising: mechanics, fees, compliance reality, white-label 04 04-shakespeare.md AI site builder: cost mechanics, mockup economics, funnel wiring, deploy paths 05 05-nostrhub.md NostrHub 2.0: auth with your keys, publishing repos/apps/articles, governance 06 06-nostr-foundations.md Keys, relays, kinds, payments, Blossom, moderation, DVMs \u2014 the protocol reference 07 07-integration-playbook.md Runbooks A\u2013D, integration matrix, build opportunities, a worked-example modded-stack blueprint (TresPies) 08 08-i18n-integration.md i18n platforms \u00d7 stack readiness: fork Agora's pattern, add Lingo.dev, symmetric parity gate 09 09-visualization-integration.md Viz components \u00d7 stack: MapLibre+PMTiles+ECharts, the zero-server Atlas pattern 10 10-mkstack.md The framework layer: scaffold anatomy, AGENTS.md agent contract + .mcp.json, provider lanes, license flag 11 11-nostrify.md Nostrify: one interface, many backends \u2014 stores, pools, signers, schema, 20 policies, uploaders, the 9-package map 12 12-building-consumer-apps.md The builder curriculum: all 19 skills as definition-of-done, the Shakespeare\u2192OpenCode\u2192clone ladder, scaffold-vs-product, the AI-team pattern 13 13-relay-operations.md Relay ops for an app team: strfry/khatru/Ditto/ditto-relay menu, archive-first pattern, monitoring, spam, budget 14 14-distribution-native.md Distribution + native: Zapstore, Capacitor, Lockdown Mode, the PWA-push gap, signer channels 15 15-production-secrets-longevity.md Production: durability economics, deletion vs law, operator liability, degradation, secrets/custody, exit playbook, incident catalog v2 wave (2026-07-10): chapters 11\u201315 added under the consumer-app builder lens; chapters 01/04/06/10 amended (see each chapter's Amended line). Gap analysis and production audit: maintainers' companion notes (not part of this public chapter set). v2.1 editorial pass (2026-07-10): generalized for public, platform-agnostic readers; provenance section added. Source of truth: this repository's notes/manual/ directory, mirrored to the maintainers' internal workspace (internal: OTH-24 manual v1, OTH-25 v2 + hosting, PIP-94 build)."
    },
    {
      "id": "manual/01-soapbox-company",
      "kind": "manual",
      "lang": "en",
      "title": "Soapbox.pub \u2014 Company Dossier",
      "url": "/manual/#ch01",
      "md_url": "/manual/md/01-soapbox-company.md",
      "sha256": "469db9508a4242a298b4ad8b798416c3c7e36e8853665cae62d06539d191cc05",
      "bytes": 27690,
      "headings": [
        "What Soapbox Is",
        "History Timeline",
        "Team & Funding",
        "AI Team Members \u2014 Plural and Evolving",
        "Master Portfolio Map",
        "Licenses & Ethics Commitments",
        "Durability & Risk Assessment for an Operator",
        "The \"Armada\" Note",
        "Open Questions",
        "Sources"
      ],
      "body": "A grant-and-donation-funded, AGPL-copyleft software studio building the Nostr protocol's social, fundraising, and AI-website-builder layer \u2014 founded by Truth Social's former head of engineering. Verified: 2026-07-09 \u00b7 Amended: 2026-07-10 (v2 wave) \u2014 added the plural AI-team-members section (Dirk Rost, Quilly, Sheila, producer-role culture, cross-ref ch. 12); reclassified HRF funding from recurring grantor to prize/event partner and flagged OpenSats' BTC-denominated treasury as a second-order risk; added a bus-factor finding to Durability & Risk, cross-ref ch. 15. Confidence: High for company facts, funding sources, licenses, and product inventory (primary-sourced, cross-checked against GitLab/GitHub). Medium for team headcount and exact grant dollar amounts (not publicly itemized). Low for the durability of any single \"Toybox\" experiment (many are days-to-weeks old with zero external stars). What Soapbox Is Soapbox describes itself as an open-source studio building \"tools for Freedom Online\" \u2014 decentralized, ad-free, non-custodial software with no VC and no shareholders [1]. Its ethics pledge states the stakes plainly: \"We would rather shut down than compromise our principles for profit.\" [3] That is not rhetorical flourish \u2014 it is the operating thesis an operator has to underwrite before building on this stack. Everything below tests whether the thesis is currently backed by cash, commits, and people. History Timeline Soapbox has gone through three distinct eras: a Fediverse-frontend company (2019\u20132022), a Nostr-infrastructure company funded by its founder's Truth Social exit (2023\u20132024), and \u2014 starting mid-2025 \u2014 an AI/\"vibe-coding\" studio. The throughline is Alex Gleason, who founded Soapbox in 2019 as a Mastodon-frontend fork, was hired by Trump Media & Technology Group in January 2022 to adapt that frontend for Truth Social, served as TMTG's Head of Engineering through mid-2023, then resigned to build on Nostr full-time the same month OpenSats funded him to do it [5][6][23]. Era Date Event Fediverse FE 2020-06-15 Soapbox FE v1.0 announced \u2014 Mastodon-compatible frontend [2] Fediverse BE 2021-10 Chooses Pleroma as backend over Mastodon (\"slow, expensive, not innovating\") [19] Truth Social 2022-01 TMTG hires Gleason to adapt Soapbox as Truth Social's frontend [6] Fediverse BE 2022-08-19 Soapbox BE (a Pleroma fork) renamed Rebased [19] Fediverse FE 2022-12-25 Soapbox 3.0 released [2] Nostr pivot 2023-02-26 Mostr launches \u2014 first Fediverse\u2194Nostr bridge [2] Nostr pivot 2023-07-17 Gleason resigns from Truth Social; OpenSats funds Soapbox 1 year from its $5M Dorsey-donated Nostr fund to build Ditto [23] Nostr build-out 2024-04-17 Nostrify (MIT-licensed framework) announced [2] Nostr build-out 2024-06-14 Ditto announced publicly, incl. mobile [2] Nostr build-out 2025-03-23 Ditto 1.3 \u2014 Cashu/ecash support [2] AI pivot 2025-05 to 2025-07 Company \"pivots to AI-assisted programming tools\" per its own quarterly report [30] AI pivot 2025-07-10 Shakespeare (AI website builder) announced [2] AI pivot 2025-11-24 \"Our Stance on AI\" / \"Really Open AI\" ethics post [12] AI + activism 2026-01-23 Agora born at HRF's \"AI Hack for Freedom\" hackathon, Bitcoin Park Austin \u2014 team wins 25M sats [20] AI + activism 2026-03-06 Sheila, an AI agent, takes over Soapbox's own bookkeeping [24] Current wave 2026-06-04 Agora publicly launches at Oslo Freedom Forum with World Liberty Congress [2] Current wave 2026-06-13 Armada repo created (see dedicated note below) [18] Current wave 2026-07-08/09 Latest blog post + same-day commits across ~10 repos (verified day of writing) [2][8] Confidence: High \u2014 dates are primary-sourced from the company's own blog index and GitLab activity timestamps. Team & Funding Soapbox is not a solo-founder shop. Its /about page lists 11 named humans plus Gleason (founder/BDFL) across engineering, DevRel, product, and \"VibeOps,\" plus an AI persona (\"Quilly \ud83e\udeb6\") credited as a team member [15] \u2014 see AI Team Members, below, for the fuller and still-growing picture. It has no revenue product: transparency copy states flatly, \"We make no income from our users or apps. No ads. No data sales. No venture capital. No shareholders\" [4]. It survives entirely on grants and donations, fiscally sponsored by And Other Stuff (AOS) while pursuing 501(c)(3) status, with OpenSats as its one demonstrated recurring grant source [4][23]. (Corrected 2026-07-10 \u2014 this line previously also named Human Rights Foundation as a second grant source; see the Funding correction note below the diagram.) This is not a dormant arrangement. Soapbox's own Open Collective ledger shows an AOS-disbursed W2 payroll run for Software Engineer / DevRel / Marketing roles ($25,977.35) and a conference-travel line for bitcoin++ Nairobi ($6,794.02), both dated July 2026 \u2014 the same month this dossier was written [21]. OpenSats has funded Soapbox continuously since its first grant in Q3 2023, with 9 consecutive quarterly public reports through April 2026 and no visible funding gap [4][23][30]. Funding correction (2026-07-10): a same-day audit checked HRF's own 2026 Bitcoin Development Fund grant rounds \u2014 20+ projects per round, names like Snort, Coracle, Zapstore, and Elsat recur \u2014 and found no round naming Soapbox, Ditto, or Agora [33]. Soapbox's actual HRF touchpoints are prize/event partner, not grantor: Agora's 25M-sat win at HRF's \"AI Hack for Freedom\" hackathon (Jan 2026) and the Oslo Freedom Forum as Agora's public-launch venue (Jun 2026). OpenSats continuity is grantee-self-reported \u2014 9 consecutive quarterly transparency reports through April 2026, with no grantor-side (OpenSats-published) 2026 confirmation independently found [4][30]. Net: one demonstrated funding line, self-reported, not the two-funder diversification the diagram previously implied. New second-order risk: OpenSats' own treasury is BTC-denominated, so a Bitcoin bear market mechanically shrinks its USD disbursement capacity \u2014 a risk layer beneath ordinary grant-renewal risk. This corrects the diagram above and the \"funder concentration\" bullet in Durability & Risk, below; it does not change the \"alive-and-shipping\" verdict (same-day commits and cleared payroll are unaffected facts). Confidence: High for funding sources and current-month payroll evidence (primary, dated). Medium for total headcount \u2014 the payroll line names only 3 roles, so how many of the 12 listed team members are W2 vs. volunteer/contributor is not reconciled in public data. AI Team Members \u2014 Plural and Evolving At least three named AI personas do Soapbox's own work, each announced separately, with no roster page tying them together [31][32][24] \u2014 verify currency before citing any single one as the example: Dirk Rost \u2014 code review and merge-request approval across Soapbox's projects, giving the team what its own post calls a \"bird's-eye view\" (cross-project oversight, not one-repo scope): \"He runs on open-source infra with a personality defined in plain markdown anyone can read\" [31]. The stated payoff is velocity \u2014 \"so quality scales as fast as we ship\" [31]. Quilly \ud83e\udeb6 \u2014 docs, community, and GitLab housekeeping (blog posts, team-page updates, asset management); self-described as \"the newest member of Team Soapbox\" [32]. Announced late January 2026 \u2014 though the post's own byline (Jan 2025) and visible date (Jan 2026) disagree, a small currency flag worth resolving before citing the date hard. Sheila \u2014 took over Soapbox's own bookkeeping starting 2026-03-06 (History Timeline, above) [24]. \"Newest member,\" in Quilly's own post, implies the roster keeps growing \u2014 treat any single AI-team name-check, including this one, as a snapshot that can go stale within months. This is also where Soapbox's build culture surfaces directly: a \"producer role\" \u2014 a human prompting, directing, and reviewing AI-generated work rather than hand-writing it \u2014 runs through both how Soapbox builds itself (the three names above) and how it expects app builders to work this stack. Inferred, synthesis-level: the practical workflow ladder is Shakespeare for ideation \u2192 a local agent session (e.g. OpenCode) for deep work \u2192 cloning MKStack directly once the app's shape is known. Ch. 12 (new) covers this ladder and the full 19-skill curriculum; treat the ladder itself as this manual's synthesis of the tooling, not a single Soapbox-published claim. Master Portfolio Map This table covers every Soapbox product and tool found across soapbox.pub, GitLab, and GitHub \u2014 including the 17-item \"Toybox\" experiments line, which is a real, distinctly-named page (soapbox.pub/toybox), separate from the developer-facing \"Toolbox\" (soapbox.pub/toolbox) [7][27]. License cells marked \"confirmed\" were verified by fetching the repo's actual LICENSE file or GitHub license badge; everything else is unverified and should not be assumed. Product Category Status (as of 2026-07-09) Repo License Hosted / Self-host Ditto Core app Active \u2014 major update Mar 2026 gitlab.com/soapbox-pub/ditto AGPL-3.0 (confirmed) [9][16] Both \u2014 ditto.pub or self-host Shakespeare Core app Active \u2014 primary 2025-26 focus gitlab.com/soapbox-pub/shakespeare AGPL-3.0 (confirmed) [11][17] Runs in-browser, local-first Agora Core app Active \u2014 public launch Jun 2026 gitlab.com/soapbox-pub/agora AGPL-3.0 (confirmed) [13] Hosted; non-custodial by design Armada Core app Active \u2014 extreme velocity, see note below gitlab.com/soapbox-pub/armada AGPL-3.0 (confirmed) [14][18] Serverless default; self-host via armada-relay Mostr Bridge Core app Active/mature (since 2023) gitlab.com/soapbox-pub/mostr Not verified Hosted (mostr.pub) Soapbox (legacy FE) Legacy core app Maintenance \u2014 superseded by Ditto github.com/soapbox-pub/soapbox AGPL-3.0 (confirmed) [22] Self-host Rebased Legacy core app Maintenance \u2014 Pleroma-fork backend github.com/soapbox-pub/rebased Not verified Self-host Nostrify Dev framework Active \u2014 foundational gitlab.com/soapbox-pub/nostrify MIT (confirmed) [22] Library, self-host by nature MKStack Dev framework Active \u2014 used by 3rd parties (e.g. Divine) gitlab.com/soapbox-pub/mkstack Not verified (fetch blocked) Local scaffolding tool NostrHub Dev tool Active \u2014 \"2.0\" relaunch Jun 2026 nostrhub.io Not verified Hosted Stacks Dev infra Active \u2014 1.0 shipped Aug 2025 getstacks.dev Not verified Self-host (Docker) Ditto Relay Dev infra Active gitlab.com/soapbox-pub/ditto-relay Not verified Both \u2014 relay.ditto.pub or self-host Ditto Extension Dev tool Active Chrome Web Store Not verified Browser extension Nostr WS Inspector Dev tool Active Chrome Web Store Not verified Browser extension Nostrbook Dev docs/MCP Active nostrbook.dev Not verified Hosted + MCP server Relay Kit Dev tool Active \u2014 third-party, not Soapbox's own github.com/samthomson/relaykit Not verified Self-host install script Soapbox Signer Dev tool Active, announced Dec 2025 Not located Not verified Browser extension (NIP-07) Mi Dev/consumer tool Newer, minor mi.shakespeare.wtf Not verified Browser-local relay Quilly AI persona Active \u2014 internal + public-facing n/a (not a repo) n/a Hosted Sheila AI agent Active since Mar 2026 Not located Not verified Internal tool (accounting) Zuka AI product Active since May 2026 Not located Not verified Hosted PWA Firefly Newer app Active (commit Jul 6, 2026) gitlab.com/soapbox-pub/firefly Not verified Not confirmed shock Newer infra Active (commit Jul 2, 2026) gitlab.com/soapbox-pub/shock Not verified Not confirmed strfry (fork) Dev infra Active (commit Jun 29, 2026) gitlab.com/soapbox-pub/strfry Not verified Self-host relay AOS (software) Experimental Active (commit Jun 28, 2026) \u2014 name collides with AOS the fiscal sponsor; unrelated gitlab.com/soapbox-pub/aos Not verified Not confirmed Agora Server Core app companion Active (commit Jun 25, 2026) gitlab.com/soapbox-pub/agora-server Not verified Self-host (optional) Agora Pay Core app companion Active (commit today) gitlab.com/soapbox-pub/agora-pay Not verified Not confirmed openclaw-armada Core app plugin Active (commit today) gitlab.com/soapbox-pub/openclaw-armada Not verified Plugin Birdblast, Monorail, Tile Studio Experimental Active, undocumented (commits Jun 16\u201321, 2026) gitlab.com/soapbox-pub/* Not verified Not confirmed Toybox (17 apps): Treasures, Birdstar, Surveil, Espy, Nostrdamus, Lief, Nests, Plektos, ZapTrax, Podstr, Color Slide, Blobbi Island, Polaroids, Relaying Earth, Clawstr, Zappix, Bookstr Experimental/toys Mixed \u2014 several months-old, some now graduated (Clawstr has its own launch post) soapbox.pub/toybox Not verified Hosted demos Chorus Toybox-adjacent \"Vibe coding experiment,\" Jun 2025 Not located Not verified Hosted Inkwell Small app Jan 2026 Not located Not verified Hosted, no-account markdown\u2192Nostr Confidence: High for status/dates (GitLab activity timestamps are live data). Medium-Low for license on unverified rows \u2014 treat as unknown, not as AGPL by default. Licenses & Ethics Commitments The verified license pattern is a two-tier copyleft strategy: consumer-facing applications are AGPL-3.0 (network copyleft \u2014 if you run a modified version as a service, you must publish your changes), while the underlying framework is MIT (permissive \u2014 free to embed without triggering disclosure) [9][11][13][14][16][22]: Layer License Confirmed examples Applications AGPL-3.0 Ditto, Shakespeare, Agora, Armada, legacy Soapbox FE Core framework/library MIT Nostrify Docs/skills content CC-BY-SA-4.0 nostr-skills, openclaw-skills Crypto utilities Unlicense seeded-rsa The Ethics Pledge commits to: 100% open source for anything public-facing, never selling/trading user data, refusing backdoors or \"unjust takedown compliance,\" and refusing acquisition by anyone who doesn't share the ethics [3]. The November 2025 \"Really Open AI\" post extends this to AI specifically, defining open AI as open code + open training data + open weights + open access, explicitly invoking the Open Source Initiative's Open Source AI Definition and the FSF's \"Four Essential Freedoms\" [12]. Confidence: High on the licenses actually checked; Medium on the ethics pledge's enforceability (it is a public commitment, not a legal instrument). Durability & Risk Assessment for an Operator Signals of life: same-day GitLab commits across ~10 repos, a 6-year unbroken blog cadence (101 posts, June 2020\u2013July 2026), 3 continuous years of OpenSats funding, and payroll that cleared this month [2][4][8][21]. This is a live, shipping company, not a grant-funded zombie. Structural risks for an operator building on this stack: No recurring revenue anywhere. 100% dependent on grant renewal + donor goodwill; OpenSats grants are typically annual, not perpetual [4][23]. Funder concentration is actually funder singularity \u2014 corrected 2026-07-10. OpenSats is the only demonstrated, self-reported recurring grant line; HRF is a prize/event partner (Agora hackathon win + Oslo launch venue), not a second grantor \u2014 the \"OpenSats + HRF diversification\" framing this bullet previously carried does not hold (see Funding correction, above). One-line dependency reads as more fragile than two, not less; compounding factor: OpenSats' own treasury is BTC-denominated, so its USD disbursement capacity is exposed to Bitcoin price independent of grant-renewal risk [4][20][31][33]. BDFL governance \u2014 Gleason is founder, \"BDFL,\" and the person the Truth Social/Ditto origin story centers on; the \"we'd rather shut down than compromise\" ethic is principled but explicitly not built for business continuity at all costs [3][6]. Extreme product sprawl \u2014 45+ named products/experiments, many with zero stars and undocumented purpose (Birdblast, Monorail, Tile Studio) \u2014 classic sign of a studio prioritizing breadth over hardening any one surface [8]. AGPL-3.0 is a real constraint, not just a badge \u2014 if you fork and modify Ditto/Shakespeare/Agora/Armada and run the modified version as a network service for clients, you must publish your changes. Using Nostrify or MKStack as a library/scaffold to build separate, independently-licensed client work (as Divine has done) does not carry the same obligation [9][11][22][29]. Bus-factor is concentrated, measured 2026-07-10 via repo APIs. Gleason authorship: Nostrify 85.2%, mkstack 71.9%, ditto-relay 99.3%, Ditto 47.4%. Ditto is the only repo in the portfolio with real secondary maintainers (Danidfra, marykatefain, derekross) \u2014 Nostrify, the framework every other product on this stack compiles against, is 85% one person [34]. See ch. 15 (new) for the per-component exit playbook this feeds. Fork survivability if Soapbox disappears tomorrow, by tier: High \u2014 Ditto, Shakespeare: both are explicitly architected for self-host/local-first operation (not an afterthought), AGPL-licensed with real external forks already existing (Ditto: 14 forks) [16][17][9]. Medium \u2014 Agora, Nostrify, MKStack: non-custodial/library-first design survives structurally, but thinner fork/community depth today. Low \u2014 Armada and anything in Toybox: weeks-old, near-zero external stars/forks; a solo fork today would likely mean you as sole maintainer. Confidence: Medium \u2014 this section synthesizes verified facts into forward-looking judgment; treat the risk framing as informed inference, not fact. The \"Armada\" Note Armada is real, current, and not vaporware: GitLab shows the repo created 2026-06-13 and already at 484 commits, 46 releases, 62 tags by 2026-07-09 \u2014 roughly 18 commits/day sustained for 26 days, with commits recorded the same day this was written [18]. It's an end-to-end-encrypted, serverless community-chat app pitched as \"Discord without the company,\" built on a new protocol called Concord plus a NIP-29 relay-based fallback for self-hosters, with a companion self-host backend (armada-relay) and at least one plugin (openclaw-armada) already shipping [14]. It sits on the homepage under \"Community Platforms\" next to Treasures, Blobbi, and Bookstr [1]. Velocity this high, this early, suggests Armada is Soapbox's current top internal priority \u2014 a separate chapter of this manual covers it in depth. Open Questions Exact OpenSats grant dollar amounts \u2014 never itemized publicly; only narrative quarterly reports [4][30]. (HRF's Agora hackathon prize is a stated figure \u2014 25M sats, Jan 2026 \u2014 but that's a one-time prize to the Agora team, not a Soapbox operating grant; see the Funding correction under Team & Funding, above.) MKStack's specific license \u2014 two fetch attempts were blocked/unrendered; inferred permissive from third-party ecosystem use (Divine ships its own separate license), not confirmed [28][29]. Rebased's specific license \u2014 not independently verified this session (GitHub org page showed the field blank) [22]. Whether Soapbox has completed 501(c)(3) conversion or is still solely AOS-fiscally-sponsored as of today [4]. Reconciling \"12 team members listed\" against \"3 W2 payroll roles disbursed\" \u2014 volunteer/contributor vs. employee split is unclear [15][21]. Current Mostr Bridge user count \u2014 the only hard figure found was \"10k+ unique users, 70% Nostr\u2192Fediverse direction,\" dated late 2023; no fresher public number was located [26]. Exact nature/status of several zero-description GitLab repos (Birdblast, Monorail, Tile Studio, NostrHub v1) [8]. Sources soapbox.pub \u2014 accessed 2026-07-09 \u2014 homepage: mission, product list, ethics summary. soapbox.pub/blog \u2014 accessed 2026-07-09 \u2014 full 101-post chronological index, June 2020\u2013July 2026. soapbox.pub/ethics \u2014 accessed 2026-07-09 \u2014 Ethics Pledge verbatim commitments. soapbox.pub/transparency \u2014 accessed 2026-07-09 \u2014 funding model, funders, quarterly report index (fetched twice for report titles/dates). alexgleason.me/work \u2014 surfaced via search 2026-07-09 \u2014 Gleason's own work history page. PRNewswire \u2014 Truth Social Head of Engineering Leaves for Jack-Dorsey-Backed Alternative, Nostr \u2014 accessed 2026-07-09 \u2014 Gleason/TMTG/Nostr pivot. soapbox.pub/toolbox \u2014 accessed 2026-07-09 \u2014 full developer-tools inventory (11 items). gitlab.com/api/v4/groups/soapbox-pub/projects \u2014 accessed 2026-07-09 \u2014 live repo list with last-activity timestamps, stars. soapbox.pub/ditto \u2014 accessed 2026-07-09 \u2014 Ditto product page: license, hosting model. soapbox.pub/agora \u2014 accessed 2026-07-09 \u2014 Agora product page: non-custodial claim, WLC quote. soapbox.pub/shakespeare \u2014 accessed 2026-07-09 \u2014 Shakespeare product page: AI providers, license, hosting. soapbox.pub/blog/our-stance-on-ai \u2014 accessed 2026-07-09 \u2014 \"Really Open AI\" ethics stance. gitlab.com/soapbox-pub/agora LICENSE \u2014 accessed 2026-07-09 \u2014 AGPL-3.0 confirmed. gitlab.com/soapbox-pub/armada README \u2014 accessed 2026-07-09 \u2014 Armada/Concord protocol description. soapbox.pub/about \u2014 accessed 2026-07-09 \u2014 full team roster and mission pillars. github.com/soapbox-pub/ditto \u2014 accessed 2026-07-09 \u2014 stars, forks, license, tech stack. github.com/soapbox-pub/shakespeare \u2014 accessed 2026-07-09 \u2014 stars, forks, license, architecture. gitlab.com/soapbox-pub/armada \u2014 accessed 2026-07-09 \u2014 commit/release/tag counts, creation date. soapbox.pub/blog/soapbox-be-is-now-rebased \u2014 accessed 2026-07-09 \u2014 Pleroma-fork lineage of Rebased. Web search, Human Rights Foundation grants \u2014 accessed 2026-07-09 \u2014 hrf.org Bitcoin Development Fund, Agora/hackathon coverage. opencollective.com/soapbox-pub \u2014 accessed 2026-07-09 \u2014 live financial ledger, July 2026 payroll/travel transactions. github.com/soapbox-pub \u2014 accessed 2026-07-09 \u2014 org-level repo/license table (confirms Nostrify = MIT). soapbox.pub/blog/soapbox-awarded-grant \u2014 accessed 2026-07-09 \u2014 OpenSats grant terms, $5M Dorsey fund detail. Web search \u2014 accessed 2026-07-09 \u2014 Sheila/Clawstr/Chorus/Inkwell descriptions via soapbox.pub/blog/announcing-sheila, soapbox.pub/blog/announcing-clawstr, soapbox.pub/blog/chorus-vibe-coding, soapbox.pub/blog/inkwell-born-in-walmart. soapbox.pub/blog/building-zuka \u2014 accessed 2026-07-09 \u2014 Zuka description, activist partner quote. Web search, Mostr bridge stats \u2014 accessed 2026-07-09 \u2014 mostr.pub, fediversereport.com bridging analysis (10k+ unique users / 70% direction figure dated late 2023). soapbox.pub/toybox \u2014 accessed 2026-07-09 \u2014 full 17-item experimental-apps inventory. gitlab.com/soapbox-pub/mkstack \u2014 accessed 2026-07-09 \u2014 commit count; license not visible/confirmed. Web search \u2014 accessed 2026-07-09 \u2014 github.com/divinevideo/divine-web confirms Divine is a separate org/team building on MKStack, not a Soapbox-owned product. soapbox.pub/transparency (report-index pass) \u2014 accessed 2026-07-09 \u2014 quarterly report titles confirming the \"pivot to AI-assisted programming tools\" dating (May\u2013July 2025) and unbroken Q3-2023\u2192Q1-2026 report sequence. soapbox.pub/blog/how-soapbox-ships-fast \u2014 accessed 2026-07-10 \u2014 Dirk Rost's role (code review, MR approval, \"bird's-eye view\"), open-infra + plain-markdown personality framing. soapbox.pub/blog/meet-quilly \u2014 accessed 2026-07-10 \u2014 Quilly's role (docs/community/GitLab), \"newest member of Team Soapbox\" self-description; note byline/date inconsistency (Jan 2025 byline vs. Jan 2026 visible date). HRF Bitcoin Development Fund grant-round announcements (hrf.org/latest and related 2026 posts) \u2014 accessed 2026-07-10 \u2014 2026 rounds name Snort, Coracle, Zapstore, Elsat and others; no round found naming Soapbox, Ditto, or Agora, supporting the HRF reclassification to prize/event partner. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set), \u00a72 fact 5 \u2014 Gleason-authorship percentages (Nostrify 85.2%, mkstack 71.9%, ditto-relay 99.3%, Ditto 47.4%) measured via GitLab/GitHub repo APIs, 2026-07-10; Ditto's secondary maintainers (Danidfra, marykatefain, derekross) named there."
    },
    {
      "id": "manual/02-community-ops",
      "kind": "manual",
      "lang": "en",
      "title": "Community & Company Operations \u2014 Ditto (public community) + Armada (team ops, early)",
      "url": "/manual/#ch02",
      "md_url": "/manual/md/02-community-ops.md",
      "sha256": "e5a1c62e70d1b4a2543bf576c958561bbeaee098372b7146f9252d64660ec536",
      "bytes": 38139,
      "headings": [
        "Two Products, Not One Gap",
        "The Armada Verdict \u2014 Corrected 2026-07-09",
        "What Ditto Is",
        "Capabilities Matrix",
        "Architecture & Self-Hosting",
        "Filesharing Verdict",
        "Company-Ops Fit",
        "Pricing & Access",
        "Setup Runbook (as documented)",
        "Armada",
        "What Armada Is",
        "The Concord Protocol",
        "Architecture",
        "Capabilities Matrix",
        "Filesharing Verdict \u2014 Armada",
        "How to Try It Today",
        "Maturity Warning",
        "Incumbent Comparison",
        "Integration Points",
        "Open Questions",
        "Sources"
      ],
      "body": "Verified: 2026-07-09 \u2014 Armada correction pass: 2026-07-09 Two Products, Not One Gap \"Community AND company operations, can it do filesharing\" turns out to map onto two separate Soapbox products, not a gap in one: Ditto Armada Job Public, branded community server (Mastodon-API shaped) Discord-shaped team chat (Concord protocol) Maturity Mature, ~2 years of public releases Real, but 26 days old \u2014 created 2026-06-13, shipping ~daily Encryption No (community content is public-by-design) Yes, by default Filesharing CAN (media) / PARTIAL (no drive) CAN (encrypted media) / UNCONFIRMED (non-image files) Ditto (below, unchanged from the first research pass) is the public-facing answer. Armada \u2014 added in this correction pass \u2014 is the internal-team answer. The Armada Verdict \u2014 Corrected 2026-07-09 The verdict below was wrong in the prior draft. Re-verified this pass by fetching the GitLab repo, its CHANGELOG, a sibling plugin repo, and Soapbox's own product page directly. Question Answer Does Soapbox.pub make a product called \"Armada\"? Yes. Confidence High \u2014 primary-sourced (repo, CHANGELOG, sibling repo, landing page) What it is An E2E-encrypted, Discord-shaped Nostr chat app on a new \"Concord\" protocol \u2014 full section below Repo gitlab.com/soapbox-pub/armada \u2014 created 2026-06-13, AGPL-3.0, 484 commits, 46 releases as of this research [33] Why the first pass missed it 26 days old at verification time, no blog announcement, absent from both soapbox.pub/tools/ and soapbox.pub/toybox \u2014 the two index pages the first pass correctly and thoroughly checked. Only discoverable via the GitLab group directly, or one nav-menu link on the soapbox.pub homepage to /armada [36][41][42][43]. A product-index search was the wrong instrument for a 26-day-old, unannounced repo. Flotilla \u2014 still correct Flotilla (flotilla.social) is a real but separate, unrelated project (hodlbod/Coracle, not Soapbox) \u2014 that part of the original verdict stands [6]. armada.buzz Re-tested this pass (https, http, archive) \u2014 still fails to resolve. Not Armada's domain; the real one is soapbox.pub/armada [44]. Sidebar \u2014 Flotilla, in one paragraph: A separate, Discord/Slack-shaped PWA built on \"relays as groups\" (NIP-29) [6]. Where Ditto is one branded server = one community, Flotilla lets a single relay host many independent group spaces. Not part of Soapbox's stack. Armada (below) is Soapbox's own answer to the same \"Discord-shaped internal chat\" need \u2014 and unlike Flotilla, it's E2E encrypted by default. What Ditto Is \"Ditto is a Nostr community server. It has a built-in Nostr relay, a web UI, and it implements Mastodon's REST API.\" [7] \"Ditto is a self-hosted server featuring a community-centered Nostr relay with a built-in UI.\" [8] Confidence: High (both quotes are from Soapbox's own blog). Note a real wrinkle: Ditto's current marketing copy pitches a lighter framing \u2014 \"Deploy it on a $5 VPS, GitHub Pages, or a Raspberry Pi in your closet\" [9] \u2014 that describes the static React/Vite frontend build [10][11], not the stateful Deno+Postgres backend that actually runs your relay, moderation, and Mastodon API [7][12]. GitHub Pages cannot run a database. Both descriptions are true of different halves of the same repo; see Architecture below. Capabilities Matrix Capability Status Detail Confidence Built-in Nostr relay Yes Ships with the server; your instance is also a relay [7] High Mastodon-API compatible Yes \"Works with most Mastodon apps\" via NIP-46 bunker login \u2014 50+ apps documented (Ivory, Tusky, Elk, etc.) [13][14] High Custom domain + branding Yes Themes (9 presets, 19 CSS tokens), NIP-05 domain-based identity High Bridges to Mastodon/Fediverse Yes Via Mostr Bridge [15] High Bridges to Bluesky Yes, indirect Mostr \u2192 Bridgy Fed relay chain; 15+ min propagation delay Medium Admin/moderator roles Yes Distinct admin & moderator roles; reports, post deletion, user approval [16] High Custom moderation policies Yes Scriptable policies incl. an OpenAI-backed content-scoring policy [16] Medium Full-text search Yes Postgres full-text search (NIP-50) [17] Medium (search-summary sourced) Native private DMs Not documented NIP-17/NIP-04 absent from Ditto's own official NIP reference list [18] Medium NIP-29 relay-groups (Discord-style) No That's Flotilla's model, not Ditto's [6] High NIP-72 Reddit-style communities Partial Listed in Ditto's NIP reference [18], but Ditto's actual community unit is the server/domain, not a NIP-72 sub-group \u2014 Chorus and Amethyst are the NIP-72-native clients [19][20] Medium Hosted (no self-host) option Yes, one ditto.pub \u2014 the official flagship instance, open enrollment, light moderation, free username [21] High Multi-tenant paid hosting Not found No pricing tiers or \"spin up your branded instance for $X/mo\" product located Medium Architecture & Self-Hosting Two independently-corroborated paths reach this same shape: Manual VPS path (third-party, detailed, technical \u2014 Linux/macOS only, Windows unsupported): install Deno v1.45.2, PostgreSQL, Nginx, Certbot; create a ditto system user; deno task setup generates .env (domain, DB credentials, media backend choice); provision Postgres; configure Nginx; certbot --nginx for TLS [12]. Docker path (community-maintained, not first-party): the arteeh/ditto image + a Postgres container on a shared network. Required env vars: DITTONSEC (relay keypair), DATABASEURL, LOCALDOMAIN, PORT (default 6996), optional DITTOPOLICY [22]. Linux amd64 only. Confidence: Medium-High (both paths are documented, but neither is the current first-party about.ditto.pub guide, which 404'd during verification \u2014 official docs appear to be mid-migration between docs.soapbox.pub and about.ditto.pub as of this writing). Filesharing Verdict Precise question: can a team use this stack instead of Google Drive/Dropbox? Use case Verdict Why Post images/video/audio in a feed or chat CAN Native Blossom upload path, configurable per-server [12][23] Arbitrary file types (PDF, .docx, .zip) PARTIAL Blossom stores any blob by SHA-256 hash \u2014 protocol-agnostic to file type \u2014 but Ditto's own UI is built around feed content, not a file browser [23][24] Folder structure / organized drive CAN'T (workaround lapsed) \"Blossom Drive\" (a separate, third-party app) layered folders on Blossom blobs via kind-30563 events \u2014 not a Ditto feature [25], and now deprecated/unmaintained upstream; its named successor Bouquet is an ad-hoc blob manager, not a drive (see ch. 06, Files & Media) Team permissions on shared files CAN'T (not found) No sharing/ACL mechanism documented beyond \"public server, anyone with the hash/URL can fetch it\" [23][25] Version history / collaborative editing CAN'T No documented feature; blobs are immutable, content-addressed \u2014 a new version is a new hash, not a revision Size limits Known ceiling Blossom spec: 100 MiB hard cap, 20 MiB on free-tier servers, \"no limit on total uploads or retention\" beyond that [26][27] NIP-96 (older HTTP file-storage NIP) Deprecated Formally marked \"unrecommended,\" superseded by Blossom [28] Bottom line: Ditto can absolutely carry a team's social/community media (photos, video, voice notes, event flyers). It is not a Drive/Dropbox replacement for internal document collaboration \u2014 no folders, no permissions, no version history, no office-doc preview, and the 100 MiB ceiling rules out most video-editing or design-asset workflows. The one folder-layer workaround has effectively lapsed \u2014 Blossom Drive is deprecated upstream (successor Bouquet manages blobs, not folders; ch. 06) \u2014 so the gap stands unbridged. Confidence: High on the CAN/CAN'T calls, Medium on exact size figures (spec-level, not Ditto-instance-verified). Company-Ops Fit Need Ditto's answer Verdict Private 1:1 or group DMs Not in Ditto's documented NIP set (no NIP-17/NIP-04 listed) [18] Gap \u2014 use a different Nostr client, or Flotilla, for private chat Team/relay-based groups (Discord-shaped) Not Ditto's model Use Flotilla (NIP-29) instead Public communities / sub-groups (Reddit-shaped) Interop-level only; native unit is the whole server Use Chorus (NIP-72-native) for this shape instead Announcements Local feed + Explore tab, domain-scoped Works Events/calendar NIP-52 calendar events supported [18] Works Bots / automation Any Mastodon-API bot framework (access tokens), or native Nostr bots against the built-in relay [14][29] Works, standard tooling Search Postgres full-text search across the instance [17] Works Data export / backup Philosophical guarantee only \u2014 \"your identity, content, and connections belong to you... take everything with you\" [30] \u2014 no documented one-click export/GDPR tool found Gap \u2014 portability is structural (signed events, any key), not a shipped export button Multi-account / staff management Admin + moderator roles; username revocation, admin promotion documented in v1.3 release notes [16][31] Works, basic Pricing & Access Path Cost Notes Join the flagship instance Free ditto.pub, open enrollment, light moderation [21] Self-host, manual VPS ~$5-10/mo (VPS) Your time + a domain; AGPL-3.0, no license fee [12] Self-host, Docker ~$5-10/mo (VPS) arteeh/ditto is community-maintained, Linux amd64 only [22] Branded multi-tenant hosted plan Not found No evidence Soapbox sells managed hosting; self-host or join the flagship are the only two documented doors Setup Runbook (as documented) Provision a Linux VPS (Ubuntu recommended) and point a domain's DNS at it [12]. Install system packages: git curl unzip nginx postgresql-contrib certbot python3-certbot-nginx [12]. Install Deno (pinned version, e.g. v1.45.2) [12]. Create a dedicated ditto system user; clone the repo to /opt/ditto, chown to that user [12]. Run deno task setup \u2014 generates .env with domain, DB credentials, and your media-backend choice (Blossom / S3 / local / IPFS / nostr.build) [12]. Provision the Postgres database and user (dittodbuser / dittodb by convention) [12]. Copy and edit the Nginx site config with your server_name [12]. Run certbot --nginx to obtain and wire up TLS [12]. Visit your domain to confirm the Ditto template renders [12]. Docker alternative to steps 2-8: run the arteeh/ditto + Postgres compose stack with DITTONSEC, DATABASEURL, LOCAL_DOMAIN set, behind your own reverse proxy [22]. Set admin role on your own pubkey, then use the admin dashboard to configure moderation policies, NIP-05 approval flow, and theme [16]. Confidence: Medium \u2014 steps 1-9 are a verified third-party walkthrough, not the current first-party guide (which redirected/404'd mid-research); version-pinned details (Deno v1.45.2) may have drifted. Armada Verified: 2026-07-09. Repo is 26 days old at time of writing \u2014 expect drift; re-check before relying on specifics. What Armada Is \"Armada is an end-to-end encrypted community chat app built on Nostr.\" [34] \"Discord without the company. Your keys. Your people.\" [41] Discord-shaped: servers, channels, threads, voice, roles, DMs, events/RSVP, emoji reactions, markdown [41]. Unlike Ditto, encryption is the default, not absent \u2014 every chat/invite/rekey event is sealed before it touches a relay [34]. Confirmed sibling repos (armada-relay, openclaw-armada) independently corroborate the product and protocol name [36]. The Concord Protocol \"A serverless, end-to-end encrypted community protocol... All control/chat/invite/rekey traffic is gift-wrapped (NIP-59) over generic Nostr relays.\" [34] Concord is Soapbox's own protocol \u2014 numbered CORD-01 through CORD-07, a sibling spec built on top of Nostr's NIPs, not a NIP itself. It runs on standard public Nostr relays (no special server), using NIP-59 gift-wrapping for every event plus NIP-42 relay auth with per-session derived keys [38]. Spec Function Confidence CORD-05 Invite links \u2014 encrypted key bundle + community identity check High (plugin docs) [38] CORD-06 \"Rekeys and refoundings\" triggered on membership change High (plugin docs) [38] CORD-07 Blind LiveKit token broker for voice \u2014 broker \"learns nothing about the community\" [34] High (README quote) CORD-01\u201304 Not identified in sources found this pass Open question \"Who sent it, which community it belongs to, even the community's name \u2014 all sealed.\" [41] That metadata-privacy claim is stronger than typical E2EE (which usually still leaks who's-talking-to-whom). It is a DOCUMENTED claim in the README and marketing copy \u2014 this pass found no independent security audit confirming it holds up. Whether CORD-06 rekeying gives MLS- or Signal-style forward secrecy is not stated anywhere found \u2014 treat as unconfirmed, not as \"it's MLS.\" A second, non-default path exists: NIP-29 relay-groups for operators who want a self-hosted server instead of the serverless default [34]. Two live implementations already coexist in the codebase \u2014 concord-v1/ and concord-v2/ \u2014 the protocol has already been rebuilt once in under a month [39]. Architecture Confidence: High on client/protocol shape (README + landing page agree); High that the NIP-29 self-host path is real but immature (armada-relay = 1 commit, created the same day as this research) [37]. Capabilities Matrix Capability Status Detail Confidence E2E encrypted group chat (Concord, default) Yes NIP-59 gift-wrapped chat/invite/rekey traffic over generic relays [34] High Metadata privacy (sender/community sealed) Claimed \"Who sent it, which community it belongs to... all sealed\" [41] Medium \u2014 claim, not audited Servers / channels / threads / roles Yes Discord-shaped, role-based moderation [41] High Voice + screen share Yes WebRTC/LiveKit; screen share shipped v0.1.0; 1:1 calls v0.9.0; identity verification v0.18.0 [35] High Voice privacy (blind broker) Claimed CORD-07 broker \"learns nothing about the community\" [34] Medium Image/media attachments in encrypted channels Yes Blossom-backed; encrypted images \"decrypt and display inline\" (v0.6.0, v0.8.3) [35][39] High Non-image files (PDF / .docx / .zip) Unconfirmed No changelog or doc evidence either way Low \u2014 open question Bluetooth mesh chat (offline) Yes Android only, v0.13.0 [35][41] High Push notifications without Google services Yes Android, v0.3.0 [35] High Self-hosted server option (NIP-29) Yes, but immature armada-relay: 1 commit, created 2026-07-09 [37] High it's real; High it's immature AI agent / bot community members Yes openclaw-armada plugin \u2014 agents decrypt invites, join, respond, DM [38] High Native iOS app No Web app only, works in mobile Safari [41] Medium Data export / portability Not documented for Armada specifically Nostr-key portability philosophy presumably applies (per Ditto's pattern) but not stated for Armada Low \u2014 inferred Filesharing Verdict \u2014 Armada Same precise question as Ditto: can a team use this instead of Google Drive/Dropbox? Use case Verdict Why Post images/media in a channel or DM CAN Blossom-backed (BlossomServerListEditor.tsx in-repo) [39]; encrypted images decrypt and display inline inside Concord communities [35] ...and is it E2E encrypted, not just server-hosted? CAN \u2014 stronger than Ditto Attachments ride inside the same gift-wrapped Concord protocol as messages, a real architectural difference from Ditto's plaintext-on-Blossom-URL model Arbitrary file types (PDF, .docx, .zip) UNCONFIRMED No changelog/doc evidence of non-image attachment handling; Blossom itself is blob-type-agnostic, but Armada's UI behavior for non-image blobs isn't documented anywhere found Folder structure / organized drive CAN'T (not found) No Blossom Drive or folder layer mentioned in README, CHANGELOG, or landing page Team permissions on shared files CAN'T (not found) No ACL beyond community membership itself documented Version history CAN'T Not documented; same content-addressed-blob limitation Blossom has generally Size limits Not confirmed for Armada Underlying Blossom spec ceiling (100 MiB, per Ditto's research above) presumably applies but wasn't confirmed as Armada's actual configured limit Bottom line: narrower than Ditto's filesharing story, but more private where it exists. Armada CAN carry E2E-encrypted image/media drops inside a private team chat today \u2014 a genuinely stronger privacy story than Ditto's, since the content itself (not just the transport) is sealed. It is not confirmed to handle arbitrary document types, and there is no evidence at all of folders, permissions, or version history \u2014 so it's still not a Drive/Dropbox replacement, for different reasons than Ditto (missing breadth here, vs. Ditto missing E2EE and hitting a hard size cap). Confidence: Medium overall \u2014 image-attachment behavior is CHANGELOG-confirmed; everything else in this table is an absence-of-evidence call on 26-day-old software, not a confirmed \"no.\" How to Try It Today Web: soapbox.pub/armada \u2192 \"Open Armada\" \u2014 works in any browser, including mobile Safari/iOS (no native iOS app) [41]. Android: native app via Capacitor; configured for Zapstore distribution (zapstore.yaml in-repo) [39][46]; native push bypasses Google services; Bluetooth mesh works fully offline [35][41]. Desktop: Electron builds for Linux and Windows (no Mac build found or mentioned) [34][41]. Join a community via an invite link \u2014 the unlock key rides in the URL fragment, so it never touches a server [41]. Self-host (NIP-29 path): marketing copy claims a \"complete open-source server stack,\" but the backing repo (armada-relay) had one commit, created the same day as this research \u2014 treat self-hosting as not yet real-world ready [37][41]. armada.buzz does not resolve \u2014 use soapbox.pub/armada [44]. Maturity Warning 26 days old, ~daily releases, self-described as \"Early version (0.x)\" on its own landing page [41]. In the 17 days since v0.1.0 (2026-06-22), the protocol has already gone through a v1\u2192v2 rebuild, an encryption-label change reversed days later, and a self-host backend that only started today [35][39][37]. The most recent 25 releases (v0.17.0 \u2192 v0.25.3) landed in just five days (2026-07-05 to 2026-07-09) \u2014 velocity is accelerating, not settling [40]. At least two named committers (Alex Gleason, Chad Curtis) \u2014 a small team, not a solo project, but this pass found no visible external community contributions [40]. Good to pilot and watch closely; do not bet confidential company operations on it without your own review \u2014 nothing here has been independently security-audited. Incumbent Comparison Dimension Ditto-centered Nostr stack Armada (Concord) Slack Discord Circle Mighty Networks Community (public) Strong \u2014 branded server, themes, bridges out to Bluesky/Mastodon, no platform lock-in Weak fit \u2014 private-by-default, no branded public-server story Weak fit (internal-tool DNA) Strong, mainstream, zero setup Strong, purpose-built Strong, purpose-built Internal company ops Weak \u2014 no native private DM spec, no threads-as-Slack-channels model Promising but 26 days old \u2014 Discord-shaped, E2E encrypted by default, zero track record Best-in-class Good (voice-first) Moderate Moderate Filesharing Weak \u2014 100 MiB cap, no folders/permissions/versioning Partial \u2014 E2E-encrypted image/media, but no folders/permissions/versioning; non-image types unconfirmed Good (with Drive/Box integration) OK (free tier capped ~10-25 MB/msg; paid raises it) Good (course/doc-shaped) Good (course/doc-shaped) Cost at small-team scale ~$5-10/mo self-host, or free (flagship, no admin control) Free (hosted default relays); self-host (NIP-29) path exists but backend repo has 1 commit as of this research Free tier thin; Pro ~$7.25-8.75/user/mo [32] Free; Nitro $4.99-9.99/mo optional [32] From $89/mo [32] From $41/mo [32] Data portability Structurally strong (your keys, signed events) but no shipped export tool Same Nostr-key philosophy presumably applies; not independently confirmed for Armada specifically Low (vendor lock-in) Low Low-Moderate Low-Moderate Setup effort High (VPS + Deno + Postgres + Nginx, or Docker) Low for default path (open web app, invite link); self-host path not yet production-real None (SaaS) None (SaaS) None (SaaS) None (SaaS) Where Nostr loses outright No mature private-DM story on Ditto itself, no file-drive replacement, self-hosting is real ops burden, no managed multi-tenant SaaS to buy Unaudited crypto, protocol already rebuilt once (v1\u2192v2) in under 30 days, ~2 named committers, self-host not production-ready \u2014 \u2014 \u2014 \u2014 Confidence: High on Ditto-column facts (cited above); High on Armada being real, Medium-Low on its unaudited/unconfirmed claims (marked throughout); Medium on incumbent pricing (current as of search date, subject to normal SaaS pricing drift) [32]. Integration Points Connects to Mechanism Enables Mastodon apps (Ivory, Tusky, Elk, 50+ others) Mastodon REST API + NIP-46 bunker login Staff can use familiar mobile/desktop clients against your Ditto server [13][14] Fediverse (Mastodon servers) Mostr Bridge Cross-posting/following between Ditto and any ActivityPub server [15] Bluesky Mostr Bridge \u2192 Bridgy Fed relay chain Indirect follow/reply bridging, ~15+ min lag Blossom media servers BUD-03 upload spec, SHA-256 addressing Resilient, mirrorable media hosting decoupled from any one server [23][26] Any Nostr client (Damus, Amethyst, primal, etc.) Standard relay connection to your built-in relay Members aren't locked into Ditto's own UI [7] Shakespeare (Soapbox's AI site builder) \"Edit and remix the entire platform\" [9] Rebrand/customize a Ditto or MKStack-based deployment without deep React expertise MKStack-built apps (Chorus, Plektos, etc.) Shared Nostr event layer Content posted in sibling apps (events, groups) can surface in a Ditto feed if event kinds overlap [19][20] OpenClaw AI agents (Armada) openclaw-armada plugin \u2014 CORD-05 invite decrypt, NIP-42 multi-key auth Bots/AI agents join Concord communities as real members, monitor channels, respond, DM [38]. OpenClaw itself is an independent open-source agent framework, not a Soapbox product [45] Blossom media servers (Armada) Same BUD-03 upload spec as Ditto, configurable per-client Encrypted image/media attachments inside Concord channels [39] Zapstore (Armada) zapstore.yaml release config in-repo Android distribution outside Google Play, cryptographically signed releases [39][46] Generic Nostr relays (Armada) NIP-59 gift-wrap + NIP-42 auth, no special server required Concord communities run on any standard public relay \u2014 no Armada-specific infrastructure needed [34] NIP-29 relays (Armada self-host path) armada-relay (early \u2014 1 commit as of this research) Operator-controlled team server, trading some Concord privacy for admin control [34][37] Open Questions Is about.ditto.pub's canonical self-hosting guide currently live at a different path than what redirected/404'd during this research pass? Worth re-checking directly before an actual deployment. Whether Ditto's NIP-72 listing in its own reference means it reads and displays NIP-72 community events from other clients (interop) or only that some internal code path touches the kind \u2014 not confirmed either way. Whether any DM capability exists via a non-listed NIP or a Mastodon-API \"direct\" visibility mapping \u2014 not found in official docs, but not exhaustively ruled out either. Whether \"Stacks\" (getstacks.dev) is a Docker-compose bundler specifically for Ditto, or a broader \"AI project template\" sharing site unrelated to production deployment \u2014 direct fetch only returned a page title, inconclusive. Exact current numeric count behind the \"27+ content types\" marketing claim vs. the \"60+ event kinds\" reference-doc claim \u2014 likely two different countings (curated UI content types vs. raw protocol event kinds) but not reconciled to a single verified number. Armada: What are CORD-01 through CORD-04? Only CORD-05 (invites), CORD-06 (rekey/refounding), and CORD-07 (voice broker) were identifiable in sources found this pass. Armada: Does CORD-06 rekeying provide forward secrecy comparable to MLS or Signal's double ratchet? Not stated anywhere found \u2014 don't assume either way. Armada: Are attachment blobs encrypted client-side before reaching the Blossom server (true E2EE at the storage layer), or only the message pointer/metadata? The CHANGELOG's \"decrypt and display inline\" language implies the former but doesn't say so explicitly. Armada: Does the UI actually support non-image file types today? No evidence either way was found. Armada: Is armada.buzz a domain Soapbox owns and intends to launch on, or unrelated/parked? Unresolved after three independent failed fetch attempts across two research passes \u2014 use soapbox.pub/armada regardless. Armada: Is a native iOS app planned, or is web-only a deliberate design choice? Not stated. Armada: How real is the \"one-command server stack\" self-host claim on the landing page, given armada-relay had exactly one commit at time of writing? Worth re-checking in a few weeks. Sources Star Wars: Armada Fleet Builder \u2014 unrelated app, false-lead check. Accessed 2026-07-09. Soapbox Tools \u2014 full product/tool list with URLs; no Armada listed. Accessed 2026-07-09. Soapbox Toybox \u2014 full experiments list; Armada absent as a project. Accessed 2026-07-09. https://armada.buzz / http://armada.buzz \u2014 fetch failed both protocols (SSL WRONGVERSIONNUMBER). Accessed 2026-07-09. Web search \"armada.buzz\" \u2014 zero Nostr/Soapbox-related results. Accessed 2026-07-09. Flotilla \u2014 GitHub \u2014 \"A nostr relay-based communities PWA modeled after discord.\" Accessed 2026-07-09. Announcing Ditto \u2014 Soapbox Blog \u2014 original server architecture (Deno, Postgres, built-in relay, Mastodon REST API). Accessed 2026-07-09. Creating Curated Communities on Nostr with Ditto \u2014 community/moderation model. Accessed 2026-07-09. Soapbox Launches Massive Update to Ditto \u2014 relaunch marketing copy, \"$5 VPS, GitHub Pages, Raspberry Pi.\" Accessed 2026-07-09. gitlab.com/soapbox-pub/ditto / raw README \u2014 React 18 + Vite + TypeScript frontend stack. Accessed 2026-07-09. github.com/soapbox-pub/ditto \u2014 README mirror, same frontend-stack description. Accessed 2026-07-09. Setting up your own nostr community with Ditto \u2014 freedomweaver.tech \u2014 third-party manual VPS self-hosting walkthrough (Deno, Postgres, Nginx, Certbot). Accessed 2026-07-09. Unlocking 50+ Mastodon Apps for Nostr with Ditto \u2014 Mastodon-API client compatibility. Accessed 2026-07-09. Web search \u2014 Mastodon API access-token/bot-automation mechanics applied to Ditto. Accessed 2026-07-09. Introducing Mostr: a Fediverse Nostr bridge and How to Follow Bluesky Accounts from Nostr \u2014 bridge mechanics, Bluesky via Bridgy Fed relay chain, ~15 min+ lag. Accessed 2026-07-09. Ditto 1.3: Explore Nostr \u2014 Soapbox Blog \u2014 admin tools (username revocation, admin promotion), moderation features. Accessed 2026-07-09. Web search summary of stacker.news/items/863195 discussion \u2014 full-text search in Postgres, moderator/admin capabilities (direct fetch returned no content; sourced via search snippet only \u2014 lower confidence). Accessed 2026-07-09. Ditto Nostr Reference \u2014 about.ditto.pub/reference \u2014 official supported-NIPs list and event-kind count. Accessed 2026-07-09. NIP-72 \u2014 Moderated Communities \u2014 spec definition, kind 34550/4550. Accessed 2026-07-09. Chorus \u2014 GitHub (andotherstuff/chorus) and Chorus: An Experiment in Vibe Coding \u2014 NIP-72-native community app built with MKStack, distinct from Ditto's model. Accessed 2026-07-09. ditto.pub and web search on its flagship-instance status \u2014 free, open enrollment, light moderation. Accessed 2026-07-09. arteeh/ditto \u2014 Docker Hub \u2014 community-maintained Docker image, env vars, Postgres dependency. Accessed 2026-07-09. Blossom \u2014 GitHub (hzrd149/blossom) and NIP-B7 \u2014 Blossom media \u2014 protocol spec, SHA-256 addressing, mirroring. Accessed 2026-07-09. Blossom Uploader \u2014 Nostrify \u2014 integration reference. Accessed 2026-07-09. Blossom Drive: Store & Retrieve Data on Public Servers \u2014 folder/drive layer on top of Blossom, kind 30563 events. Accessed 2026-07-09. Web search on Blossom spec limits \u2014 100 MiB hard cap, 20 MiB free-tier convention. Accessed 2026-07-09. blossom.nostr.build \u2014 example Blossom server, up to 100MB. Accessed 2026-07-09. NIP-96 \u2014 HTTP File Storage Integration \u2014 marked unrecommended, superseded by Blossom. Accessed 2026-07-09. Web search \u2014 Nostr bot / Mastodon API automation patterns (nostrdon bridge example). Accessed 2026-07-09. Web search summary \u2014 Ditto's \"your identity, content, and connections belong to you\" data-portability claim. Accessed 2026-07-09. Ditto 1.3 release notes \u2014 staff/role management features. Accessed 2026-07-09. Web search \u2014 current Slack, Discord Nitro, Circle.so, Mighty Networks pricing tiers (2026). Accessed 2026-07-09. Armada correction pass (2026-07-09) \u2014 sources 33-46: gitlab.com/soapbox-pub/armada \u2014 main repo page: created 2026-06-13, AGPL-3.0, 484 commits, 17 branches, 62 tags, 46 releases. Accessed 2026-07-09. gitlab.com/soapbox-pub/armada/-/raw/main/README.md \u2014 verbatim definition of Armada and the Concord protocol, NIP-59 gift-wrap mechanics, NIP-29 self-host alternative, install instructions. Accessed 2026-07-09. gitlab.com/soapbox-pub/armada/-/raw/main/CHANGELOG.md \u2014 chronological feature history v0.1.0 (2026-06-22) through v0.25.x (2026-07-09): encrypted image attachments, voice/screen-share, Bluetooth mesh, Concord v2 cutover. Accessed 2026-07-09. gitlab.com/api/v4/groups/soapbox-pub/projects \u2014 GitLab group API listing; confirms armada, armada-relay, and openclaw-armada as sibling repos under soapbox-pub. Accessed 2026-07-09. gitlab.com/soapbox-pub/armada-relay \u2014 self-hosted backend repo: 1 commit, 1 branch, 0 releases, created 2026-07-09 \u2014 key maturity signal for the self-host claim. Accessed 2026-07-09. gitlab.com/soapbox-pub/openclaw-armada/-/raw/main/README.md \u2014 confirms Concord protocol spec numbering (CORD-01\u201307), NIP-59/NIP-42/kind-3313/kind-1059 mechanics, and OpenClaw AI-agent integration. Accessed 2026-07-09. GitLab repository-tree API for soapbox-pub/armada (root + recursive src/) \u2014 confirms parallel concord-v1/ and concord-v2/ implementations and BlossomServerListEditor.tsx (media/attachment config UI). Accessed 2026-07-09. GitLab releases API for soapbox-pub/armada \u2014 25 dated releases v0.17.0 through v0.25.3, spanning 2026-07-05 to 2026-07-09; named authors Alex Gleason and Chad Curtis. Accessed 2026-07-09. soapbox.pub/armada \u2014 the actual product landing page (not linked from /tools/ or /toybox): tagline, feature list, encryption claims, self-host claim, \"Open Armada\" CTA. Accessed 2026-07-09. soapbox.pub/blog/ \u2014 full blog index (101 posts); confirms /armada exists only as a main-nav link, no dedicated announcement post found. Accessed 2026-07-09. soapbox.pub/tools/ \u2014 re-verified this pass; Armada still absent from the product/tools index, consistent with the original chapter's finding and explaining the discovery gap. Accessed 2026-07-09. https://armada.buzz, http://armada.buzz, and a web-archive lookup \u2014 re-tested this pass; all three fail (SSL WRONGVERSIONNUMBER on both protocols; archive fetch could not connect). Confirms this is not Armada's working domain. Accessed 2026-07-09. github.com/openclaw/openclaw and open-claw.bot/docs/channels/nostr \u2014 background confirming OpenClaw is an independent open-source AI-agent framework (not a Soapbox product) with an existing Nostr channel plugin pattern. Accessed 2026-07-09. zapstore.dev and github.com/zapstore/zapstore \u2014 background on Zapstore, the Nostr-native Android app store Armada's repo is configured for (zapstore.yaml); Armada's own live listing was not independently confirmed. Accessed 2026-07-09."
    },
    {
      "id": "manual/03-agora",
      "kind": "manual",
      "lang": "en",
      "title": "Agora \u2014 Funding Rails",
      "url": "/manual/#ch03",
      "md_url": "/manual/md/03-agora.md",
      "sha256": "723ce95f1c14a51e786cc705fad5a3a393d39ac39d1a06ebda0097731dcd175d",
      "bytes": 16564,
      "headings": [
        "What It Is",
        "How a Donation Flows",
        "Campaign Creation & Eligibility",
        "Fees & Costs",
        "Custody, Compliance & Fiat Reality (US Operator Lens)",
        "Self-Host / White-Label",
        "Traction & Credibility",
        "Incumbent Comparison",
        "Integration Points",
        "Open Questions",
        "Sources"
      ],
      "body": "Agora is Soapbox's non-custodial, on-chain-Bitcoin fundraising app for activists \u2014 campaigns move wallet-to-wallet with zero platform fee, no KYC, and no approval step. Verified: 2026-07-09 What It Is Built by Soapbox (Alex Gleason's company) on Nostr + Bitcoin, Agora started as a hackathon project called Pathos and relaunched as Agora on June 2, 2026 at the Oslo Freedom Forum, announced by the World Liberty Congress (WLC) with Human Rights Foundation (HRF) backing. It lives at agora.spot (web) and on ZapStore (Android), with source at gitlab.com/soapbox-pub/agora. \"Agora never holds funds. Donations move wallet-to-wallet on Bitcoin.\" [1] \"Recipients sign up in seconds. No bank. No paperwork. No approval.\" [1] The platform describes itself as \"the world's first Borderless Micro-Philanthropy Network\" [8] \u2014 positioned specifically for activists, dissidents, and political prisoners, not general-purpose crowdfunding. How a Donation Flows Campaign donations run entirely on-chain \u2014 not Lightning. (Lightning appears elsewhere in the broader app for social tipping \u2014 see Integration Points.) Donors pick Public (standard address, visible forever, widest wallet support, fastest) or Silent (BIP-352, unlinkable fresh output, fewer wallets support it, slower, no push notifications) [6]. Creators choose which to accept, or both [7]. Campaign Creation & Eligibility Question Answer Evidence Who can create a campaign? Anyone with a Nostr key \u2014 no application \"No permission needed... no gatekeepers\" [7] Is it WLC/HRF-gated? No \u2014 permissionless by mechanism. WLC/HRF campaigns are featured, not exclusive [1][3] KYC for creators or donors? None documented at any Agora-controlled step FAQ costs/creators + donor guide [6][7] How does trust work, then? Opt-in and social: orgs publish a public \"verification statement\" vouching for campaigns they endorse \"your reputation does the work\" [7] Is anything moderated? Yes \u2014 Agora runs its own relay + Blossom file server, zero-tolerance CSAE policy, NCMEC/law-enforcement cooperation Safety page [8] Could TresPies or a client org start a campaign today? Technically yes \u2014 nothing in the flow blocks it Inferred from permissionless signup; no ToS document was located Would it fit the brand? Not natively \u2014 every launch campaign is a human-rights/political-prisoner cause [1][3] The gate here is social and reputational, not technical: Agora doesn't vet campaigns, but it also doesn't market itself to small businesses or general nonprofits \u2014 a non-activist campaign would be real and fundable, just off-brand and undiscoverable without its own audience. Fees & Costs Cost Charged by Rate Paid by Platform fee Agora $0 \u2014 \"no platform fees\" [1], \"we take nothing\" [10] n/a Bitcoin network (miner) fee Bitcoin network Market rate, varies with congestion Donor, on top of the gift [6] Donor's wallet/exchange fee Donor's own provider (Cash App, Strike, etc.) Varies by provider Donor BTC\u2192USD conversion Recipient's chosen exchange Standard trading/withdrawal fee Recipient, later, off-platform Agora's own cut is genuinely zero \u2014 the FAQ instructs donors to \"pay the amount plus the network fee\" [6], meaning the only unavoidable cost is Bitcoin's own transaction fee, not a Soapbox markup. Custody, Compliance & Fiat Reality (US Operator Lens) Custody is real and non-custodial: the receiving address is derived from the recipient's own Nostr secret key, and funds can be exported straight to Sparrow, BlueWallet, Trezor, or Ledger [7]. But \"no KYC at Agora\" doesn't mean \"no KYC anywhere\" \u2014 it just relocates to both ends of the transaction: Step Touches Agora? KYC/AML checkpoint? Campaign created, address derived from nsec Yes (app only) None Donor pays from their own wallet No \u2014 wallet-to-wallet Only if the donor's own wallet/exchange requires it (most retail apps do) BTC confirms on-chain No \u2014 Bitcoin network only None Recipient wants a US tax-deductible receipt No Not practically possible for anonymous/Silent-payment gifts \u2014 no donor name/address is ever captured Recipient converts BTC to spendable USD No \u2014 recipient's own exchange Standard exchange KYC/AML applies here Two general considerations for a US-based 501(c)(3) or small business \u2014 not legal advice: (1) the IRS treats crypto as property (Notice 2014-21); issuing a compliant donor receipt requires the donor's identity and fair-market-value at receipt, which Silent Payments structurally prevent and Public payments only partially provide (an address isn't a legal name). (2) Funds sit in BTC, subject to price movement, until someone manually off-ramps them \u2014 a $10,000 goal today isn't a fixed $10,000 in the bank the way a GoFundMe balance is. Self-Host / White-Label Agora is open source (AGPL-3.0) and built to be redeployed, not just used [4]: Requirement Detail License AGPL-3.0 \u2014 copyleft; a hosted fork must offer source to its users Stack React 18, Vite, TypeScript, Tailwind 3 + shadcn/ui, React Router, TanStack Query, Nostrify + nostr-tools, Capacitor (mobile), Vitest Hosting Builds to static files \u2014 GitLab/GitHub Pages, Netlify, Vercel, or any VPS; Docker Compose path documented Config agora.json (gitignored) for per-deployment branding/relays; CONFIG_FILE env var for a custom path Multi-tenant SaaS option None found \u2014 no hosted \"Agora for Teams\" product; this is fork-and-run, not buy-a-plan Skill needed A developer fluent in a modern React/Nostr stack, plus a relay (and optionally a Blossom file server) to operate Verdict: technically real, but it's a codebase to fork and operate, not a product to purchase. Realistic for a dev-capable client; not a weekend project for a non-technical one. Traction & Credibility Signal Detail Launch June 2, 2026, Oslo Freedom Forum [9] Origin HRF's \"AI Hack for Freedom,\" Bitcoin Park, Austin, Jan 17\u201318, 2026; Team Soapbox (\"Pathos\") took 2nd place, 0.25 BTC = 25M sats [2][12] Early hackathon traction 100+ users within 24 hours of the original build [2] Backers Human Rights Foundation, World Liberty Congress (Leopoldo L\u00f3pez), Soapbox, \"And Other Stuff\" [10] Independently verified press PRNewswire wire release, syndicated to Yahoo Finance, StreetInsider, Amsterdam Aesthetics, Norwegian outlet Geopolitika [9][11] Self-reported-only press Forbes, Associated Press \u2014 claimed on Agora's own sponsors page; not independently located in this research [10] Only public dollar figure found Venezuela pilot: $8,420 of $10,000 goal, 247 donors, 12 countries [1] Platform-wide totals ($ raised, live campaigns) Not published anywhere found Confidence: Medium. The launch itself and WLC/HRF backing are solidly corroborated by an independent wire release; platform-wide traction is not \u2014 the one dollar figure available comes from Agora's own marketing page, not an independent scan. Incumbent Comparison Platform Fee Custody KYC Rails Where it beats Agora Agora 0% + BTC network fee Non-custodial, always None On-chain BTC only (baseline) GoFundMe 2.2\u20132.9% + $0.30/donation [16] Custodial Government ID + bank account, ~20 countries [16] Card/bank, USD Discovery, trust, card checkout, disputes, tax help Kickstarter 5% + ~3%+$0.20 processing Custodial, all-or-nothing Bank/tax info Card, USD Built-in audience, reward mechanics Patreon ~10% + ~3% processing Custodial Bank/tax info Card, USD Recurring billing, tiered perks, mainstream reach Open Collective 0\u201310%, fiscal-host dependent Semi-custodial (fiscal host holds funds) Fiscal host's own KYC Card/bank, USD Public expense ledger, legal nonprofit wrapper Geyser.fund 0% (own node) to 5% (Geyser wallet) + 10% for promotion [17] Non-custodial (Boltz-Exchange swap) None for creators [17] On-chain BTC + Lightning Lightning speed/cost, built bitcoiner audience, reward campaigns, longer track record Confidence: Medium \u2014 Agora's own figures are primary-sourced; incumbent fee figures are drawn from secondary aggregation (help-center pages and pricing trackers), not each platform's raw fee schedule fetched directly. Where Agora structurally loses, regardless of fees: no card/fiat donor checkout (a donor must already own or acquire BTC themselves), no Lightning option for cheap micro-donations, no reward or membership mechanic, five weeks of track record versus GoFundMe's ~15 years, and a brand that reads as off-topic for anything that isn't a human-rights cause. Integration Points Connects to Mechanism Enables Lightning wallets NIP-57 zaps (kind 9734 request / 9735 receipt) [13] In-app tipping of posts/activists \u2014 a separate rail from campaign donations Remote Lightning wallet NIP-47 Nostr Wallet Connect (NWC) [14] One-tap zap payment without exposing keys to the client Browser Lightning extension WebLN [4] Alternate in-browser zap path On-chain BTC wallets BIP-352 Silent Payments Unlinkable, private per-campaign donation addresses Nostr relay network Nostrify + nostr-tools; Agora runs its own relay + Blossom file server [4][8] Campaign posts, updates, social graph, moderation Hardware/desktop wallets Seed export Move campaign funds to Sparrow, BlueWallet, Trezor, Ledger Static hosting / Docker AGPL-3.0 open-source build [4] Self-hosted, white-label forks (copyleft obligation attached) Android distribution ZapStore [9] Censorship-resistant install path outside Google Play External sites (e.g. Shakespeare-built pages) None found No embed/iframe/widget documented \u2014 only linking out to an agora.spot URL is confirmed possible Zap Goals (NIP-75, kind 9041) [15] Not confirmed in use The ecosystem-standard Lightning crowdfunding-goal event exists, but Agora's on-chain goal bar is not documented as using it \u2014 likely custom logic instead Open Questions Exact Nostr event kind(s) recording the on-chain campaign/donation itself (site says donations are \"public... on Nostr\" [1] but doesn't name the kind) Whether NIP-75 powers campaign goal-tracking, or if it's bespoke Mechanism for posting campaign updates to donors (standard Nostr notes vs. a dedicated notification path) Any embed/widget capability for third-party sites \u2014 none located Platform-wide traction (total raised, total live campaigns, total donors) beyond the single featured example Whether the claimed Forbes/AP coverage is substantive \u2014 could not independently locate either Full workings of the org \"verification statement\" feature (concept confirmed, UI/workflow not) No Terms of Service document was located despite being referenced from the FAQ No iOS listing found \u2014 web and Android/ZapStore only, cause unconfirmed Sources soapbox.pub/agora \u2014 Soapbox, \"Agora \u2014 GoFundMe Without Borders.\" Accessed 2026-07-09. Supports: tagline, custody quote, zero-fee claim, payment options, Venezuela campaign figures. soapbox.pub/blog/building-pathos \u2014 Soapbox blog, \"Building Agora: From Hackathon to Real-World Activism.\" Accessed 2026-07-09. Supports: Pathos\u2192Agora rename, hackathon origin, 25M-sat prize, 100+ users in 24h. soapbox.pub/blog/agora-connecting-freedom-fighters \u2014 Soapbox blog. Accessed 2026-07-09. Supports: launch story, WLC/HRF/Bitcoin Park partnership, Venezuela pilot, 2026 expansion countries. gitlab.com/soapbox-pub/agora \u2014 GitLab repository + README. Accessed 2026-07-09. Supports: AGPL-3.0 license, tech stack, self-hosting/Docker instructions, config model, Nostr kinds, Lightning zaps via NWC/WebLN. agora.spot \u2014 Live app. Accessed 2026-07-09. Supports: navigation structure, \"zero platform fees.\" agora.spot/help/donors and agora.spot/help \u2014 Donor guide + FAQ. Accessed 2026-07-09. Supports: 3-step donation flow, network-fee statement, wallet list, Public vs. Silent explanation. agora.spot/help/activists and agora.spot/verify \u2014 Activist guide + verify page. Accessed 2026-07-09. Supports: non-custodial confirmation, wallet export options, permissionless creation, org verification-statement model. agora.spot/safety and agora.spot/about \u2014 Safety + about pages. Accessed 2026-07-09. Supports: \"Borderless Micro-Philanthropy Network,\" no-Lightning-for-donations, CSAE policy, own relay + Blossom server. PRNewswire \u2014 World Liberty Congress Launches Agora at Oslo Freedom Forum. Accessed 2026-07-09. Supports: June 2, 2026 launch date, L\u00f3pez/Fain quotes, launch countries, ZapStore/Android distribution. agora.spot/sponsors \u2014 Sponsors page. Accessed 2026-07-09. Supports: partner list, self-reported press coverage. Yahoo Finance \u2014 World Liberty Congress Launches Agora (syndicated PRNewswire). Accessed 2026-07-09. HRF \u2014 HRF Sponsors AI Hack for Freedom in Austin, TX, Jan. 17-18. Accessed 2026-07-09. Supports: hackathon structure, prize tiers (0.5/0.25/0.1 BTC), dates. NIP-57 \u2014 Lightning Zaps. Accessed 2026-07-09. Supports: kind 9734/9735 definitions. NIP-47 \u2014 Nostr Wallet Connect. Accessed 2026-07-09. Supports: NWC mechanics. NIP-75 \u2014 Zap Goals. Accessed 2026-07-09. Supports: kind 9041, amount/relays tags, goal semantics. GoFundMe Help Center \u2014 Requirements to receive funds and Learn about GoFundMe fees. Accessed 2026-07-09. Supports: GoFundMe fee rates, ID/bank/country requirements. Geyser Guide \u2014 Geyser Fees and How on-chain contributions work. Accessed 2026-07-09. Supports: Geyser fee tiers, Boltz-Exchange non-custodial swap, no-KYC-for-creators. Kickstarter, Patreon, and Open Collective fee figures \u2014 aggregated via web search of secondary pricing-comparison sources (not each platform's own pricing page fetched directly). Accessed 2026-07-09. Confidence: Medium; treat as directionally accurate, not verbatim-verified."
    },
    {
      "id": "manual/04-shakespeare",
      "kind": "manual",
      "lang": "en",
      "title": "Shakespeare \u2014 AI Website/App Builder on Nostr",
      "url": "/manual/#ch04",
      "md_url": "/manual/md/04-shakespeare.md",
      "sha256": "d0a21c08872118251aeda1e76087bc48c30666b14b5bea98c44e05ab65fe4d22",
      "bytes": 27597,
      "headings": [
        "What It Is",
        "How It Works",
        "Cost Mechanics \u2014 The Free-Mockups Verdict",
        "Funnel Capability Matrix",
        "Deployment Paths",
        "Code Ownership & Export",
        "Limits & Workflow",
        "Agency Comparison",
        "Integration Points",
        "Open Questions",
        "Sources"
      ],
      "body": "A browser-only, open-source AI coding environment that chats you into a React app, stores the code on your machine (not Soapbox's servers), and deploys it to a free subdomain or anywhere else you point it \u2014 priced by the AI token, not the seat. Verified: 2026-07-09 \u00b7 Amended: 2026-07-10 (v2 wave) \u2014 flagged the BYOK claim UNRESOLVED (a live re-fetch of the announcement post shows no BYOK mechanism mentioned; custody location unknown) without deleting the original claim; added the NostrDeploy.com DNS-tripwire annotation (not previously present in this chapter, unlike ch. 10); flagged Stacks CLI provider-key storage as unknown/unfound. Confidence: High for architecture, storage, license, and deployment-target facts (multiple primary Soapbox sources agree). Medium for exact current pricing/free-tier durability and for funnel/data-capture mechanics (documented capability exists; where captured data actually lands is not spelled out by Soapbox and is partly inferred from the tool's no-backend architecture). Low for anything competitive (Lovable/Bolt/Webflow/Framer cells are general-knowledge, not independently fetched from those vendors this pass). What It Is \"Shakespeare is a web interface where you can build websites through conversation with AI assistants.\" [2] It is Soapbox's consumer-facing wrapper around MKStack, its Nostr app framework: \"bringing the power of MKStack to everyone through natural conversation\" [1]. Announced July 10, 2025 and publicly launched July 14, 2025 at a Human Rights Foundation event [2][10], it is not a template picker \u2014 it is a full in-browser IDE. Act 2 (Oct 2025) reframed it as \"a full-featured development environment, entirely in your browser\": code editor, hot-reload preview, in-chat terminal, file uploads [3]. Founder Alex Gleason's framing: \"It used to be hard to build websites using decentralized protocols. But Nostr + AI makes this something that anyone can do now.\" [10] Soapbox runs it \"trust-based\" rather than subscription-funded, with no outside revenue disclosed [14]. It's a lineage product: Block's Goose agent framework (Jan 2025) \u2192 Stacks, a Nostr template platform (May 2025) \u2192 the browser-native rebuild that became Shakespeare (Jul 2025), each step shedding a barrier (terminal, Node.js install) [22]. How It Works Everything \u2014 the AI agent loop, the TypeScript compiler, the git client, the file system \u2014 runs client-side. There is, per the repo's own README, \"no backend (except for a couple microservices in the services/ directory; these are fully configurable within Shakespeare's settings)\" [5]. Stack: React PWA frontend, IndexedDB/LightningFS for storage, isomorphic-git for version control, esbuild-wasm to compile TypeScript to a running React app \u2014 all in-tab [5]. Generated apps get MKStack's scaffolding: 50+ Nostr NIPs, ShadCN components, and Nostr-native primitives (profiles, DMs, zaps, Cashu wallets) available to the AI on request [6]. Full stack: React, not a generic static-site generator \u2014 MKStack is the template; the AI, called \"Dork\" in the underlying framework, decides what to wire up [9]. Confidence: High \u2014 architecture is corroborated across the README, the launch post, and Act 2. Cost Mechanics \u2014 The Free-Mockups Verdict Yes. You can generate close to unlimited client mockups at near-zero marginal cost \u2014 but the mechanism matters, because only one of four paths is genuinely \"free\" without caveats. The underlying model: Shakespeare doesn't sell AI capacity itself, it brokers access to independent Nostr Service Providers (NSPs) who set their own pricing (pay-per-use, subscription, or free tiers) and settle in USD or Bitcoin [11]. Path Who gets paid Marginal cost per mockup Catch Free Gemini Flash NSP Nobody \u2014 Soapbox-subsidized $0 \"We're currently offering a free Gemini Flash NSP so you can try Shakespeare without adding credits!\" [2] \u2014 promotional language, no published end date or usage cap found BYO API key, budget model (Z.ai GLM 4.5, etc.) Model provider, directly Cents GLM 4.5 is \"often 60\u201380% less expensive than Claude with comparable results\" [20]; Shakespeare \"takes no cut\" on BYOK [3] BYO API key, premium (Claude Sonnet 4.5) Model provider, directly ~$4/M prompt + $16/M completion tokens via the Shakespeare AI proxy [12] Best quality; still no Shakespeare markup Local model (Ollama, GPT-OSS, DeepSeek R1, Gemma 3) Nobody $0 after setup [17][20] Needs decent hardware; slower, lower ceiling than frontier cloud models Official paid NSP (MKStack + Claude Sonnet 4) Soapbox, via Stripe or Lightning Pay-per-use, rate not published The only path where it applies: \"Shakespeare only takes a cut if you use our paid NSP: MKStack + Claude Sonnet 4\" [13] There is no subscription anywhere in this picture \u2014 Shakespeare's own comparison page needles v0 for exactly the model you'd otherwise be locked into: \"Five monthly free credits, then subscription-based ($20-$100/mo)... No pay-as-you-go option\" [16]. Practical read: run free-tier or a cheap BYOK model for the volume mockup pass, reserve Sonnet 4.5 for the deal that's actually going to close. Confidence: High on the mechanism; Medium on \"free forever\" \u2014 the Gemini Flash tier is described as a current promotion, not a permanent commitment, so verify live before quoting a client $0. BYOK flag \u2014 UNRESOLVED (2026-07-10): the two \"BYO API key\" rows above could not be re-verified live this pass. Soapbox's own Shakespeare announcement post [2] \u2014 one of this table's own citations \u2014 was re-fetched and documents only NSP-marketplace payment (USD via Stripe or Bitcoin Lightning) plus the free Gemini Flash NSP; it does not mention a BYOK mechanism at all. Act 2 [3] does document \"BYOK providers\" as a real feature, so the capability itself is not in doubt \u2014 what's unresolved is the custody model: where a pasted API key is stored (browser-local, alongside the IndexedDB/LightningFS project data, versus sent to and held by a Shakespeare-operated server) is not stated in any source fetched. This does not overturn the rows above \u2014 they stay \u2014 but verify directly in-product (add a BYOK key, then check browser devtools > Application > IndexedDB/localStorage) before trusting a client's API key to it. Funnel Capability Matrix This is the section that needs the most caution. \"Add a contact form\" is a literal documented example prompt [1] \u2014 but Shakespeare has no conventional backend or database; Nostr's native data model is public, signed, relay-broadcast events, not a private leads table [5]. A generated form's UI will render; where its submissions land is not specified by Soapbox and depends entirely on what you prompt it to wire up. Funnel need Native? Mechanism Gap-fill if not native Landing page / mockup Yes Chat \u2192 React site, live preview [1][3] \u2014 Contact form (UI) Yes Documented prompt example [1] \u2014 Contact form (usable lead data) No (inferred) No default backend/DB; Nostr events are public, not a private CRM [5] Prompt it to fetch() a Formspree/Basin endpoint or a webhook Email list capture No Nostr has no email primitive Embed Beehiiv/ManyChat signup script \u2014 already in your stack Scheduling No Not Nostr-specific; nothing baked in Cal.com/Calendly iframe \u2014 trivial, it's a normal React page Bitcoin/Lightning payment Yes NIP-57 zaps, NIP-60 Cashu, NIP-61 nutzaps, NIP-47 wallet-connect ship in MKStack's 50+ NIPs [6]; Agora runs a live donation flow on this exact stack [24] \u2014 Credit-card payment (Stripe) No Not a Nostr primitive Stripe Checkout link or JS embed \u2014 doable, not one-click Analytics Not documented No mention in any primary source found Plausible/Fathom/GA script tag Verdict: the awareness layer (site, form UI, scheduling embed) and Bitcoin-native payment are genuinely one-prompt-away. The conversion/data layer for a mainstream (non-Nostr) small-business client \u2014 the part that actually makes a \"funnel\" \u2014 needs the same external services most funnels already run (Beehiiv, ManyChat, Cal.com, Stripe), stitched in by prompt rather than provided. Confidence: Medium \u2014 the gap is a structural inference from the architecture, not a Soapbox-stated limitation. Deployment Paths Runbook, as documented: build in chat \u2192 click deploy \u2192 live instantly at a *.shakespeare.wtf subdomain, \"no setup required and no configuration headaches\" [1]. Act 2's showcased projects confirm the pattern live: mi.shakespeare.wtf, linkbio.shakespeare.wtf [3]. For anything else \u2014 \"use our built-in, free, deployment service or export your complete project and deploy anywhere you choose\" [3] \u2014 via ZIP or a git push to GitHub/GitLab/custom, including nostr:// Git URLs for censorship-resistant backup needing no GitHub account [3][5]. The fully decentralized route (content-addressed on Blossom servers, pointer events on Nostr relays, resolvable via nsite:// or gateway domains \u2014 the same nsite spec used across the wider Nostr static-hosting ecosystem [27]) is documented for MKStack projects deployed via the Stacks CLI (npm run deploy \u2192 Blossom + relays \u2192 NostrDeploy.com) [7][9], not spelled out step-by-step for the browser Shakespeare export path specifically \u2014 treat as reachable with extra tooling, not a native one-click Shakespeare button. \u26a0 Tripwire (2026-07-10), cross-ref ch. 10: nostrdeploy.com does not resolve \u2014 a direct DNS check hit ENOTFOUND, which reads as dead-or-broken domain, not a server outage [28]. Both the NostrDeploy.com mention above and in the mermaid diagram are therefore unverifiable and possibly dead; don't promise this decentralized-deploy lane to a client or build a runbook on it until the domain resolves again. Ch. 10 carries the full tripwire detail, including the untested nuance that the underlying Blossom+relay substrate is content-addressed and may still work even if the NostrDeploy.com index/gateway itself is gone.  Stacks CLI provider-key storage \u2014 unknown, flag before wiring real keys (2026-07-10): ch. 10 documents stacks configure as where the Stacks CLI's model-provider keys (OpenRouter, Routstr, PayPerQ) get set, but where that command actually persists the key (plaintext config file, OS keychain, encrypted store) was not found in this pass \u2014 the term is search-drowned by the unrelated \"Stacks\" blockchain project, which floods generic web results. Before wiring a real client-facing provider key through the Stacks CLI lane, run stacks configure and inspect its output/config file directly rather than assuming a security posture. Confidence: High for the *.shakespeare.wtf free path and the 8-target export list (corroborated across two independent Soapbox comparison posts [16][17]). Medium for custom-domain mechanics on either path \u2014 working examples exist (espy.you) but no published runbook was found. Code Ownership & Export Two licenses are in play and they answer different questions: What License Source The Shakespeare tool itself (if you fork/self-host it) AGPLv3 \"Fully auditable codebase under AGPL 3.0 license\" [2][5] Code Shakespeare generates for your project No license imposed (inferred) Soapbox's own comparison: unlike Replit, which \"automatically licenses apps with MIT,\" Shakespeare's code \"stored in browser \u2014 Soapbox has no control over it\" [17] That second row is the load-bearing fact for an agency workflow: there is no platform to be banned from. Soapbox's contrast: a Replit ban deletes your account and \"all Replit App will have been deleted\"; Shakespeare's code lives in your browser's IndexedDB from the start, so \"prevents account bans\" really means \"no account to ban\" [17]. Export is one click to a ZIP or a full-history git push \u2014 no lock-in step exists to remove [3][5]. Confidence: High for the tool's own AGPLv3 status (confirmed on the repo). Medium-High for \"no license on generated output\" \u2014 strongly implied by the architecture and Soapbox's own competitor framing, but never stated as a standalone legal claim. Limits & Workflow Iteration is chat-native, not context-free. Shakespeare's own debugging guide flags \"context overload: the conversation has become so long that each prompt is expensive\" as the signal to start a fresh chat rather than keep pushing [19]. Debugging is a 4-step protocol Soapbox documents explicitly: gather evidence \u2192 isolate the problem \u2192 provide context \u2192 test systematically with rollback available, closing with \"start with evidence, not assumptions\" [19]. Model choice is the real cost/quality lever, not a plan tier: \"If you choose a cheap model, you can expect cheap results\" [19][20]. Version control is built in, framed as \"a time machine for your code\" \u2014 one-click rollback via a three-dot menu, or raw git commands in the in-browser terminal for power users [21]. Editing an existing (including imported) site is supported \u2014 Shakespeare can import external projects, not just greenfield-generate [18]. No multiplayer/live-collab feature was found anywhere in the primary sources (community, Act 2, or resources pages) \u2014 the \"Shakespeare Community\" is a Nostr-based chat/forum for builders to swap tips, not in-project co-editing [4]. Confidence: High \u2014 sourced from Soapbox's own guides, not marketing copy. Agency Comparison Shakespeare Lovable Bolt.new v0 (Vercel) Webflow Framer Client mockups, cost BYOK/free-tier/local \u2192 effectively $0\u2013cents [2][3] Free tier + paid plans (subscription) Free tier + paid plans (subscription) 5 free credits, then $20\u2013$100/mo, no pay-as-you-go [16] Free-to-build, paid to publish/subscribe Free-to-build, paid to publish/subscribe Production backend Nostr events/relays; no managed DB out of the box, though Shakespeare claims support for \"backend frameworks like databases, containerization\" [16] Managed Supabase DB, one prompt away Multi-framework, backend via integrations \"Front-end only. No backends, no databases\" \u2014 Shakespeare's own characterization [16] CMS + hosting, no custom app logic Marketing sites; limited app logic Ownership / lock-in Local-first, no imposed license, no account to ban [5][17] Code not Vercel/Lovable-owned, but lives on their platform Platform-hosted by default Vercel \"collects your source code, billing info... and location data,\" \"can't delete your own data\" \u2014 per Shakespeare's framing [16] Platform-locked (hosted CMS) Platform-locked Payments baked in Bitcoin/Lightning/Cashu (NIP-57/60/61/47) native [6]; card payments need manual wiring One-click Stripe pattern Manual wiring Manual wiring Native e-commerce Forms native; commerce via add-ons Templates / visual editor None \u2014 chat-only Chat-only, growing gallery Chat-only Chat-only Deep editor + template marketplace Deep editor, design-forward templates Non-technical handoff Needs re-prompting or hand-edits; no CMS Similar chat-only friction Similar Similar Best-in-class for marketers Best-in-class for marketers Track record ~1 year old (launched Jul 2025) [2][10] Longer, larger base Longer, larger base Vercel-backed, mature Decade+, mature Mature, design-standard Where Shakespeare wins: true pay-per-use with no subscription tax, real code ownership with no ban risk, native Bitcoin/Lightning rails, export to 8+ hosts instead of one [16][17]. Where it loses: no visual/drag-and-drop editor, no managed database or one-click Stripe/CRM the way Lovable ships it, no template marketplace, younger track record \u2014 plus a client-comfort tax: \"log in with a Nostr key\" and \"your data lives on relays\" are unfamiliar to a small-business client used to plain email/password SaaS. Confidence: Medium \u2014 Shakespeare's claims about itself and about v0/Replit are primary-sourced [16][17]; the Lovable/Webflow/Framer cells reflect general market knowledge, not a fresh fetch of those vendors' own pricing/docs this pass. Integration Points Connects to Mechanism Enables MKStack Shakespeare is the browser front-end to MKStack's template + 50+ NIPs [1][6] Every Nostr-native primitive (profiles, zaps, Cashu, DMs) available on request Agora (built with Shakespeare+MKStack at an HRF hackathon) Reference implementation, not an embeddable widget Proof a live Lightning-donation/crowdfunding flow works in production on this stack [24][25] Ditto Separate product (Nostr community server, self-hostable or ditto.pub) [23] Pairing pattern: Shakespeare = funnel/marketing site; Ditto = retained community/membership layer post-conversion \u2014 a two-product package, not a plug-in NostrHub Discovery/publishing hub for Nostr apps, NIPs, repos [26] Distribution channel for your own templates/portfolio in the Nostr dev ecosystem \u2014 minor to client funnels directly Beehiiv / ManyChat (common funnel-stack tools) Embed signup script or webhook into generated site Real email capture \u2014 the piece Nostr doesn't natively provide Cal.com / Calendly iframe/embed, no Nostr dependency Scheduling step in a funnel \u2014 trivial since output is a normal React page Stripe JS SDK or Checkout link, manually prompted Credit-card conversion step for non-Bitcoin clients Git hosts (GitHub/GitLab/custom) + Nostr Git Native git integration, incl. nostr:// remote [3][5] Backup/handoff independent of any single platform Confidence: Medium \u2014 product relationships are documented; the specific \"how to combine these for an agency package\" framing is this chapter's synthesis, not a Soapbox-stated playbook. Open Questions Whether the free Gemini Flash NSP is still active today (2026-07-09) and whether it carries a rate limit or usage cap \u2014 described in launch copy as a current promotion, not a permanent commitment, and no post after Dec 2025 was found confirming its status [2]. The exact DNS/runbook steps for attaching a fully custom domain (either to *.shakespeare.wtf or to an nsite/Blossom deployment) \u2014 working examples exist (espy.you) but no step-by-step was found [3]. Whether a contact-form submission can be routed to a private Nostr DM (NIP-17) to the site owner as a semi-native lead-capture path, versus requiring an external HTTP service \u2014 plausible given MKStack's NIP coverage, but not demonstrated in any source fetched. Whether analytics of any kind (even privacy-respecting/Nostr-native) exists or is roadmapped \u2014 zero mentions found across marketing pages, blog, and FAQ listing. Current product state beyond the last confirmed changelog entry (Dec 16, 2025, \"AI-First Development on Mobile\") \u2014 seven months of potential unlogged change between then and today; verify live before any client-facing commitment [15]. Where a BYOK key is actually stored (browser-local vs. Shakespeare-operated server) \u2014 see the BYOK flag in Cost Mechanics, above; unresolved as of this pass, inspect in-product before trusting a client's key to it. Where the Stacks CLI persists a provider key set via stacks configure \u2014 see the Deployment Paths tripwire, above; unresolved, search-drowned by the unrelated Stacks-blockchain project. Sources Shakespeare \u2014 Open Source AI Website Builder \u2014 product marketing page: pricing claims, provider list, deployment/export claims. Accessed 2026-07-09. Introducing Shakespeare: AI-Powered Website Builder on Nostr \u2014 launch post (2025-07-10): what it is, NSP payment model, free Gemini Flash tier, AGPLv3 license. Accessed 2026-07-09; re-fetched 2026-07-10 \u2014 confirms no BYOK mechanism is mentioned in this post (see the BYOK flag in Cost Mechanics). Shakespeare: Act 2 \u2014 Build Freely \u2014 2025-10-01 update: local storage (IndexedDB/LightningFS), BYOK providers, git integration incl. nostr://, free deploy service, example live subdomains. Accessed 2026-07-09. Announcing the Shakespeare Community \u2014 community structure, channels, no multiplayer/payment features mentioned. Accessed 2026-07-09. gitlab.com/soapbox-pub/shakespeare and raw README \u2014 tech stack (React PWA, IndexedDB+LightningFS, isomorphic-git, esbuild-wasm), \"no backend\" claim, AGPLv3 license. Accessed 2026-07-09. MKStack \u2014 AI-Powered Nostr App Framework \u2014 50+ NIPs list incl. payments (NIP-57/60/61/47), React/TypeScript stack, NostrDeploy.com integration. Accessed 2026-07-09. Stacks \u2014 AI-First Development Platform \u2014 Docker-based template platform, stack.json/agent.json/CONTEXT.md, NostrDeploy.com deploy workflow, Dork AI agent providers. Accessed 2026-07-09. Soapbox Toolbox \u2014 full tool inventory used to map integration points (Ditto Relay, Nostrify, NostrHub, Relay Kit, etc.). Accessed 2026-07-09. MKStack: Vibe Coding for Everyone \u2014 step-by-step Dork generation pipeline, npm run dev/npm run deploy, cost caution (\"this gets expensive\"). Accessed 2026-07-09. Shakespeare Launches as Open Source Competitor to AI-site builders \u2014 PR Newswire \u2014 launch date/venue, Alex Gleason quote. Accessed 2026-07-09. Understanding Nostr Service Providers (NSPs) \u2014 NSP payment structure (pay-per-use, subscription, free tiers), how to pick one. Accessed 2026-07-09. ai.shakespeare.diy \u2014 OpenAI-compatible API with NIP-98 auth; GLM-4.5 and Claude Sonnet 4.5 per-token pricing. Accessed 2026-07-09. Shakespeare \u2014 Product Hunt \u2014 maker comments, \"Shakespeare only takes a cut if you use our paid NSP\" quote, user feedback. Accessed 2026-07-09. Inside Soapbox's push to keep AI open for everyone \u2014 TechCabal \u2014 Gleason's origin motivation quote, \"trust-based\" business framing, no revenue/funding disclosed. Accessed 2026-07-09. Soapbox Blog index \u2014 full Shakespeare-related post list with dates, used to establish most-recent-confirmed-update timeline (through 2025-12-16). Accessed 2026-07-09. Shakespeare vs. v0 by Vercel \u2014 official feature/pricing comparison table (Soapbox's own framing). Accessed 2026-07-09. Shakespeare vs. Replit \u2014 official comparison incl. ban/ownership contrast, deployment target list. Accessed 2026-07-09. Shakespeare Resources \u2014 FAQ & Guides \u2014 guide index (importing projects, editing code, deploying, version control, debugging, prompting) with dates; FAQ question titles (answer text not rendered). Accessed 2026-07-09. Debugging in Shakespeare \u2014 4-step debug protocol, context-overload guidance, cost-effective prompting tips. Accessed 2026-07-09. Which AI Model Should I Use with Shakespeare? \u2014 model recommendations by budget, GLM 4.5 vs Claude cost comparison, local-model framing. Accessed 2026-07-09. Using Version Control in Shakespeare \u2014 rollback UI, GitHub/GitLab sync workflow, terminal git access, Nostr git backup. Accessed 2026-07-09. The Shakespeare Origin Story \u2014 Goose \u2192 Stacks \u2192 Shakespeare evolution narrative. Accessed 2026-07-09. Ditto \u2014 Your Content. Your Vibe. Your Rules. and github.com/soapbox-pub/ditto \u2014 Ditto product description, self-host/hosted options. Accessed 2026-07-09. Agora: Connecting Freedom Fighters to Uncensorable International Support \u2014 Agora product description, Bitcoin/Lightning support flow. Accessed 2026-07-09. Building Agora: From Hackathon to Real-World Activism \u2014 confirms Agora built with MKStack and Shakespeare at an HRF hackathon. Accessed 2026-07-09. gitlab.com/soapbox-pub/nostrhub and NostrHub \u2014 protocol/app discovery hub description. Accessed 2026-07-09. Web search summaries on the nsite spec (github.com/lez/nsite, nsite.info) \u2014 static-site-on-Nostr mechanics (Blossom storage + relay pointer events); community/protocol-level source, not Soapbox-authored, used only to explain the decentralized deploy path's underlying spec. Accessed 2026-07-09. nostrdeploy.com \u2014 direct DNS resolution check: ENOTFOUND, domain does not resolve. Checked 2026-07-10; cross-ref this manual's ch. 10 \u2014 MKStack, source [26], which ran the same check the same day."
    },
    {
      "id": "manual/05-nostrhub",
      "kind": "manual",
      "lang": "en",
      "title": "NostrHub \u2014 Soapbox's Developer Hub for NIPs, Apps, and Repos",
      "url": "/manual/#ch05",
      "md_url": "/manual/md/05-nostrhub.md",
      "sha256": "268d011e27f037c55490e005b331b38912154533f0c9d145233edddaefab5f87",
      "bytes": 27172,
      "headings": [
        "What It Is",
        "Feature Map",
        "Signing In With Your Nostr Credentials",
        "First-login runbook",
        "Publishing Workflows",
        "Governance Model",
        "Distribution & Discovery Value",
        "Stack Relations",
        "Operating Model & Self-Hosting",
        "Comparison",
        "Integration Points",
        "Addendum (2026-07-10): The Existing MCP / Agent Surface \u2014 and the Empty Slot",
        "Open Questions",
        "Sources"
      ],
      "body": "A Nostr-native site (nostrhub.io) where developers browse and propose protocol specs (NIPs), list apps, host git repos over Nostr, and discuss all three \u2014 ranked not by a company or a vote but by a \"configurable meritocracy\" of experts each visitor picks themselves. Verified: 2026-07-09 \u00b7 Delta pass: 2026-07-10 (repo velocity, rating-scale reconfirm, contribution-program check, MCP/agent-surface addendum) Confidence overview: High for feature inventory, NIP kind numbers, and the login flow (source-code-verified against the live GitLab repo). High for the governance model's mechanics and quotes (primary blog post, fetched directly). Medium for distribution/audience size and cross-tool integration with Shakespeare/Ditto (no hard numbers or explicit docs found \u2014 flagged in Open Questions). Low for anything about the DVM marketplace's current (2.0-era) status. What It Is \"It's not a democracy. It's not a dictatorship. It's a meritocracy you configure yourself.\" [3] NostrHub is built by Soapbox (founder Alex Gleason) and has shipped twice. v1 launched June 10, 2025 as \"the ultimate resource for Nostr developers\" \u2014 NIPs, apps, repos, comments [1]. It got overrun by spam [3]. NostrHub 2.0 \u2014 a from-scratch rewrite (the GitLab repo was recreated June 11, 2026 [4]) \u2014 was announced June 28, 2026, eleven days before this was verified [3]. Everything below describes 2.0 unless marked v1-only. Framed against its own inspiration: \"We started by trying to escape GitHub's oligarchy over the NIPs. We ended up rebuilding the good parts of GitHub itself... on a substrate nobody owns, governed by a meritocracy you control.\" [3] Feature Map Surface What it is Underlying Nostr mechanism Confidence NIPs explorer Official nostr-protocol/nips + community-submitted custom NIPs, comment threads on each Custom NIPs published as kind 30023 long-form articles [3][16]; official NIPs mirrored for browsing High Browse-by-kind Pages like /kind/30023/ list every NIP touching a given event kind Derived index over NIP content Medium (URL pattern confirmed via search index [24], not directly fetched) App directory Apps listed/discovered by event kinds they support; 4-tier ProtonDB-style quality scale \u2014 Flawless / Incomplete / Isolated / Borked \u2014 each rating an ordinary portable Nostr event, not a NostrHub-locked score (reconfirmed 2026-07-10) NIP-89 kind 31990 handler-info events + kind 31989 recommendations [3][13] High Git repos Create in-browser or mirror a GitHub repo; GitHub-style issues/PRs/file browser NIP-34: kind 30617 announce, 1617 patch, 1618/1619 PR, 1621 issue, pushed to a GRASP host [3][12][18] High Comments Every NIP/app/repo has a decentralized comment thread Nostr reply events High [1] Community chat Built-in dev community + AI agent, \"loosely inspired by Block's Sprout/Buzz,\" explicitly experimental NIP-72 community space [1][3] Medium Plan Graph Constellation-style map of ecosystem goals/problems/people; author calls it unsatisfying, still iterating Custom, experimental Medium Profiles Every dev's profile aggregates their published NIPs/apps/repos as a reputation signal Standard Nostr profile + NostrHub-side aggregation Medium DVM marketplace (beta) AI-powered Data Vending Machines \u2014 translation, image generation, on-demand compute NIP-90 [1] Low \u2014 was live in v1 [1]; not mentioned once in the 2.0 announcement [3] \u2014 status unconfirmed Signing In With Your Nostr Credentials Since you already hold a keypair, this is the load-bearing question. NostrHub's actual login component (AuthDialog.tsx, QuickLoginDialog.tsx \u2014 read directly from the GitLab repo [8][9]) offers four paths. Ranked by safety: Method How it works Where your key lives Safety Confirmed on NostrHub Browser extension (NIP-07) \u2014 Alby, nos2x Extension exposes window.nostr; site asks it to sign, never sees the key In the extension's own storage Safest \u2014 use this Yes \u2014 default path. If an extension is detected, QuickLoginDialog shows one \"Log in\" button that calls login.extension() [9] Remote signer / bunker (NIP-46) \u2014 nsec.app, Amber, etc. Paste a bunker://\u2026 URI, or click \"Open signer app\" to hand off via nostrconnect:// On your phone or bunker service, never touches NostrHub's browser tab Safe Yes \u2014 under \"Other ways to log in\" in AuthDialog [8] Key file upload Upload a .txt file containing your nsec Briefly loaded into NostrHub's JS runtime Risky Yes \u2014 explicit menu option [8] Paste nsec directly Type/paste nsec1\u2026 into a password-style field Touches NostrHub's JS runtime the moment you paste it Risky \u2014 avoid for your real key Yes, no extra confirmation step shown at paste time [8] No confirmation dialog gates the nsec-paste path beyond a generic warning shown only during new-key generation (\"This key is your only way to access your account. If you lose it, you lose the account.\") [8] \u2014 that warning is about loss, not about the security cost of pasting an existing key into a website. Treat the paste/upload options as absent for your primary identity. First-login runbook Confirm your existing nsec is already imported into a NIP-07 extension (Alby or nos2x), or have a bunker ready (nsec.app, Amber). Visit nostrhub.io. If the extension is detected, you'll see a \"Welcome back\" dialog with a single Log in button. Click it \u2014 the extension prompts you to approve getPublicKey/signEvent; your key never leaves the extension [9]. No extension active? Click \"Other ways to log in\" \u2192 paste your bunker://\u2026 URI, or click \"Open signer app\" to connect a mobile signer via nostrconnect:// [8]. Do not use the nsec-paste or file-upload option for your primary key. If you ever need to smoke-test something disposable, use a burner key there instead. Publishing Workflows All three content types share one shape \u2014 compose, sign, publish to a relay (or GRASP host for repos), NostrHub indexes the event: (a) Publish/announce a git repo Choose \"New repo\" or \"Mirror from GitHub\" (paste a GitHub URL to import history) [3]. NostrHub composes a kind 30617 repository-announcement event (name, description, clone URL, relay list, maintainers) and asks your signer to sign it [12]. The signed event, plus the repo data, is pushed to a GRASP server \u2014 \"a relay that doubles as a git host\" [3][18]. You get a GitHub-style page: issues (kind 1621), PRs (1618/1619), patches (1617), file browser \u2014 \"except there's no GitHub underneath\" [3]. \"Claiming\"/updating = publish a new 30617 (it's replaceable, keyed by its d tag) or a 30618 state event for branch/tag updates [12]. (b) List an app Publish a kind 31990 handler-information event: which event kinds your app supports (k tags), per-platform URLs [13]. No submission queue or approval gate \u2014 self-announced. NostrHub's directory just indexes 31990/31989 events by kind [3][13]. Community attaches ProtonDB-style ratings and comments; ratings are ordinary Nostr events, portable to any client that reads them, not locked to NostrHub [3]. (c) Propose/discuss a NIP (long-form) Write the proposal in Markdown, publish as a kind 30023 long-form article (same event kind NIP-23 defines for blog posts), with title/summary/d tags [16][3]. It appears under \"custom NIPs\" with a comment thread [1][3]. Anyone in your configured expert set can attach a NIP-32 label event (kind 1985) approving it [3][17]. Enough of your experts' approvals move it toward \"official\" \u2014 for you specifically. There is no single global official flag; ranking is computed per viewer from their own expert list [3]. Governance Model Confidence: High \u2014 this section is built almost entirely from direct quotes in the 2.0 announcement [3]. Ships with a default expert list: \"fiatjaf, hodlbod, Vitor Pamplona, PABLOF7z, jb55, Kieran, mattn, and the rest.\" [3] Users can add or remove experts from any profile; experts display a shield badge [3]. Approvals are ordinary NIP-32 label events (kind 1985) attached to a NIP's kind-30023 article [3][17] \u2014 not a database flag, not a merge commit. History, in the founder's own words: \"That first NostrHub got covered in spam. Then ManiMe added web-of-trust scoring to it, which improved the quality, but it was still missing a way for a NIP to become 'official.'\" [3] Spam control: your combined experts' follow-lists cap the visible community (reported default ~1,000 people, configurable) \u2014 \"This is what kills the spam that drowned NostrHub 1.0.\" [3] vs. github.com/nostr-protocol/nips: the canonical NIPs repo runs on ordinary git-maintainer authority \u2014 a small set of people (fiatjaf among them) merge pull requests, and \"official\" means \"merged.\" NostrHub inverts that: anyone can publish a NIP-shaped event, nothing is ever merged or rejected centrally, and \"official\" is a number that recomputes per visitor depending on whose approvals they've chosen to weight. It's a discovery/ranking layer next to the git repo, not a replacement governance body for the protocol itself \u2014 the canonical spec-acceptance process still runs on GitHub. Distribution & Discovery Value Confidence: Medium \u2014 no traffic/audience figures were found for nostrhub.io in any source checked; treat the following as qualitative, not a growth metric. NostrHub sits inside Soapbox's own \"Toolbox\" page alongside Shakespeare, MKStack, Ditto, and Nostrify [19] \u2014 its built-in audience is Soapbox's existing Nostr-developer readership, not a separate acquisition channel. Because every listing is an ordinary Nostr event, discovery is protocol-native in principle: any NIP-89-aware client can in theory surface the same kind 31990 handler event NostrHub indexes [13]. In practice, propagation is not automatic \u2014 Zapstore (Android APK store) and nostrapps.com run their own separate catalogs, and this research did not confirm they consume NostrHub's specific events [22]. A repo announced on NostrHub, by contrast, interoperates cleanly with other NIP-34 clients out of the box, because they all read the same kind 30617 event \u2014 confirmed by NostrHub's own repo being independently browsable on the competing client gitworkshop.dev [21]. Stack Relations Tool Confirmed relation to NostrHub Confidence MKStack NostrHub 2.0's own package.json is literally named \"mkstack\", and it imports @nostrify/nostrify + @nostrify/react \u2014 Soapbox scaffolded its own flagship dev-hub with its own AI app-builder template [10] High (source-verified) Nostrify The underlying protocol/client framework NostrHub runs on [10][19] High Nostrbook Sister tool: docs + MCP server for Nostr kinds/tags, aimed at AI agents rather than NostrHub's human-facing NIP explorer [19]; nostrbook.dev live-verified 2026-07-10 [25] High for existence/purpose (live-checked); still no direct code link to NostrHub \u2014 see the MCP/agent addendum below Shakespeare Soapbox's AI website builder Not confirmed \u2014 no evidence found that Shakespeare deploys to or reads from NostrHub specifically Ditto Soapbox's community-server product; \"Ditto Relay\" is marketed as \"the relay infrastructure powering Ditto\" [19], not stated to also power NostrHub Not confirmed Toybox \u2014 Not found in any source during this research Operating Model & Self-Hosting Repo: gitlab.com/soapbox-pub/nostrhub \u2014 public, re-created 2026-06-11 (the 2.0 rewrite), last activity 2026-07-07 [4]. Velocity re-checked 2026-07-10: 866 commits in the 29 days since the rebuild \u2014 roughly 30/day sustained, hotter than even Armada's ~18/day (ch. 01) [26]. This is Soapbox's most actively poured foundation right now, not a parked launch. License: not declared in the GitLab project's own metadata at time of check (empty license field) [4], despite the README's \"open source\" framing [5]. Don't assume a specific OSS license without checking again. Cost: no pricing or paid tier found on the blog, product page, or repo \u2014 free to use. Community program: none. The full soapbox.pub blog index (60 posts, checked 2026-07-10) contains no bounty, contest, or call-for-contributions post [27]. Engagement with this ecosystem is artifact-first \u2014 you ship events, repos, or skills into it (see the addendum below); there is no formal program to apply to. Self-hosting: architecturally plausible \u2014 public Vite/React/TypeScript repo, .env.example present (currently just a Plausible-analytics domain toggle) [11] \u2014 but no explicit self-hosting guide was found. Inferred, not documented. Relay operator: not conclusively identified. NostrHub is a client over whatever relays are configured per-event (each repo's own relays tag; GRASP hosts for git specifically [18]) \u2014 no evidence ties it to Soapbox's own Ditto Relay. Comparison NostrHub GitHub npm Product Hunt gitworkshop.dev Primary unit NIPs + apps + repos + community Code repos JS packages Product launches Git repos (NIP-34 only) Hosting Metadata layer over relays + GRASP git hosts Centralized (Microsoft) Centralized registry Centralized Same NIP-34/GRASP substrate as NostrHub Discovery Kind-indexed browse + per-viewer expert ranking Stars, search, trending Search, download counts Daily upvote leaderboard Repos feed, npub browsing Governance Configurable meritocracy, per-viewer [3] Corporate ToS + maintainer merge rights npm Inc. (GitHub-owned), single registry Company-run No formal layer \u2014 \"first implementation of the NIP-34 draft\" [20] Distribution None \u2014 metadata/discovery only, no artifact hosting Releases, Packages, Actions Package artifacts themselves One-day traffic spike, not ongoing reference None \u2014 same scope limit as NostrHub The gap worth flagging for any agent-tooling/package-distribution use case: NostrHub has no package-registry equivalent. Listing an app publishes metadata (a handler event), not a binary or a build artifact \u2014 you still need somewhere else (Shakespeare's own deploy target, a normal host, or Zapstore for Android) to actually distribute the thing. Integration Points Connects to Mechanism Enables Any NIP-07 extension (Alby, nos2x) window.nostr (NIP-07) [14] Safe sign-in, key never leaves the extension Any NIP-46 bunker (nsec.app, Amber) bunker://\u2026, nostrconnect://\u2026 (NIP-46) [15] Remote signing, key never touches NostrHub's runtime Any Nostr relay WebSocket relay protocol Where every NIP/app/repo/comment event actually lives \u2014 NostrHub is a lens over relays, not a silo Any NIP-34 git client (gitworkshop.dev, ngit CLI, gittr) Shared kind 30617/1617/1618/1621 events [12] A repo announced on NostrHub is clonable/browsable elsewhere without republishing \u2014 verified: NostrHub's own repo shows up on gitworkshop.dev [21] Any NIP-89-aware client kind 31989/31990 handler events [13] An app listed on NostrHub is discoverable by other NIP-89-respecting clients in principle \u2014 not the same catalog as Zapstore's Android store GRASP git host (ngit-relay, gitnostr.com, etc.) GRASP \u2014 \"Git Relays Authorized via Signed-Nostr Proofs\" [18] Actual git object storage + signed-push authorization behind a NostrHub-created repo Soapbox's MKStack scaffold Shared codebase lineage \u2014 package.json name \"mkstack\", @nostrify/* deps [10] NostrHub is itself proof that an MKStack-built app is production-viable at Soapbox's own flagship-tool scale Addendum (2026-07-10): The Existing MCP / Agent Surface \u2014 and the Empty Slot Delta pass, one day after the chapter's main verification. Confidence: High \u2014 each surface below was checked live on 2026-07-10. Surface What it is Posture toward outside contributors nostrbook.dev Docs site plus MCP server for NIP/kind/tag documentation \u2014 an agent queries protocol docs over MCP [25] Read-only reference; ch. 01 inventories it, live-confirmed this pass soapbox-pub/nostr-skills (GitHub) Claude/agent skill files for Nostr development, CC-BY-SA-4.0 [28] Explicitly invites community contributions \u2014 the one explicit, standing invitation to outsiders found this pass soapbox-pub/openclaw-skills (GitHub) Companion skills repo for OpenClaw agents (OpenClaw itself is independent, not a Soapbox product \u2014 ch. 02) [29] Same CC-BY-SA-4.0 skills family (ch. 01's license table already groups them) The split that matters: everything above reads; nothing acts. Nostrbook serves docs to agents; the skills repos teach agents conventions. No MCP server was found \u2014 from Soapbox or anyone else \u2014 that performs NostrHub's actual verbs for an agent: publish a kind 31990 handler announcement (NIP-89 app listing), push to a kind 30617 repo (NIP-34), or attach a kind 1985 quality rating (NIP-32). That niche came back empty across every surface checked this pass \u2014 Soapbox's repo inventory, the toolbox, the 60-post blog index, and both skills repos [25][26][27][28]. INFERRED, practical read: this is the highest-leverage contribution slot this manual has surfaced. The event kinds are fully documented (this chapter + ch. 06); MKStack already ships a nostr MCP server for building apps (ch. 10) but nothing for publishing into the hub; and the skills repos prove Soapbox welcomes agent-tooling contributions and even name the content-license norm (CC-BY-SA-4.0 \u2014 code licensing is murkier, ch. 10). An \"acting\" NostrHub MCP server would make every flow in Publishing Workflows above scriptable by any MCP-capable agent \u2014 and since no bounty or contest program exists to enter (Operating Model above), shipping exactly this kind of artifact is the engagement mechanism. Open Questions Is the DVM marketplace (beta, present in the June 2025 v1 [1]) still live in the June 2026 2.0 rewrite? Not mentioned once in the 2.0 announcement [3]; nostrhub.io is a client-rendered SPA that direct fetches can't confirm either way. Exact default \"expert\" count: one summarized source said \"12\"; the primary blog quote itself names seven and trails off with \"and the rest\" [3] \u2014 precise number unresolved. No OSS license file was confirmed despite repeated \"open source\" framing in Soapbox's own copy [4][5]. No hard traffic or registered-developer figures found for nostrhub.io anywhere in this pass. Whether Shakespeare or Ditto integrate with NostrHub beyond sharing a Toolbox page \u2014 not found. NostrHub's own default/hardcoded relay set (beyond per-event relay tags) \u2014 not found in accessible config. Whether Zapstore's app-listing event kind is the same NIP-89 kind 31990 NostrHub indexes, or a separate proprietary kind \u2014 Zapstore's own NIP doc page 404'd during this research; unconfirmed. Sources soapbox.pub/blog/announcing-nostrhub/ \u2014 \"NostrHub: NIPs, Apps, and Repos on Nostr,\" June 10, 2025. Accessed 2026-07-09. Supports: v1 feature set, DVM marketplace (beta), NIP-72 community space. soapbox.pub/tools/nostrhub/ \u2014 Product page. Accessed 2026-07-09. Supports: tagline, feature list, profile/reputation framing. soapbox.pub/blog/nostrhub-2 \u2014 \"NostrHub 2.0: A Meritocracy for Building Nostr Together,\" Alex Gleason, June 28, 2026. Accessed 2026-07-09. Supports: governance model (all verbatim quotes), Plan Graph, GRASP publishing flow, GitHub comparison, spam history. gitlab.com/soapbox-pub/nostrhub + GitLab API project metadata. Accessed 2026-07-09. Supports: repo creation date (2026-06-11), last activity (2026-07-07), empty license field. gitlab.com/soapbox-pub/nostrhub/-/raw/main/README.md \u2014 Accessed 2026-07-09. Supports: \"configurable meritocracy\" framing, tech stack, \"NostrHub doesn't tell you what's true...\" quote. GitLab API repository tree, src/components/auth/ listing. Accessed 2026-07-09. Supports: existence of AccountSwitcher.tsx, AuthDialog.tsx, LoginArea.tsx, QuickLoginDialog.tsx. GitLab API repository tree, root and src/ listings. Accessed 2026-07-09. Supports: React/Vite/TypeScript project shape. AuthDialog.tsx source, via GitLab raw API. Accessed 2026-07-09. Supports: nsec paste, bunker URI, key-file upload, new-account generation flow, exact UI copy/warnings. QuickLoginDialog.tsx source, via GitLab raw API. Accessed 2026-07-09. Supports: extension-first \"Welcome back\" login flow, login.extension(). package.json, via GitLab raw API. Accessed 2026-07-09. Supports: project named \"mkstack\", @nostrify/nostrify, @nostrify/react, nostr-tools, isomorphic-git dependencies. .env.example, via GitLab raw API. Accessed 2026-07-09. Supports: Plausible Analytics config, no default relay found in this file. NIP-34 \u2014 git stuff. Accessed 2026-07-09. Supports: kind 30617/30618/1617/1618/1619/1621/1630-1633 definitions, tag structures, clone-URL format. NIP-89 \u2014 Recommended Application Handlers. Accessed 2026-07-09. Supports: kind 31989/31990 definitions, k/d/a tags, discovery workflow. NIP-07 \u2014 window.nostr capability. Accessed 2026-07-09. Supports: extension signing model, getPublicKey/signEvent. NIP-46 \u2014 Nostr Connect / remote signing. Accessed 2026-07-09. Supports: bunker/client roles, bunker:///nostrconnect:// URI formats, kind 24133. NIP-23 \u2014 Long-form Content and [nostrhub.io/kind/30023/ search index result]. Accessed 2026-07-09. Supports: kind 30023 definition; NostrHub's use of it for custom NIPs. NIP-32 \u2014 Labeling (via search index). Accessed 2026-07-09. Supports: kind 1985, l/L tags, distributed-moderation use case. ngit.dev/grasp/ \u2014 \"Grasp: Git Repositories Authorized via Signed-Nostr Proofs.\" Accessed 2026-07-09. Supports: GRASP definition, two-service model (Smart HTTP Git + Nostr relay), implementations (ngit-relay, gitnostr.com). soapbox.pub/toolbox. Accessed 2026-07-09. Supports: full Soapbox tool list, one-line descriptions, Ditto Relay/NostrHub/Nostrbook positioning. gitworkshop.dev and gitworkshop.dev/about (via search index). Accessed 2026-07-09. Supports: gitworkshop.dev's own description as \"Decentralized Git,\" first NIP-34 draft implementation, pairing with ngit. gitworkshop.dev/alex@gleasonator.dev/nostrhub. Accessed 2026-07-09. Supports: NostrHub's own repo is independently browsable via a competing NIP-34 client, confirming cross-client interoperability. zapstore.dev and github.com/zapstore/zapstore (via search index). Accessed 2026-07-09. Supports: Zapstore's separate Android-APK-focused catalog model. Note: zapstore.dev/docs/nips/app/ returned HTTP 404 during this research \u2014 exact event-kind overlap with NIP-89 unconfirmed. nostrhub.io \u2014 direct fetch. Accessed 2026-07-09. Supports: tagline only (\"Build Nostr Together\") \u2014 site is a client-rendered SPA, body content not retrievable via direct fetch. Search-engine index results for site:nostrhub.io (Google/Bing snippets covering /apps/, /01/, /kind/30023/, /EE). Accessed 2026-07-09. Supports: existence and URL patterns of the browse-by-kind and per-NIP page structure, used because the live SPA could not be fetched directly. nostrbook.dev \u2014 direct fetch. Accessed 2026-07-10. Supports: Nostrbook live as a docs site + MCP server for NIP/kind/tag documentation; a read surface only \u2014 no publish/act capability found. GitLab API project metadata re-check for soapbox-pub/nostrhub. Accessed 2026-07-10. Supports: 866 commits in the 29 days since the 2026-06-11 recreation. soapbox.pub/blog \u2014 full post index, 60 posts. Accessed 2026-07-10. Supports: no bounty, contest, or call-for-contributions program anywhere in the blog's history; no announcement of a NostrHub-acting MCP server. github.com/soapbox-pub/nostr-skills \u2014 Accessed 2026-07-10. Supports: Claude/agent skills for Nostr development, CC-BY-SA-4.0, README explicitly inviting community contributions. github.com/soapbox-pub/openclaw-skills \u2014 Accessed 2026-07-10. Supports: companion OpenClaw agent-skills repo in the same CC-BY-SA-4.0 skills family."
    },
    {
      "id": "manual/06-nostr-foundations",
      "kind": "manual",
      "lang": "en",
      "title": "06 \u2014 Nostr Foundations for Operators",
      "url": "/manual/#ch06",
      "md_url": "/manual/md/06-nostr-foundations.md",
      "sha256": "5cde353e7680f28643715861694fc3dcca1c0182bb1d00c87caa83e8cfc837a1",
      "bytes": 53204,
      "headings": [
        "1. Identity & Keys for a Company",
        "Key custody decision tree",
        "NIP-07 vs NIP-46 \u2014 the two signer models",
        "NIP-55 \u2014 the third signer standard",
        "NIP-05 \u2014 your name@domain identifier",
        "Org-account patterns",
        "Day 1 with your new credentials \u2014 checklist",
        "2. Relays",
        "NIP-42 (relay auth) and NIP-77 (sync efficiency)",
        "Local-first caching \u2014 NIndexedDB",
        "3. Event Model & Content Kinds",
        "NIP-04 vs NIP-17 \u2014 currency verdict",
        "NIP-72 vs NIP-29 \u2014 currency verdict",
        "4. Payments",
        "Zap flow (NIP-57)",
        "Nostr Wallet Connect (NIP-47)",
        "Cashu / nutzaps (NIP-60 / NIP-61) \u2014 status: active, still maturing",
        "Onchain zaps (kind 8333) \u2014 a third payment mechanism",
        "Practical wallet options (verify before moving real money)",
        "Tax reality (flag, not advice)",
        "5. Files & Media \u2014 The Storage Substrate",
        "NIP-96 vs Blossom \u2014 currency verdict",
        "How Blossom works",
        "nsite \u2014 static sites on Blossom",
        "Media metadata in posts (NIP-92)",
        "File-tool maturity",
        "6. Trust & Safety",
        "NIP-09 vs NIP-62 \u2014 currency verdict",
        "7. Discovery & App Wiring",
        "DVMs (NIP-90) \u2014 worked example: the agent-dispatch angle",
        "8. Master NIP Reference Table",
        "Open Questions",
        "Sources"
      ],
      "body": "This chapter is connective tissue: the protocol-level concepts underneath every Soapbox product a builder will touch \u2014 Ditto (community/company ops) [1], Agora (fundraising) [2], Shakespeare (AI-built sites) [3], NostrHub (publishing) [4]. Other chapters cover each product's verdict in depth; this one covers the NIPs (Nostr Implementation Possibilities) those products are built from, so decisions in one tool make sense in the others. Verified live against the nostr-protocol/nips repo on 2026-07-09 \u2014 the spec has moved since 2025 training data, notably several deprecations below. Worked examples throughout this chapter (a company domain, an operator's day-1 checklist, an agent-dispatch pattern) use the maintainers' own setup \u2014 trespies.dev, the operator Cruz, the DojoGenesis agent stack \u2014 as concrete, real data instead of placeholders. Swap in your own domain, team, and orchestrator wherever you see them. Amended: 2026-07-10 (v2 wave \u2014 NIP-62, NIP-55/17/29/42/77 currency, onchain zaps, signer additions, local-first caching). 1. Identity & Keys for a Company Confidence: High \u2014 verified against NIP-01, NIP-05, NIP-07, NIP-46, NIP-49, NIP-55 source, plus GitHub PR history for key migration. A Nostr identity is one keypair: a private key (nsec) and a public key (npub) \u2014 bech32-encoded, human-readable wrappers around a raw secp256k1 hex key [5][6]. The npub is the identity. There is no username/password, no account database, no \"forgot password\" flow. Whoever holds the nsec is the account, permanently, on every relay and client at once. Why this matters more than it sounds like it should: there is no ratified key-rotation mechanism. DOCUMENTED: \"there is no native, widely-adopted key rotation or recovery in Nostr. Your public key is your identity, so you cannot update or rotate it while keeping the same account\" [7] \u2014 a 2023 migration proposal (NIP-41) never merged [8]. If a key leaks, recovery is social: publish a note from the old key pointing followers to a new one, and wait for re-follows. NIP-26 (delegated signing), once floated as a fix, is now deprecated \u2014 \"unnecessary burden\" [5]. Treat nsec loss as identity loss, not a support ticket. Key custody decision tree NIP-07 vs NIP-46 \u2014 the two signer models NIP-07 (browser extension) NIP-46 (remote signer / bunker) What it is window.nostr object a browser extension injects; sites call getPublicKey()/signEvent() [9] Client and signer talk over relays via encrypted bunker:// or nostrconnect:// events (kind 24133); nsec never touches the client device [10] Where nsec lives In the browser extension's storage, on that one machine In the signer app/daemon \u2014 can be a phone, a server, hardware Tools Alby (Lightning wallet + signer, heavier), nos2x (signer-only, minimal, by Nostr's creator) [11] nsec.app (desktop + mobile, non-custodial) [12]; Amber (Android, keeps nsec segregated in one app, acts as a NIP-46 signer for other apps) [13] Best for Solo desktop use, one machine Multi-device use, teams, mobile-only, or keeping the key off the everyday client entirely Rationale straight from the spec: \"Private keys should be exposed to as few systems - apps, operating systems, devices - as possible as each system adds to the attack surface\" [10]. NIP-55 \u2014 the third signer standard NIP-07 and NIP-46 aren't the whole story. NIP-55 standardizes signing through Android's intent system: a client sends a sign request as an Android Intent, the signer app \u2014 not the requesting app \u2014 shows the approval prompt and returns the signature, so the private key never enters the requesting app's process [46]. Status is draft optional, the same maturity marker most working NIPs in this manual carry, and Amber is the reference implementation [13][46]. Soapbox's own key-management guidance draws the line explicitly: apps should implement NIP-07, NIP-55, and NIP-46 so a site or app can \"request signatures... without ever seeing the private key itself\" \u2014 and never fall back to asking for a raw nsec [47]. Treat that trio as the minimum bar for anything you build that touches Nostr keys. Two signer tools worth knowing that are newer than most Nostr key-management writeups: Soapbox Signer (Chrome/Firefox extension, announced Dec 2025) \u2014 NIP-07, multi-identity (switch between several npubs from one extension), per-domain permission grants, both NIP-04 and NIP-44 encryption, and identity export as JSON/CSV for backup or migration [48]. Divine's Keycast \u2014 a managed remote-signer service behind Divine, a Nostr-native short-video app (iOS + Android/Flutter): users create an account or import an nsec once, keys are encrypted server-side, and apps request signing via OAuth-style grants over a NIP-46 bunker URL \u2014 the pattern for \"feels custodial, isn't underneath\" signing [49]. NIP-05 \u2014 your name@domain identifier NIP-05 maps name@yourdomain.com to a pubkey via a JSON file at /.well-known/nostr.json [14]: Clients GET https://trespies.dev/.well-known/nostr.json?name=cruz and check the returned pubkey matches your profile's claimed pubkey [14]. Two rules that trip people up: the endpoint must not redirect, and the local-part is restricted to a-z0-9-_. [14]. Critically, this is identification, not verification \u2014 NIP-05 \"is not intended to verify a user, but only to identify them\" [14]; it proves domain control, nothing about the person. Two paths for @trespies.dev: Static file \u2014 trespies.dev already exists as a hosted static site; dropping a .well-known/nostr.json there is a no-server, static-hosting-compatible change [14]. This is the practical path for TresPies today. Ditto self-service \u2014 if community ops move to a self-hosted Ditto instance, Ditto grants NIP-05 self-service under its own domain, with admin approve/deny per request [15]. That's a different domain identity (e.g. @community.trespies.dev) than the static root-domain file \u2014 decide which one is canonical before publishing both. Org-account patterns [INFERRED from NIP-46 + NIP-05 mechanics \u2014 no single spec source covers \"how a company does this.\"] Nostr has no built-in org-account primitive; every event needs exactly one signing key. Two patterns cover most real usage: Pattern How it works Trade-off Shared brand account One npub (@trespies), key held in a bunker (self-hosted or nsec.app); staff get NIP-46 connection grants to request signatures, never see nsec Single voice, single point of custody failure; revoking a departed teammate = revoking their bunker grant, not rotating the key Personal + domain identity Each teammate runs their own npub with name@trespies.dev NIP-05; \"company\" is expressed via shared domain + mutual follows/mentions, not one account No single custody bottleneck; brand presence is diffuse across people Most orgs blend both \u2014 a brand account for official posts, personal NIP-05 identities on the same domain for individuals. Pick the brand-account bunker's admin (who can grant/revoke signer access) before anyone posts as @trespies. Day 1 with your new credentials \u2014 checklist Confirm your npub/nsec pair is the one you were issued; do not generate a second one by accident in a different client. Back up nsec offline immediately \u2014 encode it as ncryptsec (NIP-49: scrypt-derived key, XChaCha20-Poly1305 encryption) with a strong password [16]; store the password in a password manager and the encrypted string somewhere offline (not in this repo, not in Slack). Install a signer \u2014 NIP-07 extension (Alby or nos2x) for daily browser use; if you'll ever touch a second device, set up a NIP-46 bunker (nsec.app) now rather than exporting raw nsec later. Publish your profile \u2014 kind 0 event: name, about, picture, and (once a wallet exists \u2014 Section 4) a lud16 lightning address. Set up NIP-05 \u2014 publish .well-known/nostr.json on trespies.dev per the format above; add the nip05 field to your kind 0. Publish a relay list \u2014 kind 10002 (NIP-65), 2-4 write relays + a few read relays (Section 2). First post \u2014 a kind 1 note, to confirm the full round-trip: signer signs \u2192 event lands on your write relays \u2192 visible on njump.me or any client. 2. Relays Confidence: High \u2014 NIP-65, NIP-42, NIP-77 fetched directly; NIndexedDB confirmed against its own source file (2026-07-10); relay ecosystem facts cross-checked across two sources. A relay is a WebSocket server that stores and forwards events \u2014 dumb by design, no protocol-level authority. Clients choose which relays to trust. NIP-65 (Relay List Metadata) lets a user publish a kind 10002 event listing preferred relays, each optionally marked read or write [17]. \"When downloading events from a user, clients SHOULD use the write relays of that user.\" [17] That's the outbox model: publish to your write relays, look for someone's posts on their write relays, look for mentions of them on their read relays \u2014 a directed lookup instead of querying every relay for everything. Spec guidance: keep the list small, 2-4 relays per category [17]. NIP-42 (relay auth) and NIP-77 (sync efficiency) Two more relay-level mechanics worth knowing before picking a relay mix. NIP-42 is ephemeral challenge-response authentication: the relay sends [\"AUTH\", <challenge>], the client signs a throwaway kind-22242 event binding that challenge to the relay URL and sends it back [50]. Relays use this to gate access \u2014 restrict publishing to a whitelist, limit a private-message subscription to just its participants, or require auth before serving any request at all [50]. It's how a paid relay actually enforces \"paid\" instead of just asking nicely. NIP-77 (negentropy) solves a different problem: efficient re-sync. Instead of a client re-downloading everything or diffing by event ID, negentropy does range-based set reconciliation \u2014 client and relay exchange compact fingerprints of what they already have and transfer only the gap [51]. The protocol originated in Doug Hoyte's strfry relay before being written up as NIP-77 [52]; independent client-side implementations exist too, e.g. @nostr-dev-kit/sync, which reports 10-100x bandwidth reduction over plain REQ/EVENT sync once both sides are mostly caught up [52]. Caveat that matters operationally: merged into the NIPs repo is not the same as deployed \u2014 most relays don't implement NIP-77 yet, so treat it as a bonus when the relay on the other end supports it, not a default to build around. Relay type Examples Fit Public/free relay.damus.io, nos.lol [18] Fine for personal reach, no guarantees, higher spam exposure Paid nostr.wine, nostr.land (~$5-10/mo) [18] Spam filtering because posting costs something; worth it once discoverability matters Self-hosted Ditto (bundles its own relay) [1]; Relay Kit \u2014 \"one install script to deploy and manage Nostr relays, Blossom servers, and nsite gateways\" [19]; Stacks \u2014 Docker-based scaffolding for full Nostr infrastructure [19] Full moderation control, own domain identity, operational burden is yours Local-first caching \u2014 NIndexedDB Everything above is about which server-side relay to trust. There's a client-side complement: NIndexedDB, from @nostrify/indexeddb, is a first-party persistent browser cache that implements the same NStore interface as a relay or any other Nostrify storage \u2014 so it drops in as a swap, not a rewrite [60]. It supports the full Nostr filter set (ids, authors, kinds, single-letter tag filters, since/until, limit, and search), resolves supersession correctly (a newer replaceable/addressable event overwrites the old one in the cache, so queries never surface a stale kind-0 profile), and applies NIP-09 deletion requests on write [60]. When IndexedDB itself isn't available \u2014 Apple's Lockdown Mode disables it, along with Service Workers and WASM, as part of the exact threat model Lockdown Mode targets [61] \u2014 NIndexedDB degrades to a silent no-op (event() does nothing, query() returns empty) instead of throwing, so an app built against it doesn't crash under Lockdown, it just stops caching [60]. The rest of the NStore/NRelay interface family \u2014 signer swaps, moderation policies, the other storage backends \u2014 is Chapter 11's job; this is the one piece operators need now, because it's the practical answer to \"does the app work offline, and does it degrade gracefully when it can't.\" Moderation implication: content policy lives at the relay + client layer, not a platform layer (expanded in Section 6). Running your own relay is how TresPies enforces house rules on its own community \u2014 but nothing stops content being copied to other relays first. Deletion requests (NIP-09, master table) are, by default, a request \u2014 not a guarantee; NIP-62 (Section 6) exists for a stronger, MUST-honor version, but adoption is thin enough that NIP-09's advisory norm is still the safer planning assumption. 3. Event Model & Content Kinds Confidence: High for kind mechanics (direct NIP fetches); Medium for \"which tool uses which\" (mix of docs + search-derived, current as of 2026-07-09; adoption claims for NIP-17/NIP-29 refreshed 2026-07-10). Every Nostr action is the same JSON envelope \u2014 id, pubkey, created_at, kind, tags, content, sig [6] \u2014 differentiated only by kind. An operator mostly touches these (NIP numbers cited individually below; kind registry per [5]): Kind NIP Plain-English function Soapbox-stack surface 0 01 Profile (name, about, picture, nip05, lud16) Every product \u2014 this is your identity card 1 10 Short text note (the \"tweet\") Ditto feed, general posting 3 02 Follow list Ditto, any client's \"who you follow\" 30023 23 Long-form content (articles/blogs, Markdown) NostrHub docs, Ditto long-form posts \u2014 company blog/policy posts 4 04 (deprecated) Encrypted DM \u2014 legacy Avoid for new work 14 / 15 17 (+59) Private chat message / file message, gift-wrapped Ditto DMs, general private messaging 34550 / 1111 72 (unrecommended) Reddit-style community + moderator-approved posts Legacy clients (Amethyst, Nostrudel, Satellite) [21] \u2014 not Ditto's model 9 / 39000-39002 29 Discord-style relay-enforced groups Target model for Ditto's in-progress \"groups\" feature [15]; live today in 0xChat, chachi.chat [21] 30311 53 Live streaming event Ditto live streams \u2014 town halls, AMAs [20] 31922-31925 52 Calendar events Community scheduling NIP-04 vs NIP-17 \u2014 currency verdict NIP-04 is deprecated \u2014 \"Encrypted Direct Message (superseded by NIP-17)\" [5]. NIP-17 wraps a plain (unsigned) message in a seal (kind 13) then a gift wrap (kind 1059), per NIP-59 [22][23]. The privacy gain is real: \"Participant identities, each message's real date and time, event kinds\u2026 are all hidden from the public\" [22] \u2014 each gift wrap uses a random one-time key so relays can't correlate messages by sender, and timestamps are randomized per layer to defeat timing analysis [23]. NIP-04 leaked all of that \u2014 sender, recipient, and timing were public even though content was encrypted. Any new DM feature should be NIP-17, full stop. Adoption has moved from \"the spec says so\" to \"the clients actually ship it\": Amethyst, Primal, Nostur, Damus, noStrudel, and Coracle all run NIP-17 as their primary DM protocol now, and Amethyst's newer work extends the same gift-wrap machinery to sealed private replies on regular notes, not just 1:1 DMs [54]. Mostro \u2014 the P2P Bitcoin/Lightning exchange built on Nostr \u2014 made the same move at the protocol level: Mostro Protocol v2 (mostro-core v0.13.0) replaced its old relay-routed order messaging with NIP-44-encrypted, gift-wrapped kind-14 messages bound to a per-trade key, so relays now see only encrypted envelopes instead of order/dispute/settlement metadata [55]. Two different products, same direction of travel. Watch item, not a recommendation yet \u2014 and already more moved-on than expected: a parallel track for group E2EE exists, adapting MLS (Messaging Layer Security, the Signal-Protocol successor standardized as RFC 9420) for Nostr. This is exactly the kind of ground that shifts between verification passes: the original proposal, NIP-EE, is now itself marked unrecommended in the live NIPs repo, superseded by a separate, non-NIP-numbered spec called the Marmot Protocol [56]. Marmot is still experimental but already has real implementations moving \u2014 MDK (its Rust reference stack), marmot-ts, and apps including White Noise, Pika, and Vector [57]. Don't build on NIP-EE directly; if group E2EE becomes a real requirement, evaluate Marmot instead, and re-verify its status before committing to it. NIP-72 vs NIP-29 \u2014 currency verdict Sharper than expected: NIP-72 is now marked unrecommended in the core spec \u2014 \"unrecommended: try NIP-29 instead\" [24]. Steering has moved from moderator-approval (Reddit-style) toward relay-enforced membership (Discord-style), though both still have active client support today (NIP-72: Amethyst, Nostrudel, Satellite; NIP-29: 0xChat, chachi.chat, groups.nip29.com, and Flotilla \u2014 partially [21]). NIP-29 itself is still draft optional, the same maturity marker NIP-72 carries [21] \u2014 steering intent isn't the same as ratified stability. Ditto does neither exactly \u2014 it runs Mastodon-style server/domain moderation (admins, reports, NIP-05 self-service) today, with NIP-29-style groups on its roadmap [15]. Operator read: don't build new tooling against NIP-72; use Ditto's current server-level moderation if it fits, and wait for its NIP-29 groups for Discord-style team space. For a consumer app specifically: NIP-29's implementation list is real but still small and still drafting \u2014 not a universal-adoption bet yet, the way NIP-65 or NIP-17 now are. 4. Payments Confidence: High for NIP-57/47/60/61 mechanics (direct spec fetches) and for kind 8333 onchain zaps (Ditto reference doc fetched directly, 2026-07-10); Medium for wallet-option currency (fast-moving market, verify before funding anything). Zap flow (NIP-57) A zap request (kind 9734) is signed by the sender but sent directly to the recipient's LNURL callback \u2014 it is not itself published to relays [25]. Once paid, the recipient's Lightning service publishes a zap receipt (kind 9735) to the relays named in the request [25] \u2014 that receipt is the public, verifiable \"this got paid\" record clients render as a zap. Nostr Wallet Connect (NIP-47) NWC lets an app pay/check-balance/list-transactions against a wallet without ever holding the wallet's keys \u2014 connection is a nostr+walletconnect:// URI (wallet pubkey + per-client secret + relay) [26]. The wallet service runs as an always-on process; the client stores only its own secret and talks to it over relays [26] \u2014 this is what lets you connect one Alby Hub wallet to several apps with separate, revocable, spend-limited grants per app. Cashu / nutzaps (NIP-60 / NIP-61) \u2014 status: active, still maturing Both are live, non-deprecated NIPs [5]. NIP-60 stores an encrypted \"wallet in relays\" \u2014 mint references and unspent ecash proofs as kind 17375/7375/7376/7374 events, so wallet state follows the user across apps [27]. NIP-61 \"nutzaps\" collapse payment and receipt into one object: a Cashu token locked to the recipient's pubkey (P2PK) is the payment and the proof, no separate receipt needed [28]. Newer and less battle-tested than NIP-57 zaps; promising, not yet default. Onchain zaps (kind 8333) \u2014 a third payment mechanism As of Ditto 2.12 (shipped, per Soapbox's own post, May 2026) there's a third way to move value on Nostr, alongside Lightning/NIP-57 and Cashu/NWC [58]: onchain zaps \u2014 direct on-chain Bitcoin transfers, using kind 8333, defined as \"attestation that an on-chain Bitcoin transaction paid a Nostr event or profile\" [59]. The mechanism leans on a property of Nostr keys that isn't obvious until pointed out: because both Nostr and Bitcoin use secp256k1, a Nostr public key can double directly as a Bitcoin address \u2014 no separate wallet setup for sender or receiver [58]. Ditto layers Silent Payments on top for privacy \u2014 deriving a fresh, unlinkable receiving address per payment from a single published key, so on-chain analysis can't trivially cluster a recipient's zaps together [58]. Practical cost, in the team's own words: \"It was costing $0.24 to send a transaction. For most of its life the average Nostr transaction was about $0.02\" [58] \u2014 an onchain zap costs noticeably more than a typical Lightning-based zap, a tradeoff the team argued over before shipping and judged acceptable once you're sending amounts larger than a tip; onchain fees also float with mempool conditions, so treat $0.24 as a snapshot, not a constant. For anyone building rather than just operating: this is the same territory MKStack's onchain-bitcoin skill covers (Chapter 12) \u2014 worth knowing it exists before reinventing it. Practical wallet options (verify before moving real money) Option Custody Fit Alby Hub Self-custodial; runs on your choice of 6 Lightning backends (LDK, LND, Greenlight, Phoenixd, Breez SDK, or a Cashu mint) [29][30] Best fit for a technical operator wanting one controlled node behind NWC coinos Lower-friction web wallet, Lightning + ecash Fast start, less control Primal Wallet Built into the Primal client Fine for personal zapping, not a business Lightning node Cashu mints Ecash \u2014 the mint is a custodial trust point even though the token is bearer-instrument-like Good for small nutzap balances; don't park significant value at a single mint Alby's own guidance signals the direction: they're \"phasing out Alby's shared [custodial] wallet\" for Alby Hub [31] \u2014 self-custody is where the tooling is consolidating in 2026, not custodial web wallets. Tax reality (flag, not advice) Sats received for goods/services are ordinary income at fair market value in USD on the date received \u2014 for a sole proprietorship, Schedule C, subject to self-employment tax [32]. The $10,000 Form 8300 cash-reporting trigger technically applies to crypto too, though enforcement is currently paused pending final regulations [32]. Not tax advice \u2014 get an accountant before treating zaps as real revenue. 5. Files & Media \u2014 The Storage Substrate Confidence: High \u2014 Blossom BUD structure and NIP-96 deprecation directly confirmed from source. NIP-96 vs Blossom \u2014 currency verdict Settled. NIP-96 (HTTP File Storage Integration) carries an explicit deprecation banner: \"unrecommended: deprecated in favor of NIP-B7\" [33] \u2014 NIP-B7 being Blossom, which was folded into the core NIPs index as an active spec [5]. Blossom won. Don't build new file-upload integrations against NIP-96. How Blossom works Blossom is an HTTP-endpoint spec for storing blobs addressed by their SHA256 hash, authorized using the uploader's Nostr keypair [34] \u2014 same file, same identity everywhere; upload/delete rights ride on Nostr auth, not a platform account. The spec is a stack of BUD (Blossom Upgrade Document) documents: BUD Covers BUD-01 Fetching blobs (GET/HEAD) BUD-02 Uploading blobs BUD-03 User Server List \u2014 which servers a user prefers BUD-04 Server-to-server mirroring BUD-05 Media optimization/transformation BUD-06 Upload constraints BUD-07 Payment-gated storage BUD-08 Nostr metadata tags for files BUD-09 Blob reporting/moderation BUD-10 URI schema BUD-11 Nostr-based auth tokens BUD-12 Blob lifecycle (delete/list) Mirroring (BUD-04) is what makes this resilient: if a file's home server disappears, any client can pull it from another server in the uploader's published list [34] \u2014 same file, same hash, different host. Ditto's product materials describe its media layer as Blossom-integrated [1]; the specific server hostname surfaced in search wasn't independently confirmable this session (install-guide fetch 404'd) \u2014 see Open Questions. nsite \u2014 static sites on Blossom nsite serves a full static website from a Blossom-hosted blob set, with the path-to-file mapping published as Nostr events under the owner's npub \u2014 \"a static site deployed under your npub, where the raw data is stored on blossom servers, and the mapping from path to sha256 of the content is stored on relays\" [35]. Effect: a website with no traditional host \u2014 if one gateway blocks it, it resolves through another, because resolution is relay-based, not DNS/server-based [35]. Directly relevant if Shakespeare-built output [3] ever needs a censorship-resistant deployment target beyond a conventional host. Media metadata in posts (NIP-92) An imeta tag attaches structured metadata \u2014 MIME type, SHA256 hash, dimensions, blurhash, alt text \u2014 to a URL inside a kind 1 note's content [36], so clients can render previews and verify integrity before fetching. File-tool maturity Tool Maturity Fit for company docs Blossom (protocol) Active, in core NIPs The substrate \u2014 always relevant Blossom Drive Deprecated / unmaintained, \"hasn't been updated in over a year\" [37] Skip Bouquet Current recommended successor for managing Blossom blobs [37] Reasonable for ad hoc file management today nsite tooling (nsyte, nsite-cli, and related CLIs) Multiple active repos surfaced in search; individual maintenance status not independently verified this session [35] Good for static-site deployment, not general document storage 6. Trust & Safety Confidence: High \u2014 NIP-56, NIP-32, NIP-51, NIP-09, NIP-62 fetched directly; NIP-62's named third-party implementations are REPORTED (search-derived), not all independently confirmed shipped. Three separate primitives, each doing one job: NIP-56 Reporting \u2014 kind 1984 events flag a pubkey or note under one of seven categories: nudity, malware, profanity, illegal, spam, impersonation, other [38]. The spec explicitly warns relays against fully-automated moderation on report volume alone \u2014 \"reports are easily manipulated\"; trusted moderator judgment is the intended backstop [38]. NIP-32 Labeling \u2014 kind 1985 events attach a namespaced label (L tag) and value (l tag) to an event, pubkey, relay, or topic [39]. Broader than moderation \u2014 also used for content classification and licensing \u2014 but it's the primitive a moderation dashboard would consume. NIP-51 Mute Lists \u2014 kind 10000, a personal list of pubkeys/hashtags/words/threads a user doesn't want to see [40]; can hold private (encrypted) entries alongside public ones. NIP-09 vs NIP-62 \u2014 currency verdict Reporting, labeling, and muting (above) are signals \u2014 they don't remove anything by themselves. Actual deletion is a separate, smaller pair of primitives, and the two are not equivalent: NIP-09 (Event Deletion Request) \u2014 a client asks relays to drop an event by publishing a kind-5 request naming it. Advisory only: the NIP uses SHOULD language, relays are free to ignore it, and nothing stops a relay that already forwarded the event from having it live on elsewhere. This is the deletion behavior most of the ecosystem has today. NIP-62 (Request to Vanish) \u2014 a materially stronger primitive, merged into the spec February 19, 2025 [53]. Relays that implement it MUST fully delete every event from the requesting pubkey (not just one named event), MUST ensure deleted events aren't re-broadcast, and \u2014 the clause with real teeth \u2014 paid or access-restricted relays MUST honor the request regardless of the requester's account status [53]: a relay can't hold data hostage by banning the account first. Requests can be targeted (naming specific relay URLs) or global ([\"relay\", \"ALL_RELAYS\"], broadcast as widely as possible) [53]. NIP-62 also SHOULDs relays into deleting NIP-59 gift wraps addressed to the pubkey \u2014 a vanish request can reach into someone's DMs, not just their public notes [53]. Adoption is thin. NIP-62 is real and legally meaningful wherever \"right to be forgotten\" regimes apply, but implementation is still early: rust-nostr has shipped it across all three of its storage backends (LMDB, SQLite, in-memory); the nostrcheck-server relay module and the Nestr client both show it as planned/in-progress per project trackers, not confirmed shipped [53]. Ditto's own support wasn't confirmed either way this session \u2014 verify directly before promising a user (or a regulator) that \"vanish\" actually works on your relay. Practical read: NIP-09 is still the safe default assumption for \"will this actually disappear\"; reach for NIP-62 when a deletion promise needs to be a MUST, not a SHOULD, and confirm relay-by-relay support before relying on it. Why moderation is relay + client level, not platform level: no central authority can remove content network-wide. A relay operator (Ditto, in TresPies' case) decides what their relay stores, and clients decide what they render \u2014 reports and labels are signals those parties act on, not enforcement with teeth beyond one relay's boundary [15]. Practical consequence: you fully control your own relay's front door for events you're willing to purge on request \u2014 NIP-62 gives that control real force, NIP-09 gives it a polite ask \u2014 but neither can make content vanish once it has propagated to a relay outside your control. 7. Discovery & App Wiring Confidence: Medium \u2014 NIP-89/34 mechanics are High (direct fetch); the DVM ecosystem's current health is a mix of DOCUMENTED spec status and REPORTED community activity. NIP-89 (Recommended Application Handlers) is Nostr's \"open in app\" mechanism: apps publish kind 31990 advertising which event kinds they handle; users or contacts publish kind 31989 recommending a handler [41]. Same mechanism DVM marketplaces use for provider discovery (below). NIP-34 (git over Nostr) replaces GitHub's centralized model with relay-published repo announcements (kind 30617), patches (kind 1617), and issues (kind 1621) [42] \u2014 not in the Soapbox stack directly, but a pattern any team could use for censorship-resistant code collaboration. NIP-05 as lightweight SSO: since a NIP-05 identifier cryptographically ties a domain to a pubkey [14], \"Login with Nostr\" flows ask a user to sign a challenge event and check it resolves to the claimed name@domain \u2014 no password, no OAuth provider. Any app you build (via Shakespeare or otherwise) can use this for low-friction auth. DVMs (NIP-90) \u2014 worked example: the agent-dispatch angle Currency verdict: the base spec is deprecated. Its own file warns: \"this got totally out of control, prefer use-case-specific microstandards\" [43], unrecommended throughout. No single named successor \u2014 but the pattern moved rather than died: a dedicated nostr-protocol/data-vending-machines repo maintains the kind registry (5000-5999 requests \u2192 6000-6999 results \u2192 7000 status) as narrow per-job \"microstandards\" [44]. Discovery still runs through NIP-89 \u2014 newer projects (e.g. Agentry) auto-discover DVM providers via kind 31990 [45]. Worked example \u2014 if you run an agent orchestrator (DojoGenesis Gateway, or any other agent-dispatch stack): DVMs are structurally the same shape as an internal job-dispatch queue (the maintainers' own is dojoagentdispatch) \u2014 post a job, providers compete, deliver, get paid in sats instead of an internal ledger. Real and live, worth scouting for any orchestrator looking for an open, cross-network job market \u2014 but the \"unrecommended\" base spec plus an informally-governed sister repo means treat it as an early probe, not a dependency. 8. Master NIP Reference Table The protocol reference card for this manual. Status reflects the live nostr-protocol/nips repo as of 2026-07-09 [5], amended 2026-07-10 with NIP-62, NIP-55, NIP-42, NIP-77, and kind 8333 (onchain zaps) \u2014 see the Amended note at the top of the chapter. Individual NIPs are cited in the relevant prose sections above; this table is the consolidated index. NIP / Protocol Function Soapbox-stack surface Operator relevance NIP-01 Core event format, keys, kind 0 profile Every product Foundation \u2014 read once, applies everywhere NIP-02 Follow list (kind 3) All clients Who your account follows NIP-05 name@domain identifier via .well-known/nostr.json Static hosting (e.g. trespies.dev) or Ditto self-service Sets up you@yourdomain; day-1 task NIP-07 Browser-extension signing (window.nostr) Any web client, incl. Shakespeare-built sites Alby or nos2x for daily desktop use NIP-09 Event deletion request All clients Advisory only \u2014 not guaranteed removal; see NIP-62 for the MUST-delete alternative NIP-17 + NIP-59 Private DMs via gift-wrap Ditto DMs, general clients Current standard \u2014 use this, not NIP-04 NIP-19 bech32 entities (npub/nsec/note/nevent) Universal How keys/events are shared as text NIP-23 Long-form content (kind 30023) NostrHub docs, Ditto articles Company blog posts, policy docs NIP-26 Delegated signing Deprecated \u2014 none Ignore; don't build on it NIP-29 Relay-based groups (Discord-style) Roadmap for Ditto groups; live in 0xChat, chachi.chat, groups.nip29.com, Flotilla (partial) Team/private space, once Ditto ships it \u2014 still draft-status itself NIP-32 Labeling (kind 1985) Ditto moderation backend Content classification signal NIP-34 Git over Nostr Not in Soapbox stack directly Optional pattern for censorship-resistant code collab NIP-41 Key migration Unmerged proposal, stalled Don't rely on it \u2014 use social recovery instead NIP-42 Relay authentication (ephemeral kind-22242 challenge-response) Paid/whitelisted relays, DM-gating Gates access \u2014 expect it wherever a relay charges or restricts NIP-46 Remote signing (bunker) nsec.app, Amber, Divine's Keycast; any NIP-46-aware client Team + multi-device signing without exposing nsec NIP-47 Nostr Wallet Connect Alby Hub \u2192 any app Connect one wallet to many apps, revocable per app NIP-49 ncryptsec password-encrypted key backup Manual step, any client How you back up nsec safely NIP-51 Lists (mute list, bookmarks, etc.) Ditto, any client Spam/abuse control (kind 10000 mute list) NIP-52 Calendar events Community clients Scheduling for company/community events NIP-53 Live streaming (kind 30311) Ditto live streams Town halls, AMAs NIP-55 Android signer app intents Amber; any Android Nostr app Third signing standard alongside NIP-07/NIP-46 \u2014 never request raw nsec NIP-56 Reporting (kind 1984) Ditto moderation queue Abuse-reporting pipeline NIP-57 Lightning zaps Ditto tipping; likely Agora's payment signal (unconfirmed \u2014 see Open Questions) Value-for-content, community support NIP-60 Cashu wallet (wallet-in-relays) Emerging wallet layer Portable ecash balance across apps \u2014 still maturing NIP-61 Nutzaps (payment = receipt) Emerging Newer than zaps; promising, not yet default NIP-62 Request to Vanish \u2014 MUST-delete, not advisory Not confirmed in Ditto; rust-nostr, others (thin adoption) Stronger deletion primitive than NIP-09; verify per-relay before relying on it NIP-65 Relay list metadata / outbox model All clients Relay strategy \u2014 where you publish, where others find you NIP-72 Communities (Reddit-style) Unrecommended \u2014 legacy clients only Understand it; don't build new work on it NIP-77 Negentropy sync (range-based set reconciliation) strfry origin; @nostr-dev-kit/sync client-side 10-100x sync bandwidth once both sides support it \u2014 most relays don't yet NIP-89 Recommended application handlers Shakespeare-built apps, NostrHub app directory, DVM discovery \"Open in app\" discovery; also how DVM providers get found NIP-90 Data Vending Machines Not in Soapbox stack directly; relevant to any agent orchestrator AI-agent job marketplace pattern \u2014 base spec deprecated, successor is a sister kind-registry repo NIP-92 Media attachment metadata (imeta) Ditto media posts Rich previews, integrity hashes on posted media NIP-94 File metadata event Pairs with Blossom uploads Describes an uploaded file as a Nostr event NIP-96 HTTP file storage Deprecated \u2014 replaced by Blossom Ignore; use Blossom NIP-B7 (Blossom) Blob storage protocol, hash-addressed Ditto media layer, Shakespeare sites, nsite The file-storage substrate under the whole stack NIP-5A (nsite) Static websites served from Blossom + relays Alternative deploy target to conventional hosting Censorship-resistant hosting option Kind 8333 (no NIP number yet) Onchain zap \u2014 Bitcoin tx as payment attestation Ditto 2.12+ wallet Third payment rail alongside Lightning zaps and Cashu; Silent Payments privacy option Open Questions Whether Agora emits actual NIP-57 zap receipts, or uses a simpler direct wallet-to-wallet Lightning flow with Nostr only for identity/comms \u2014 Agora's own materials describe \"wallet-to-wallet\" Bitcoin movement without confirming zap-event mechanics [2]; verify in the Agora-specific chapter. Whether Ditto's media pipeline specifically points at blossom.ditto.pub \u2014 this hostname surfaced in preliminary search results but the primary Ditto self-hosting doc 404'd on direct fetch this session; the general claim \"Ditto integrates with Blossom\" is solid [1], the specific hostname is REPORTED, not independently confirmed. Exact reason NIP-06 (mnemonic-seed key derivation) was deprecated \u2014 confirmed deprecated in the index [5], but the deprecation-note text itself wasn't fetched; doesn't change the operator recommendation (use NIP-49 ncryptsec for backup) but worth closing out if seed-phrase import ever comes up in a signer's UI. Whether Ditto's planned NIP-29 groups feature has shipped by the time an operator would adopt it \u2014 roadmap item as of the fetched blog post [15], not yet confirmed live. DVM ecosystem health beyond the spec-status question \u2014 Agentry and similar discovery projects surfaced in search but weren't independently verified for maturity beyond their own landing page [45]; treat any DVM integration as a probe, not a plan. Sources Soapbox \u2014 Ditto product page, plus Announcing Ditto and Ditto Server Keypair docs \u2014 accessed 2026-07-09 \u2014 Ditto architecture (relay + web UI + Mastodon API), Blossom integration, self-hosted relay. Soapbox \u2014 Agora and Agora: Connecting Freedom Fighters to Uncensorable International Support \u2014 accessed 2026-07-09 \u2014 Agora product description, non-custodial wallet-to-wallet design, Nostr-as-comms-layer framing. Soapbox \u2014 Shakespeare and Announcing Shakespeare \u2014 accessed 2026-07-09 \u2014 AI website builder on Nostr, NSP model, AGPL license. Soapbox \u2014 NostrHub \u2014 accessed 2026-07-09 \u2014 NIP/app/repo discovery hub description. nostr-protocol/nips README (NIP index + kind registry) \u2014 accessed 2026-07-09 \u2014 full NIP list, deprecation status, complete event-kind registry. NIP-01: Basic protocol flow description \u2014 accessed 2026-07-09 \u2014 event structure, key basics, kind 0 definition. Nostr Key Management: Complete Guide \u2014 accessed 2026-07-09 \u2014 current-practice statement on key rotation absence. NIP-41: simple account migration (unmerged PR #829) \u2014 accessed 2026-07-09 \u2014 confirms migration proposal never ratified. NIP-07: window.nostr capability for web browsers \u2014 accessed 2026-07-09 \u2014 extension API, methods. NIP-46: Nostr Remote Signing \u2014 accessed 2026-07-09 \u2014 bunker/nostrconnect flow, roles, rationale quote. Best Nostr Browser Extensions 2026 \u2014 comparison \u2014 accessed 2026-07-09 \u2014 Alby vs nos2x positioning. nsec.app \u2014 accessed 2026-07-09 \u2014 non-custodial key storage/remote signer product description. Amber (GitHub) \u2014 accessed 2026-07-09 \u2014 Android NIP-46 signer, supported client list. NIP-05: Mapping Nostr keys to DNS-based identifiers \u2014 accessed 2026-07-09 \u2014 exact .well-known/nostr.json format, verification flow, caveats. Creating Curated Communities on Nostr with Ditto \u2014 accessed 2026-07-09 \u2014 NIP-05 self-service, moderation model, NIP-29 roadmap note. NIP-49: Private Key Encryption (ncryptsec) \u2014 accessed 2026-07-09 \u2014 password-encrypted key backup spec. NIP-65: Relay List Metadata \u2014 accessed 2026-07-09 \u2014 outbox model, read/write markers. How to Choose Nostr Relays \u2014 accessed 2026-07-09 \u2014 relay-mix recommendations, paid relay examples/pricing. Soapbox Toolbox \u2014 accessed 2026-07-09 \u2014 full Soapbox product inventory, Relay Kit / Stacks descriptions. NIP-53: Live Streaming and Spaces \u2014 accessed 2026-07-09 \u2014 kind 30311 structure. Comparing Nostr Group Implementations \u2014 Nostrbook \u2014 accessed 2026-07-09 \u2014 plain-English NIP-29 vs NIP-72 comparison, client support lists. NIP-17: Private Direct Messages \u2014 accessed 2026-07-09 \u2014 gift-wrap DM design, kind 14/15. NIP-59: Gift Wrap \u2014 accessed 2026-07-09 \u2014 rumor/seal/wrap layering, metadata protection. NIP-72: Moderated Communities \u2014 accessed 2026-07-09 \u2014 verbatim deprecation notice, original community model. NIP-57: Lightning Zaps \u2014 accessed 2026-07-09 \u2014 zap request/receipt flow. NIP-47: Nostr Wallet Connect \u2014 accessed 2026-07-09 \u2014 connection URI, methods, roles. NIP-60: Cashu Wallet \u2014 accessed 2026-07-09 \u2014 wallet-in-relays architecture, kind numbers. NIP-61: Nutzaps \u2014 accessed 2026-07-09 \u2014 payment-as-receipt design, kind 9321. Alby Hub \u2014 accessed 2026-07-09 \u2014 self-custodial wallet product description. The 6 different Lightning backends for Alby Hub \u2014 accessed 2026-07-09 \u2014 backend options (LDK, LND, Greenlight, Phoenixd, Breez SDK, Cashu mint). Embrace Alby Hub \u2014 phasing out Alby's shared wallet \u2014 accessed 2026-07-09 \u2014 custodial-to-self-custodial market shift, verbatim quote. IRS: Report digital asset income \u2014 accessed 2026-07-09 \u2014 tax treatment of crypto/digital-asset income, Form 8300 status. NIP-96: HTTP File Storage Integration \u2014 accessed 2026-07-09 \u2014 verbatim deprecation notice pointing to NIP-B7/Blossom. Blossom protocol README / BUD specs \u2014 accessed 2026-07-09 \u2014 blob addressing, BUD-01 through BUD-12 overview, mirroring. Nsite.info \u2014 Let them eat static \u2014 accessed 2026-07-09 \u2014 nsite mechanics, Blossom + relay resolution; also source for nsite CLI tooling landscape. NIP-92: Media Attachments Metadata (imeta) \u2014 accessed 2026-07-09 \u2014 imeta tag fields. blossom-drive (GitHub) \u2014 deprecation note pointing to Bouquet \u2014 accessed 2026-07-09 \u2014 file-manager tool status. NIP-56: Reporting \u2014 accessed 2026-07-09 \u2014 kind 1984 structure, report categories. NIP-32: Labeling \u2014 accessed 2026-07-09 \u2014 kind 1985 structure, namespaces, use cases. NIP-51: Lists \u2014 accessed 2026-07-09 \u2014 mute list and other standard list kinds. NIP-89: Recommended Application Handlers \u2014 accessed 2026-07-09 \u2014 kind 31989/31990 discovery mechanism. NIP-34: git stuff \u2014 accessed 2026-07-09 \u2014 repo/patch/issue event kinds. NIP-90: Data Vending Machines \u2014 accessed 2026-07-09 \u2014 verbatim deprecation notice, original job-marketplace design. nostr-protocol/data-vending-machines (kind registry repo) \u2014 accessed 2026-07-09 \u2014 successor governance model for DVM kinds. Nostr Agent Network \u2014 Agentry \u2014 accessed 2026-07-09 \u2014 example of DVM provider discovery via NIP-89. Amendment pack sources (2026-07-10 v2 wave): NIP-55: Android Signer Application \u2014 accessed 2026-07-10 \u2014 status header (draft optional), Intent/Content Resolver/Web signing methods. Managing Nostr Keys \u2014 Soapbox Blog \u2014 accessed 2026-07-10 \u2014 NIP-07/NIP-55/NIP-46 framing as the three signing standards apps should implement, Amber description. Announcing Soapbox Signer \u2014 accessed 2026-07-10 \u2014 Dec 7 2025 launch, Chrome/Firefox extension, multi-identity, per-domain permissions, NIP-04/NIP-44, JSON/CSV identity export. Divine \u2014 Open Source, Divine (GitHub org), Keycast (GitHub) \u2014 accessed 2026-07-10 \u2014 Nostr-native short-video app; Keycast as its OAuth-style NIP-46 remote-signer service; iOS App Store + Flutter Android build. NIP-42: Authentication of Clients to Relays \u2014 accessed 2026-07-10 \u2014 ephemeral kind-22242 challenge-response flow, access-gating use cases. NIP-77: Negentropy Syncing \u2014 accessed 2026-07-10 \u2014 range-based set reconciliation spec, draft status. @nostr-dev-kit/sync (npm), hoytech/negentropy \u2014 accessed 2026-07-10 \u2014 negentropy's origin in Doug Hoyte's strfry relay; 10-100x bandwidth-reduction claim; client-side NIP-77 implementation. NIP-62: Request to Vanish, merge PR #1256 \u2014 accessed 2026-07-10 \u2014 MUST-delete / no-rebroadcast / paid-relay language verbatim; merge date (2025-02-19) confirmed directly via repo commit history; third-party implementation status (rust-nostr, nostrcheck-server, Nestr) cross-checked via search \u2014 REPORTED, not all independently confirmed shipped. Amethyst (GitHub) \u2014 accessed 2026-07-10 \u2014 NIP-17 as primary DM protocol across major clients (Amethyst, Primal, Nostur, Damus, noStrudel, Coracle); gift-wrapped private-note replies \u2014 search-derived, current release cycle. Mostro (GitHub) \u2014 accessed 2026-07-10 \u2014 Mostro Protocol v2 / mostro-core v0.13.0 migration to NIP-44 gift-wrapped kind-14 trade messaging. NIP-EE: E2EE Messaging using MLS \u2014 accessed 2026-07-10 \u2014 status header (final unrecommended optional), verbatim supersession notice pointing to the Marmot Protocol. Marmot Protocol (GitHub) \u2014 accessed 2026-07-10 \u2014 NIP-EE's successor; experimental status, named implementations (MDK, marmot-ts, White Noise, Pika, Vector). Onchain Zaps in Ditto \u2014 Soapbox Blog \u2014 accessed 2026-07-10 \u2014 May 2026 post; Ditto 2.12 wallet, Nostr-keys-as-Bitcoin-addresses mechanic, Silent Payments, verbatim $0.24-vs-$0.02 fee quote. Ditto Nostr Reference \u2014 accessed 2026-07-10 \u2014 kind 8333 definition (\"attestation that an on-chain Bitcoin transaction paid a Nostr event or profile\"). NIndexedDB.ts (soapbox-pub/nostrify) \u2014 accessed 2026-07-10 \u2014 full source of @nostrify/indexeddb's NStore implementation: filter support, replaceable/addressable supersession, NIP-09 deletion-on-write, IndexedDB-unavailable no-op behavior. About Lockdown Mode \u2014 Apple Support \u2014 accessed 2026-07-10 \u2014 corroborates that Lockdown Mode disables IndexedDB-dependent web functionality, the real-world trigger for NIndexedDB's no-op path."
    },
    {
      "id": "manual/07-integration-playbook",
      "kind": "manual",
      "lang": "en",
      "title": "07 \u2014 Integration Playbook: Running (and Modding) the Stack",
      "url": "/manual/#ch07",
      "md_url": "/manual/md/07-integration-playbook.md",
      "sha256": "c1120a61c2d9db627608c8bd9ff39b4c5550ff57b08f00e879515369e29c1f0b",
      "bytes": 20375,
      "headings": [
        "0. The operating rule that governs everything: the AGPL boundary",
        "1. Decision summary",
        "2. Day 1 with your credentials (do this before anything else)",
        "3. Runbook A \u2014 Community and company ops",
        "4. Runbook B \u2014 Funding on Agora",
        "5. Runbook C \u2014 Sites, funnels, mockups on Shakespeare",
        "6. Runbook D \u2014 Publishing on NostrHub 2.0",
        "7. Integration matrix",
        "8. Build opportunities",
        "9. The TresPies modded-stack blueprint (steering direction, 2026-07-09)",
        "9.0 AI + orchestration layer (operator-specified 2026-07-09)",
        "9.1 i18n integration (from ch. 08)",
        "9.2 Visualization integration (from ch. 09)",
        "9.3 Git-anchor + mirror runbook",
        "9.4 Sequencing (30/60/90) and tripwires",
        "10. Consolidated open questions"
      ],
      "body": "How TresPies/DojoGenesis actually operates on the Soapbox stack \u2014 four runbooks, one integration matrix, the build opportunities, and the TresPies modded-stack blueprint (steering direction, 2026-07-09). Verified: 2026-07-09. Synthesized in the main thread from chapters 01\u201306 and 08\u201309 (each chapter carries its own numbered primary sources; this chapter cites chapters). Facts cross-checked across chapters; two contradictions found and resolved during assembly (Armada existence \u2014 ch. 02 corrected; Blossom Drive deprecation \u2014 ch. 02 aligned to ch. 06). 0. The operating rule that governs everything: the AGPL boundary Soapbox apps are AGPL-3.0: a modded, client-facing deployment must publish its modifications (ch. 01). The rule: i18n/viz mods live in the open layer (good citizenship in a grant-funded ecosystem, and it's the build-in-public playbook anyway); client work and IP live in config/content/plugin layers on top, never in the fork; anything that must stay closed gets built on Nostrify (MIT, confirmed). Ch. 10 nuance: the MKStack template ships no license file at all \u2014 likely an oversight and boilerplate norms suggest reuse is expected, but get explicit terms from Soapbox before a closed commercial fork \u2014 and mkstack-nsp (the AI backend) is AGPLv3, so a self-hosted modified NSP owes its source to its users. Ratified 2026-07-09 \u2014 ADR: 0001-mod-layer-rule (the maintainers' companion decision record; not shipped with this public chapter set; internal: PIP-94 phase 1 closed); residual item: ask Soapbox for explicit MKStack-template terms before any closed commercial fork. 1. Decision summary Need Use Not (yet) Chapter Public branded community Ditto (self-host or ditto.pub while piloting) Armada (too young for public-facing) 02 Internal team chat, E2E Armada pilot (low-stakes channels first) Betting company ops on 0.x 02 Team file storage (binary/office assets) Keep Drive/Dropbox Blossom as a drive (no folders/ACLs/versions) 02, 06 Team knowledge (md + git + memory autosync) Git-anchored via NIP-34/GRASP (\u00a79.3.6) Needing Drive for md-native work 05, \u00a79.3 Fundraising rail (BTC-native, censorship-resistant) Agora Replacing GoFundMe for normie donors (no card checkout) 03 Client mockups at volume Shakespeare, free tier / cheap BYOK \u2014 04 Production client sites + funnels Shakespeare + external conversion stack Client self-editing (no CMS) 04 Developer distribution / credibility NostrHub 2.0 (repos, apps, articles) Expecting it to be a growth channel 05 Bilingual layer Fork Agora's i18next pattern + Lingo.dev Waiting for a Nostr language NIP (none ratified) 08 Equity-data dashboards MapLibre+PMTiles+ECharts, zero-server Viz inside Ditto (no widget surface) or 30023 (no HTML) 09 2. Day 1 with your credentials (do this before anything else) Ch. 06 \u00a71 has the full version with sources; the sequence: Back up the nsec offline \u2014 password-encrypt it as ncryptsec (NIP-49). There is no reset and no ratified key rotation; losing it is identity loss. Install a NIP-07 signer extension (Alby or nos2x) on your main machine. The key never touches websites. Stand up a NIP-46 bunker (nsec.app; Amber on Android) the moment a second device or teammate is involved. Publish your kind-0 profile (name, bio, avatar) from a real client. Claim NIP-05: you@yourdomain.com = one static JSON at https://yourdomain.com/.well-known/nostr.json (no redirects allowed). Minutes on existing infra. Pick relays deliberately \u2014 2\u20134 write relays + a few read (NIP-65 outbox), not twenty. Log into NostrHub with the extension (never the nsec-paste or key-file options it also offers \u2014 ch. 05). First publishes: a kind-1 note; then a kind-30023 long-form to test the publishing path. Decide the org-account pattern: brand account (shared via bunker) + personal accounts; document custody (who holds what, where the ncryptsec backups live). Wallet: connect via NWC (NIP-47) for zaps; treat received sats as accounting events from day 1 (ch. 06 \u00a74 flags the tax reality). 3. Runbook A \u2014 Community and company ops Shape: Ditto = the storefront community (public, branded, bridged); Armada = the back office pilot (E2E, internal). They are different products, not versions of one thing (ch. 02). Step Ditto (public) Armada (internal pilot) 1. Stand up Join flagship ditto.pub to learn the UX, then self-host: Deno + Postgres + Nginx/Certbot (real ops, not a $5 static VPS \u2014 ch. 02) Open the web app from soapbox.pub/armada; Zapstore for Android; Electron for desktop 2. Brand Custom domain, themes (9 presets / 19 CSS tokens; beyond that = fork \u2192 AGPL layer) Create server \u2192 channels/threads/roles 3. Team Staff accounts via bunker; moderation = Mastodon-style admin tools Invite via Concord invites (gift-wrapped over public relays; no server to run) 4. Reach Mastodon-API apps (50+ clients), Mostr bridge \u2192 Fediverse, \u2192 Bluesky (~15 min lag) Keep to low-stakes channels until audited; export nothing sensitive yet 5. Media Blossom uploads (100 MiB cap; 20 MiB on free servers), plaintext URLs E2E-encrypted images/media in-channel Filesharing verdict stands: neither is a Drive replacement (no folders/ACLs/versioning; the one folder app, Blossom Drive, is deprecated \u2014 Bouquet manages blobs only). Keep Drive; use the stack for community media and E2E chat attachments. Watch item: Ditto has no native DMs today (NIP-17 absent) and implements neither NIP-72 nor NIP-29 groups (roadmap). For private conversation, Armada is the answer; don't promise DM privacy on Ditto. 4. Runbook B \u2014 Funding on Agora When Agora: BTC-native donor base, censorship-resistance matters, zero platform fees matter, or client is an activist/civic org comfortable with crypto. When not: normie donors (no card checkout), US 501(c)(3) needing tax receipts (anonymous Silent-Payment gifts can't get IRS-compliant receipts \u2014 ch. 03), or discovery-dependent campaigns. Campaign creation is permissionless \u2014 any Nostr keypair; \"featured\" is curated (WLC/HRF human-rights positioning). Donations flow wallet-to-wallet on-chain BTC (incl. BIP-352 Silent Payments). Agora never holds funds; $0 platform fee; donor pays network fee. Lightning zaps exist in Agora only as social tipping, a separate rail from campaign donations \u2014 don't conflate them in client explanations. Publish campaign updates on Nostr; donations are publicly auditable (blockchain + Nostr) \u2014 a transparency feature for community orgs. Off-ramp is manual: raised BTC \u2192 exchange (KYC reappears there) \u2192 USD; plan the volatility window. Embedding: none. Shakespeare sites link out to the campaign; no widget exists (ch. 03). Zap-goal (NIP-75) integration unconfirmed. White-label: AGPL fork-and-run is feasible (static React/Vite, Docker) for a client's own campaign platform \u2014 publishes your mods per \u00a70. 5. Runbook C \u2014 Sites, funnels, mockups on Shakespeare Mockup economics (the agency loop): Lane Cost Use for Free Gemini Flash tier (promotional \u2014 verify live before quoting) $0 Volume first-pass mockups BYO API key, cheap model (e.g. GLM-class) Cents per mockup; Soapbox takes no cut Iteration rounds Local models (Ollama) $0 after hardware Offline/batch Paid NSP (MKStack + Claude Sonnet) Paid via Stripe/Lightning The deal that's closing Funnel wiring \u2014 what's native vs external: The trap: forms render with one prompt but there is no backend \u2014 where submissions land must be explicitly wired to an external service or they land nowhere (ch. 04). Payments are the inverse: Lightning/Cashu is genuinely native (Agora proves it in production); Stripe is the manual add. Deploy paths: free *.shakespeare.wtf for mockups \u2192 export ZIP/git (including nostr:// git URLs) \u2192 production on Netlify/Vercel/Cloudflare/Pages, or fully decentralized via nsite + Blossom (Stacks CLI). Custom domains observed live but no documented runbook \u2014 budget discovery time. Client caveat: no CMS/visual editor; whoever builds it owns the edits (a retainer surface \u2014 position it as such to a client). 6. Runbook D \u2014 Publishing on NostrHub 2.0 Log in via NIP-07 extension (\u00a72). Repo: create/mirror \u2192 signs a kind-30617 announcement \u2192 lives on a GRASP host (relay+git) \u2192 issues/PRs/browsing on NostrHub; the same repo is clonable via gitworkshop.dev/ngit (interop verified live \u2014 ch. 05). App: self-announce a kind-31990 NIP-89 handler event \u2014 no submission queue; community ratings accrue. Article/docs: kind-30023 markdown; your chosen experts' NIP-32 approvals drive per-viewer ranking (\"configurable meritocracy\"). Expectations: it is a credibility and discovery layer, not a growth channel \u2014 metadata only (no artifact hosting), no auto-propagation to Zapstore/nostrapps (list those separately). 7. Integration matrix From To Mechanism Enables Status Any product Identity Nostr keypair + NIP-07/46 signer One login everywhere Live Ditto 50+ Mastodon apps Mastodon API + bunker login Mobile clients day 1 Live Ditto Fediverse / Bluesky Mostr bridge (+Bridgy Fed) Cross-network reach Live (lag) Ditto/Armada Blossom servers BUD specs Swappable, mirrorable media Live Armada Public relays Concord gift-wrap (NIP-59) Serverless E2E ops Early (0.x) Shakespeare MKStack Generation target Nostr-native apps incl. Recharts, zaps Live Shakespeare site Agora Link-out only Campaign traffic Live (no embed) Shakespeare site Beehiiv/ManyChat/Cal.com/Stripe Prompted API wiring Real conversion funnel Manual Shakespeare/repos NostrHub kind 30617 / 31990 / 30023 Publishing + discovery Live NostrHub repo gitworkshop/ngit NIP-34 + GRASP Clone/PR from any NIP-34 client Verified Any app Wallets NIP-57 zaps, NIP-47 NWC, Cashu 60/61 Payments without processors Live Agent orchestrators Nostr jobs DVM pattern (kind registry; base NIP-90 deprecated) Paid agent job market Scout 8. Build opportunities DVM-shaped agent dispatch \u2014 the data-vending-machine pattern (post job \u2192 providers compete \u2192 paid in sats) is structurally identical to an internal agent-dispatch queue like dojoagentdispatch (ch. 06, worked example) \u2014 the maintainers use this shape today. A thin bridge would put any agent orchestrator on an open job market. Scout, not dependency. Ditto bots via Mastodon API \u2014 the entire Mastodon bot/tooling ecosystem works against a Ditto instance; cheapest automation surface in the stack. MCP \u2194 Nostr bridge \u2014 publish/read Nostr events as MCP tools (post, zap, fetch community signals); nothing found in the ecosystem occupying this niche. The bilingual mod layer itself (\u00a79.2) \u2014 first-mover OSS contribution with obvious upstream demand: Soapbox's own builder UI has no Spanish (ch. 08). Concord early expertise \u2014 protocol is 26 days old (CORD-01\u201307); early implementers get standing in whatever it becomes. 9. The TresPies modded-stack blueprint (steering direction, 2026-07-09) What follows is the maintainers' own integration plan, published as a worked example of wiring this stack into a real firm \u2014 adapt the shape, swap the specifics (a different niche, a different orchestrator, a different git-mirror target) for your own. Operator direction, verbatim: \"integrate this stack with cutting edge internationalization platforms and visualization platform components then we'll build a Tres Pies stack on the modded version and git anchor it all in Nostr, mirror it to Dojo Genesis Git.\" (internal: PIP-94). Phase gates below assume \u00a70's mod-layer rule is ratified first. 9.0 AI + orchestration layer (operator-specified 2026-07-09) Direction, verbatim: \"built featuring my dojo orchestration system and the providers of your choice: enterprise or TresPies or windsurf or cursor or whatever or Local: OpenRouter or Dojo Genesis.\" The build engine is Dojo orchestration (Gateway agent-dispatch + Claude Code sessions) driving generation against MKStack's AGENTS.md agent contract \u2014 348 lines at the template root, shipping with .mcp.json (Claude Code's own MCP config), opencode.json, and 19 skill files (ch. 10; note NIP.md is a different artifact \u2014 the NSP wire protocol in mkstack-nsp). Shakespeare becomes one optional front-end among several, not the required lane. All lanes target the same scaffold: Lane Driven by Models from When Enterprise Claude Code / direct API Anthropic enterprise (or the client's own) Client work with contract/compliance requirements TresPies-hosted Dojo Gateway dispatch TresPies keys House builds, POCs, batch generation IDE agents Windsurf / Cursor / \"whatever\" Their provider config Operator-in-the-loop editing sessions Local / routed Any agent OpenRouter or DojoGenesis Gateway (incl. local models) Cost-floor mockup volume, offline work Rule: no lane lock-in. The scaffold + AGENTS.md contract must build identically from every lane \u2014 the zero-lock-in founder veto applied to our own tooling. Ch. 10 confirms it: a raw clone is Claude Code-ready out of the box (AGENTS.md + .mcp.json + skills), local lanes impose no model provider, and only hosted Shakespeare and Stacks/Dork touch a Soapbox-rostered model list. The one unbuilt extension point: a Dojo-Gateway AI_PROVIDER adapter for a self-hosted mkstack-nsp (only OpenAI/OpenRouter adapters exist today \u2014 and a self-hosted NSP is AGPLv3, so modified server source must be published). 9.1 i18n integration (from ch. 08) Runtime: keep i18next/react-i18next \u2014 already proven inside this stack by Agora (16 locales, es at 99.96% parity). Fork Agora's src/i18n.ts pattern into the Ditto/Armada-derived base rather than importing a foreign architecture. Automation: layer Lingo.dev (Apache-2.0, CI-native AI-MT with glossary/brand-voice control) for machine passes; TresPies native-Spanish review stays the human gate. Gate: port the NS-style symmetric parity check into CI \u2014 Agora's existing gate fails only on extra keys, not missing ones; tighten it. Nostr layer: no ratified language NIP (Gleason's own NIP-37 closed unmerged; PR #1127 open) \u2014 adopt the de facto NIP-32 labels [\"L\",\"ISO-639-1\"] [\"l\",\"es\",\"ISO-639-1\"] for bilingual content now. Contribution play: Ditto and Armada have literally zero i18n today; Shakespeare's UI has no Spanish. A clean es layer is a visible, welcomed upstream contribution (and marketing). 9.2 Visualization integration (from ch. 09) Spec-layer rule: framework-agnostic engines (ECharts, MapLibre GL) bridge the React stack and Svelte house surfaces; framework-bound charts route per surface (Recharts inside Shakespeare/MKStack \u2014 it ships in the scaffold; LayerChart/unovis in Svelte dashboards). The Atlas pattern (zero-server): ACS/TIGER \u2192 Tippecanoe \u2192 PMTiles + Parquet on static hosting \u2192 MapLibre choropleths + DuckDB-WASM drill-down \u2192 bilingual labels via \u00a79.1 hooks. No origin server anywhere; deployable to Pages/R2 or nsite/Blossom. Tripwire: PMTiles needs HTTP range requests; Blossom's spec only recommends them \u2014 verify per Blossom server or default to Cloudflare R2 (documented Protomaps path). Position: no Nostr+census precedent found \u2014 an Atlas on this substrate is first-of-kind for the maintainers' \u00a71557/equity-data niche (swap in your own domain \u2014 the zero-server pattern doesn't care what the data is). 9.3 Git-anchor + mirror runbook Repo canonical home: GRASP host (relay + git server) with a kind-30617 announcement signed by the TresPies/DojoGenesis key (per repo). Add the GitHub mirror: git remote add github git@github.com:DojoGenesis/<repo>.git \u2014 gh auth switch --user DojoGenesis first (existing guard, enforced by hook). Push discipline: anchor push (ngit/GRASP) then mirror push; CI or a post-push hook keeps them in lockstep. nostr:// remotes are already supported by Shakespeare's git export (ch. 04). Issues/PRs: NIP-34 events \u2014 workable from NostrHub or gitworkshop.dev interchangeably (verified interop, ch. 05). What stays off the anchor: anything under IP gate or client NDA \u2014 Nostr announcements are public and permanent; private repos stay GitHub-only until the maintainers are ready to publish them (their standing practice for moving in-progress internal work into the open). The knowledge layer rides this rail (operator call, 2026-07-09): because the operating model keeps knowledge as markdown in git (manuals, notes, ADRs, the memory system with local autosync), git-over-Nostr IS the internal file layer for knowledge work \u2014 anchored, mirrored, versioned. This narrows \u00a71's \"keep Drive\" verdict to binary/office assets only (client spreadsheets, design files, video); md-native ops need no Drive. 9.4 Sequencing (30/60/90) and tripwires Window Moves Gate 0\u201330d Day-1 credentials (\u00a72) \u00b7 NIP-05 on your domain \u00b7 Shakespeare mockup lane in client workflow \u00b7 Armada internal pilot (low-stakes) \u00b7 ratify mod-layer rule Phase 1 (operator; internal: PIP-94) 30\u201360d i18n fork: Agora pattern \u2192 Ditto base + Lingo.dev CI + symmetric gate \u00b7 first repo git-anchored + DojoGenesis-mirrored \u00b7 NostrHub presence (repo + article) Parity gate green 60\u201390d Atlas-pattern reference dashboard (PMTiles static) \u00b7 Ditto community soft launch (bridged) \u00b7 evaluate Agora campaign for a real client cause \u00b7 upstream the es layer First-of-kind demo live Tripwires: Armada security audit status (none yet \u2014 recheck before widening pilot) \u00b7 Shakespeare free-tier lapse (promotional, no end date) \u00b7 Soapbox grant renewals (their existential risk, ch. 01) \u00b7 Blossom range-request support (per-server) \u00b7 Concord protocol churn (already v1\u2192v2 in 26 days). 10. Consolidated open questions Highest-value unknowns across chapters (each chapter lists its own in full): Armada arbitrary-file attachments and audit roadmap (02) \u00b7 Agora NIP-75 zap-goal use and Forbes/AP coverage verification (03) \u00b7 Shakespeare custom-domain runbook and free-tier durability (04) \u00b7 NostrHub DVM-marketplace status in 2.0 and license file (05) \u00b7 Agora zap-vs-donation edge mechanics (03/06) \u00b7 whether Soapbox would accept an es upstream contribution PR promptly (08 \u2014 ask them directly; they're reachable on their own products)."
    },
    {
      "id": "manual/08-i18n-integration",
      "kind": "manual",
      "lang": "en",
      "title": "08 \u2014 i18n Integration: Localization Platforms \u00d7 the Soapbox Stack",
      "url": "/manual/#ch08",
      "md_url": "/manual/md/08-i18n-integration.md",
      "sha256": "6e569e7e4f1951a895b3ced54dd62a9d4f5d73a433d6dc6892461f23a7441778",
      "bytes": 24744,
      "headings": [
        "1. The 2026 Landscape \u2014 Legacy TMS vs. AI/Agent-Native",
        "2. Stack i18n Readiness \u2014 Repo-Verified",
        "3. Integration Architecture for a Modded TresPies Fork",
        "4. Nostr-Layer i18n Gaps \u2014 No Ratified Standard",
        "5. Recommendation",
        "Open Questions",
        "Sources"
      ],
      "body": "Where a modded, bilingual TresPies fork would actually plug in \u2014 verified against the real Ditto, Armada, Agora, and Shakespeare/MKStack repos, not just their marketing pages. The tool landscape and stack-readiness research below (\u00a71, \u00a72, \u00a74, and the comparison table in \u00a75) apply to any team evaluating this stack for localization. \u00a73 and the adoption runbook in \u00a75 are the maintainers' own integration plan for their bilingual fork \u2014 a worked example of wiring a parity gate into a real firm; adapt the shape, swap the specifics for your own. Verified: 2026-07-09 Confidence: High for stack-readiness facts (all four products' actual GitLab repos fetched \u2014 package.json, locale files, router code, AGENTS.md \u2014 not inferred from docs). High for the Nostr language-tagging verdict (both proposal PRs fetched directly, states confirmed). Medium for the landscape/tool comparison (aggregated from current search results, not independent primary-source fetches of every vendor). Medium-Low for cost figures, which move fast and weren't independently re-verified per vendor. 1. The 2026 Landscape \u2014 Legacy TMS vs. AI/Agent-Native The field has split into two generations: TMSes built for a human-translator queue, and a newer layer built to sit inside a git repo and a CI pipeline with an LLM doing the first pass. Tool Category License Agent/CI-native? What's distinctive inlang / Paraglide-JS Compiler-based i18n library + ecosystem (Fink editor, Sherlock VS Code extension) MIT [1] Yes \u2014 git-native message files, Sherlock gives inline IDE translation, Fink lets a translator edit without cloning Compiles to tree-shaken per-message functions; up to 70% smaller i18n bundles than runtime libraries [1] Lingo.dev \"Localization engineering platform\" \u2014 compiler + CLI + CI Action Apache-2.0 [2] Yes, explicitly \u2014 GitHub Actions/GitLab CI/Bitbucket Pipelines trigger translation on every push, PRs come back with localized strings [2] Stateful \"localization engines\": glossary + brand-voice rules + per-locale model chains + AI quality scoring, configured once [2] Tolgee Self-hostable TMS, developer-first Apache-2.0 core; Enterprise features dual-licensed (ee/ dir) [3] Partial \u2014 strong git/CI integration and in-context editing, but built around a hosted/self-hosted web app, not a pure CLI In-context editing (click text on the live page to translate it); native React/Vue/Next SDKs [4] Weblate Self-hostable TMS, translator-first GPL-3.0 Partial \u2014 mature git integration (its core design), but workflow center-of-gravity is a translator UI, not agent-driven Oldest and most battle-tested OSS TMS (2012); the safe, boring choice [4] Crowdin / Lokalise / Phrase Incumbent SaaS TMS Proprietary Increasingly \u2014 Crowdin now brands \"AI-powered localization,\" 700+ integrations Deepest integration catalogs (Figma, Slack, Jira); enterprise support; no self-host on the free tiers [4] i18next / react-i18next Runtime i18n library MIT Neutral \u2014 it's a library, not a pipeline; agent-nativeness depends on what you wire around it Largest ecosystem, browser + Node, non-ICU key format; already running in this exact stack (\u00a72) FormatJS / react-intl Runtime i18n library, ICU-strict BSD-3 Neutral Built on the browser's native Intl API; best when translators already work in ICU MessageFormat [5] LinguiJS Compiler-based i18n library MIT Neutral, but compiler step fits a CI pipeline cleanly Smallest bundle (~3KB core vs. i18next's ~8-20KB) [5]; PO-file extraction, co-located messages What's genuinely cutting-edge mid-2026: the AI-MT layer, not the runtime library. REPORTED across multiple vendor blogs: the current pattern is glossary + brand-voice-trained LLM + \"quality-based routing\" that scores each translated segment and only escalates the weak ones to a human editor, rather than a human reviewing every string [6]. Lingo.dev and Crowdin both ship this; inlang's ecosystem (Fink/Sherlock) is compiler-and-editor-native rather than AI-MT-native \u2014 it assumes a human or an external MT step fills the message files. Confidence: Medium \u2014 landscape claims are aggregated from current comparison articles and vendor pages, not independently fetched primary text for every row. 2. Stack i18n Readiness \u2014 Repo-Verified Fetched each product's actual GitLab tree, package.json, and (where present) locale files and routing code. This is the load-bearing section \u2014 no marketing-page claims below. Product Repo i18n library in package.json Locales shipped Spanish? Evidence Ditto soapbox-pub/ditto none none No No i18n/intl/locale dependency among 155 deps; src/ has no locale directory [7] Armada soapbox-pub/armada none none No Same check, 99 deps, zero hits; repo genuinely skeletal (concord-v1/concord-v2 protocol dirs, no locale dir) [8] Agora soapbox-pub/agora i18next 26.0.5, react-i18next 17.0.4, i18next-browser-languagedetector 8.2.1 16: en, es, ar, fa, fr, hi, id, km, ps, pt, ru, sn, sw, tr, zh, zh-Hant Yes \u2014 2,401 of 2,402 keys (99.96%) src/i18n.ts, src/locales/*.json fetched directly; keys diffed programmatically [9] Shakespeare (builder UI) soapbox-pub/shakespeare i18next 25.5.2, react-i18next 15.7.3 6: en, ha (Hausa), ig (Igbo), pt, yo (Yoruba), zh No src/locales/ listed directly; 574 leaf keys in en.json [10] MKStack template / scaffold inferred from soapbox-pub/soapbox.pub (package name is literally \"mkstack\") + mkstack-nsp's NIP.md spec none none No Zero i18n deps in the marketing site's package.json; the 1,085-line \"Nostr SPA Builder\" spec that governs what gets scaffolded contains zero mentions of language/locale/i18n [11][12] Agora is the reference implementation, and it's better than a generic tutorial pattern. Its src/i18n.ts bundles only English eagerly (sync, no flash of untranslated content) and lazy-loads every other locale as its own Vite chunk on selection or detection \u2014 REPORTED as saving roughly 2MB off the initial bundle, DOCUMENTED directly in the code's own comments: \"Only English is bundled eagerly. Every other locale is loaded on demand via a dynamic import()\" [9] It also handles RTL languages (ar, fa, ps, +4 more) by flipping document.dir and relying on Tailwind's rtl: variant, and resolves region/script variants (pt-BR\u2192pt, zh-TW/zh-HK\u2192zh-Hant) to the right JSON chunk. Agora already runs a parity gate \u2014 looser than the maintainers' own TresPies standard. Its AGENTS.md (written for AI coding agents working in the repo) states: \"src/test/locales.test.ts fails the build if any locale ships a key that doesn't exist in en.json, but the inverse (a key missing from a non-English locale) is allowed and falls back to English at runtime\" [13] That's an asymmetric gate (blocks drift one direction, tolerates it the other) \u2014 looser than the maintainers' existing same-commit EN+ES parity rule. The same file also instructs agents to work the way the maintainers' own workspace already works: \"dispatch the per-language edits to subagents in parallel rather than translating fifteen files sequentially\" [13] Confidence: High \u2014 every figure above came from a direct fetch of the file in question, not a changelog or blog post. 3. Integration Architecture for a Modded TresPies Fork Locale routing on static hosting \u2014 three options, one clear default: Pattern How it works Static-host fit Verdict for this stack Client-side detection, no URL segmentation Browser Accept-Language + localStorage pick the locale; one bundle, one URL for every language Perfect \u2014 this is what Agora ships today [9][14] Recommended default. Zero extra deploy complexity, proven in-family Path-prefix routing (/es/...) React Router locale segment; still one SPA bundle Works if the host does SPA-fallback (serves index.html for unmatched paths) \u2014 true of Cloudflare Pages, Vercel, Netlify, and nsite/Blossom gateway resolution alike Only worth it for SEO \u2014 a static Nostr SPA behind client-rendered content gets little SEO value from this today Separate nsite deployment per locale A named nsite (kind 35128, d tag = locale code) resolves to its own subdomain, independent of the root site (kind 15128 = npub-only) [15] Fully supported \u2014 this is exactly what Agora's own nsiteSubdomain.ts implements for named sites in general [15] Reserve for a fully independent censorship-resistant Spanish-language mirror, not routine bilingual support Typography/formatting for es: use the web-standard Intl API rather than hand-rolled formatting \u2014 Intl.DateTimeFormat('es', \u2026), Intl.NumberFormat('es', \u2026) (decimal comma, currency placement), and Intl.PluralRules('es') for the two-form (singular/plural) Spanish plural system, simpler than languages Agora already handles (Arabic has six plural forms). i18next's ICU/plural plugin and FormatJS both wrap this natively; nothing custom is needed. (Confidence: High \u2014 this is stable web-platform behavior, not a Soapbox-specific claim.) On Shakespeare specifically \u2014 can you prompt it to generate a bilingual site? The MKStack scaffold has no i18n opinion baked in (\u00a72), so yes, but the AI has to be told the pattern explicitly rather than reaching for a convention. INFERRED, practical recommendation: paste Agora's src/i18n.ts as a reference into the Shakespeare chat and ask it to replicate the lazy-load + detection pattern with en+es locale files \u2014 this reuses a pattern proven inside the same company's own product family rather than inventing one per generated site. Confidence: Medium \u2014 the pipeline and routing recommendations synthesize DOCUMENTED repo evidence with INFERRED architectural judgment; flagged inline above. 4. Nostr-Layer i18n Gaps \u2014 No Ratified Standard Verdict: there is no ratified NIP for natural-language content tagging. Two proposals exist; neither merged. Proposal Author Status What it would have added NIP-37 \"Language Tag\" Alex Gleason \u2014 the Soapbox/Ditto founder himself [16] Closed, unmerged, 2024-06-07 A dedicated lang tag on text events NIP-XXX \"Internationalization and Localization\" (PR #1127) eznix86 Still open, last activity 2026-03-04, unmerged l-tag language marking plus a kind:0 (profile) language field NIP-32 Labeling (ratified, general-purpose) \u2014 Ratified, in production use The de facto working pattern: [\"L\",\"ISO-639-1\"], [\"l\",\"en\",\"ISO-639-1\"] \u2014 a spec example states plainly, \"Author is labeling their note language as English using ISO-639-1\" [17] NIP-50 Search \u2014 Ratified Search-time filter only: language:<two-letter ISO 639-1 code> [18] NIP-C0 Code Snippets \u2014 Ratified Also uses an l tag \u2014 but for programming language (\"javascript\", \"python\"), a different namespace. Don't confuse the two l tags across NIPs [19] Even Soapbox's own founder couldn't get a dedicated language tag ratified. The reason it stalled, DOCUMENTED verbatim from the PR thread: \"I think users can't be trusted to specify this tag correctly and all automatic translation tools will already detect the language automatically anyway.\" [16] Practical patterns for bilingual posting, given no standard: (a) dual posts \u2014 publish separate EN and ES events, each self-labeled via NIP-32's l/L tags, letting language-aware clients filter; (b) inline-both \u2014 one event containing both languages in the body, which sidesteps tagging entirely but degrades UX and can't be filtered; (c) per-language accounts \u2014 separate npubs per language, cleanest for filtering but fragments the identity (see the org-account tension already documented in chapter 06 [20]). What clients actually render: most Nostr clients show the raw event content regardless of any l tag present \u2014 language tags are a filtering/search signal, not a rendering instruction, so a bilingual post still displays as one undifferentiated block unless the client explicitly builds a language switcher around it. No evidence found of any major client (Ditto included) doing that today. Confidence: High on the ratification status (both PRs fetched directly, states unambiguous); Medium on \"what clients actually render,\" which is a general-knowledge claim not independently verified against every client's source in this session. 5. Recommendation Platform License OSS/AGPL fork fit Agent/CI automatable EN\u2194ES quality + glossary Static-host fit Cost @ small team i18next + react-i18next MIT Excellent \u2014 already MIT, already living inside an AGPL-3.0 app (Agora) [9] Neutral (library, not a pipeline) Depends entirely on what feeds it Excellent \u2014 proven in this exact stack Free (library only) Lingo.dev Apache-2.0 Excellent \u2014 Apache-2.0 is GPLv3/AGPLv3-compatible [2] Best-in-class \u2014 CLI + CI Action is the point [2] Strong \u2014 glossary + brand-voice + quality scoring built in [2] Compiler targets Vite/Next; framework-agnostic CLI works with any static build Usage-based; free/OSS tier for the CLI itself inlang / Paraglide-JS MIT Excellent Good \u2014 Sherlock/Fink are git-native, but no AI-MT layer of its own None built-in \u2014 bring your own MT Excellent \u2014 compiles to a static bundle by design Free (self-hosted message files) Tolgee Apache-2.0 core Good \u2014 core is Apache-2.0; EE features are dual-licensed [3] Good \u2014 strong git/CI hooks, but centered on a hosted app Good \u2014 in-context editing aids human review Good Free self-host tier (\u226410 seats) [3] Weblate GPL-3.0 Good \u2014 copyleft-native, philosophically closest to AGPL Fair \u2014 mature git integration, translator-UI center of gravity Good, human-review-first Good Free (self-hosted) Crowdin Proprietary Poor \u2014 can't live inside a published AGPL fork Good \u2014 many integrations Strong \u2014 mature AI-MT + QA Good No self-host on entry tiers LinguiJS MIT Excellent Good \u2014 compiler step fits CI None built-in Excellent \u2014 smallest bundle Free Ranked recommendation: don't replace the runtime \u2014 extend it. i18next/react-i18next stays (it's already MIT, already proven inside an AGPL-3.0 Soapbox product, and copying Agora's src/i18n.ts into Ditto/Armada is near-zero migration cost). Add Lingo.dev as the AI-MT + CI automation layer on top \u2014 it's the one tool on this list built specifically to sit in a CI pipeline with a glossary and brand-voice config, which is exactly the \"cutting-edge\" piece the current stack is missing. Skip a new TMS platform for now \u2014 tightening Agora's existing (asymmetric) locales.test.ts into a symmetric same-commit gate gets the maintainers' existing discipline without adopting Tolgee/Weblate's operational overhead; revisit if the team scales past ad hoc PR review. 5-step adoption runbook: Fork Agora's src/i18n.ts + src/locales/en.json pattern into the Ditto/Armada-derived TresPies base \u2014 proven, in-family, zero new dependencies to evaluate. Stand up Lingo.dev: one i18n.json config pointing at src/locales/en.json, TresPies glossary + brand-voice rules configured once, CI Action wired to GitHub/GitLab so every push opens a translated-string PR. Tighten the parity gate \u2014 extend the locales.test.ts pattern to fail the build on missing keys too, not just extra ones, matching the existing TresPies same-commit EN+ES rule. Route every AI-MT'd PR through native-Spanish human review before merge \u2014 the existing TresPies review culture, unchanged; Lingo.dev's human-in-the-loop review surface can host this or a plain PR review works equally well. Deploy with client-side detection only (Agora's pattern) as the default; treat a separate nsite named-site (d-tag = es) as an optional later add-on, not a day-one requirement. Confidence: Medium-High \u2014 the runtime/parity-gate recommendation is grounded in verified repo evidence; the Lingo.dev pick is grounded in documented product capability but not independently load-tested by this research. Open Questions Whether Lingo.dev's Vite compiler mode has been used in production with a Nostrify/@nostrify/react app specifically \u2014 no direct evidence found either way, worth a small spike before committing. Whether any Nostr client (Ditto or otherwise) actually reads NIP-32 l/L language tags to drive a UI language filter today, versus the tag existing in the spec but going unused in practice \u2014 not independently verified against client source code this session. Current status/adoption of eznix86's open i18n/l10n NIP proposal (#1127) beyond \"still open as of 2026-03\" \u2014 worth re-checking periodically since it's the only active path toward a ratified standard. Exact current pricing tiers for Lingo.dev at TresPies' likely usage volume \u2014 REPORTED as \"usage-based\" with an OSS/free CLI tier, but exact thresholds weren't independently priced out this session. Whether Shakespeare's AI model has actual training exposure to Agora's src/i18n.ts (same company, public repo) versus needing the pattern pasted in manually every time \u2014 untested this session. Sources inlang \u2014 Localization Tools; opral/paraglide-js (GitHub); Paraglide JS \u2014 inlang \u2014 accessed 2026-07-09 \u2014 MIT license, compiler architecture, bundle-size claim, Fink/Sherlock roles. Lingo.dev; lingodotdev/lingo.dev (GitHub); Lingo.dev CLI \u2014 How it works; Lingo.dev Compiler \u2014 Advanced Configuration \u2014 accessed 2026-07-09 \u2014 Apache-2.0 license, CLI/CI/compiler mechanics, glossary/brand-voice/quality-scoring \"localization engine\" model. Tolgee \u2014 Why open-source; Tolgee \u2014 Self-hosting Licensing; Tolgee EE License FAQ \u2014 accessed 2026-07-09 \u2014 Apache-2.0 core + dual-licensed EE features, free self-host seat limits. Open-Source TMS Comparison 2026: Weblate vs Tolgee vs Pontoon \u2014 IntlPull \u2014 accessed 2026-07-09 \u2014 Weblate/Tolgee positioning, Crowdin integration-count claim, git-vs-translator-UI framing. React i18n in 2026: react-intl vs i18next vs LinguiJS \u2014 auto18n; Best React i18n Libraries in 2026 \u2014 Tolgee \u2014 accessed 2026-07-09 \u2014 bundle-size comparison, extraction-method comparison, ICU-strictness framing. AI Localization in 2026: Engine, Review, Collaboration \u2014 Prismy; AI Localization: Automating Content Workflows \u2014 Crowdin Blog; How enterprise teams automate localization with AI \u2014 Smartling \u2014 accessed 2026-07-09 \u2014 glossary/brand-voice/quality-routing AI-MT workflow pattern. gitlab.com/soapbox-pub/ditto \u2014 package.json and src/ tree fetched directly via GitLab API 2026-07-09 \u2014 155 deps, zero i18n-related packages, no locale directory; React 19.2.4/Vite 8/Tailwind/Nostrify confirmed. gitlab.com/soapbox-pub/armada \u2014 package.json and src/ tree fetched directly 2026-07-09 \u2014 99 deps, zero i18n packages, concord-v1/concord-v2 protocol dirs present, no locale directory. gitlab.com/soapbox-pub/agora \u2014 package.json, src/i18n.ts, and src/locales/{en,es}.json fetched directly 2026-07-09 \u2014 i18next stack confirmed, 16 locales, 2,401/2,402 key parity computed programmatically, lazy-chunk architecture read from source comments. gitlab.com/soapbox-pub/shakespeare \u2014 package.json and src/locales/ tree fetched directly 2026-07-09 \u2014 i18next stack confirmed, 6 locales (en/ha/ig/pt/yo/zh, no es), 574 leaf keys in en.json. gitlab.com/soapbox-pub/soapbox.pub \u2014 package.json (name: \"mkstack\") fetched directly 2026-07-09 \u2014 zero i18n deps, no locale directory in src/. gitlab.com/soapbox-pub/mkstack-nsp \u2014 README.md, CONTEXT.md, NIP.md fetched directly 2026-07-09 \u2014 NSP/Deno architecture, CLONE_URL-configurable base template, zero language/locale/i18n mentions across the 1,085-line spec. gitlab.com/soapbox-pub/agora \u2014 AGENTS.md \u2014 accessed 2026-07-09 \u2014 verbatim parity-gate behavior and agent-parallelization instruction for translation work. gitlab.com/soapbox-pub/agora \u2014 AppRouter.tsx \u2014 accessed 2026-07-09 \u2014 confirmed no path-prefix locale routing exists; only a /settings/language settings page. gitlab.com/soapbox-pub/agora \u2014 src/lib/nsiteSubdomain.ts \u2014 accessed 2026-07-09 \u2014 NIP-5A subdomain derivation for root (kind 15128) vs. named (kind 35128, d-tag) nsite events, corroborating chapter 06's nsite citation. NIP-37: Language Tag (PR #632) \u2014 accessed 2026-07-09 \u2014 author Alex Gleason, closed unmerged 2024-06-07, verbatim fiatjaf objection quote. NIP-32: Labeling \u2014 accessed 2026-07-09 \u2014 verbatim ISO-639-1 language-labeling example. NIP-50: Search Capability \u2014 accessed 2026-07-09 \u2014 language:<ISO 639-1> search filter extension. NIP-C0: Code Snippets \u2014 accessed 2026-07-09 \u2014 confirms the l tag here means programming language, a distinct namespace from natural-language tagging. NIP-XXX: Internationalization and Localization (PR #1127) \u2014 accessed 2026-07-09 \u2014 author eznix86, still open, last activity 2026-03-04, unmerged; proposes l-tag plus kind:0 language field."
    },
    {
      "id": "manual/09-visualization-integration",
      "kind": "manual",
      "lang": "en",
      "title": "Visualization Integration \u2014 Charting and Mapping Across the Soapbox Stack",
      "url": "/manual/#ch09",
      "md_url": "/manual/md/09-visualization-integration.md",
      "sha256": "e90210e24a73d623fae3e95601b8cfaa0f90d961ac1bc93e2b7029079e50073b",
      "bytes": 26744,
      "headings": [
        "1. The 2026 Landscape",
        "2. Embedding in the Stack",
        "3. The Atlas Pattern \u2014 Reference Architecture",
        "4. Framework Tension \u2014 React vs. Svelte 5",
        "5. Recommendation",
        "Open Questions",
        "Sources"
      ],
      "body": "Where interactive charts and census-scale maps can actually live across Shakespeare, Ditto, Blossom/nsite, and Nostr long-form content \u2014 and the reference pattern for building an Atlas-class dashboard on top of it, with zero origin servers. Verified: 2026-07-09 Confidence: High for the landscape survey, licensing, and the Shakespeare/MKStack embedding answer (a live dependency-manifest fetch is primary evidence). Medium-High for the static/Blossom-hosting and Nostr long-form answers (protocol specs are primary and quoted verbatim, but real-world server behavior varies). Medium for Ditto's embedding ceiling (no widget/plugin doc was found across two source sweeps \u2014 an absence, not a documented \"no\"). Medium for the Atlas reference architecture itself: every component is independently well-sourced, but no live Nostr-stack census/civic-data project was found to validate the combination end-to-end \u2014 this pattern is this chapter's synthesis, not a Soapbox playbook. 1. The 2026 Landscape Tool Category License 2026 status Fit note Observable Framework + Plot Static-site generator + grammar-of-graphics charting ISC (D3 family) Active; data loaders run at build time in any language and can shell out to binaries like DuckDB or ffmpeg [1][2][3] Best match for a build-time, zero-server report/dashboard D3 Low-level rendering primitives ISC Foundational substrate \u2014 Plot, Vega, Nivo, and visx all sit on it [4] Rarely hand-written now; used as a base layer Apache ECharts Full chart + geo + 3D framework Apache 2.0 Highest adoption of any JS-native chart lib by a wide margin; weekly npm downloads in the millions vs. Vega-Lite's low hundreds of thousands [5] Broadest single-library feature set, including a native geo/map chart type Vega-Lite Declarative JSON chart grammar BSD-3 Active; strongest in Jupyter/Python (Altair) exploratory workflows [6] Good AI-generation target (compact spec), weaker as a production UI polish layer deck.gl + MapLibre GL JS WebGL geo layers + vector-tile map engine MIT (deck.gl) / BSD-3 (MapLibre) deck.gl v9 lives under the OpenJS Foundation's Open Visualization space [7][9]; MapLibre is the Linux-Foundation-incubated fork of Mapbox GL JS from its Dec-2020 license change [10] The map-heavy pairing; deck.gl's MapboxOverlay syncs its WebGL layers to MapLibre's camera exactly [7] React layer \u2014 Recharts / visx / Nivo / Tremor Chart components All MIT Recharts v3 is current; Tremor was fully open-sourced (incl. its paid \"Blocks\") when Vercel acquired it in Jan 2025 [11][12][13][41] Recharts is also shadcn/ui's own official chart primitive [14] Svelte \u2014 LayerChart / unovis Chart components MIT Both confirmed Svelte-5-compatible [15][16] Smaller ecosystem/training-data footprint than the React equivalents evidence.dev SQL + Markdown \u2192 static BI site MIT Active, DuckDB-powered, now ships its own in-browser AI dev agent [17] Closest single-tool match to \"Atlas as a reproducible, versioned report\" AI-assisted generation Practice, not a library n/a LLMs default to Recharts or Chart.js when asked for a React chart [21]; Microsoft's Data Formulator 0.7 (2026) adds an iterative AI chart-authoring workspace [20]; MapLibre ships a dedicated agent-skills repo for AI coding tools [22][23] Prompted generation is a first-class path now, not a novelty \u2014 see \u00a75 Confidence: High \u2014 every cell above traces to a primary repo/license file or a 2026-dated comparison source. 2. Embedding in the Stack The one fact that resolves most of this section: the MKStack template that Shakespeare scaffolds already depends on Recharts. A live fetch of its package.json shows React 19.2.5, Vite 8.0.10, Tailwind CSS v4.2.4, and Recharts v3.8.1 as a first-class dependency, alongside Radix UI, TanStack Query, and Nostrify [18]. A secondary write-up describes MKStack as \"React 18.x... TailwindCSS 3.x\" [43] \u2014 that's stale against the live manifest; treat any secondary MKStack description as provisional and re-fetch before quoting a client. Surface Interactive charts/maps? Mechanism Ceiling (a) Shakespeare-generated sites Yes Recharts is already in the dependency tree \u2014 prompt Shakespeare directly for a chart or dashboard page and it composes from an installed library, not a cold start [18] Full client-side React chart; a live database view needs an external API wired in by prompt, same as any Shakespeare funnel gap (see this manual's Shakespeare chapter) (b) Static/Blossom/nsite hosting Yes, client-side only Any JS chart/map library runs fine as static assets; maps need PMTiles (below) No server-side rendering, no live query API, no request-time database \u2014 everything must be precomputed at build time or fetched from a separate hosted service (c) Ditto communities No native widget/embed surface found (inferred \u2014 absence across two doc sweeps, not a stated \"no\") Ditto's own customization docs describe only theme CSS tokens (9 presets, 19 tokens) and \"add new features... completely redesign the UI to fit your wants and dreams\" via forking the React source with Shakespeare [28][29] Getting a chart into Ditto means editing Ditto's own React+Vite frontend directly \u2014 not a drop-in widget slot (d) Nostr long-form (kind 30023) No NIP-23 is explicit: \"MUST NOT support adding HTML to Markdown\" [24]. The only visual hook is the optional image tag, \"a URL pointing to an image to be shown along with the title\" [24][25] A chart in a 30023 article can only be a static exported image, or prose linking out to a hosted interactive page \u2014 never an inline embed On (b), the fine print that matters for the Atlas pattern: nsite maps file paths to content via Nostr kind 34128 events (d tag = path, sha256 tag = content hash), storing raw bytes on Blossom servers; the spec is explicit that this is for \"a simple application that doesn't use a backend\" [26]. Blossom's own BUD-01 spec requires CORS \u2014 \"Servers MUST set the Access-Control-Allow-Origin:  header on all responses\" \u2014 but only recommends* byte-range support: \"servers should support range requests (RFC 7233 section 3)\" [27]. That word \"should\" is load-bearing: PMTiles depends on range requests to work at all, so a given Blossom server may or may not serve a census-scale map efficiently \u2014 verify per-server before committing production tiles to nsite (see Open Questions). Confidence: High for (a) and (d) \u2014 primary manifest and primary spec text. Medium-High for (b) \u2014 primary specs, but real-server range-support behavior is untested here. Medium for (c) \u2014 a documented absence, not a documented limit. 3. The Atlas Pattern \u2014 Reference Architecture A census/ACS dashboard (Equity Atlas-class: county\u2192tract drill-down, choropleth fill, bilingual labels) fits this stack only as a build-time-baked, fully static app. No component in the pipeline below needs an origin server at request time. Build runbook: Pull ACS 5-year variables and TIGER/Line geometry (county, tract) via the Census API, tidycensus/tigris (R), or cenpy (Python). Join ACS attributes to geometry; export the attribute table only (no geometry) to Parquet for the DuckDB-WASM/pre-aggregation path. Convert geometry to GeoJSON, then to PMTiles with Tippecanoe (v2.17+ writes PMTiles directly) \u2014 e.g. tippecanoe -zg -o tracts.pmtiles -l tracts tracts.geojson \u2014 tuning min/max zoom for the state\u2192county\u2192tract drill-down [30]. A documented precedent exists at this exact scale: a 650,000-plus-feature Texas census-block PMTiles build via Tippecanoe [31]. Precompute heavy rollups (state/county summaries) as static JSON at build time \u2014 an Observable Framework data loader or a plain build script both work [1][2]. Host PMTiles + JSON + Parquet as static assets. Cloudflare R2/Pages is the verified-safe default: Protomaps documents a direct Cloudflare integration [35], though a stock Cloudflare CDN path has been reported to corrupt PMTiles' byte-range responses unless served through a Worker or R2 directly [37] \u2014 configure CORS to allow the range and if-match headers explicitly [36]. nsite+Blossom is reachable but its range-request support is a spec-level \"should,\" not a guarantee (\u00a72) \u2014 pilot it, don't default to it for production tiles. Render with MapLibre GL JS plus the pmtiles:// protocol handler; add a choropleth fill layer keyed to the joined ACS variable. Wire drill-down as client-side view state: zoom/tap swaps the active PMTiles zoom range and re-queries either the in-browser DuckDB-WASM Parquet or the pre-aggregated JSON for the side panel. Hook the bilingual layer at two boundaries only \u2014 the component string table, and the Intl.NumberFormat/Intl.DateTimeFormat call for chart ticks and tooltips \u2014 full locale-file strategy is the parallel i18n chapter's job, not this one's. Ship the frontend as a static build \u2014 React via Shakespeare/MKStack, or a standalone Svelte 5 app \u2014 to Cloudflare Pages, GitHub Pages, or nsite. No origin server exists anywhere in this stack. Before first paint in production, curl -I the tile host and confirm accept-ranges: bytes and access-control-allow-origin are actually present \u2014 MapLibre degrades silently (slow, not broken) when range requests aren't honored. Confidence: High on each individual component (Tippecanoe, PMTiles, MapLibre, DuckDB-WASM are all independently well-documented). Medium on the architecture as a combination \u2014 no Nostr-stack precedent for census/civic-data work was found in this pass; TresPies would be first-of-kind here. 4. Framework Tension \u2014 React vs. Svelte 5 Surface Framework Why Shakespeare/MKStack-generated funnel or community site React (follow the stack) MKStack's scaffolding is React 19 + Vite + Recharts already installed [18]; hand-rewriting it in Svelte defeats the reason to use Shakespeare at all Ditto community customization React (follow the stack) Ditto's own frontend is React 18+Vite (per this manual's Community Ops chapter); \"beyond themes\" customization means editing that codebase directly Standalone dashboards (dash.trespies.dev, an Equity Atlas build) Svelte 5 (house standard) No Soapbox/MKStack dependency exists here \u2014 it's the maintainers' own infra and build, so their house Svelte 5 convention (documented in their own project-instructions file) applies without conflict Shared spec layer across both Framework-agnostic libraries ECharts, Vega-Lite, Observable Plot, and MapLibre GL JS all render from a plain JS/JSON call, not a component tree \u2014 the same chart option object or map style can be wrapped by a thin React shell in a Shakespeare output and a thin Svelte shell in a standalone build Recommendation: treat ECharts (general charts) and MapLibre GL JS (maps) as the portable spec layer \u2014 write the chart option / map style once, wrap it twice. Use Recharts/shadcn charts only inside Shakespeare-generated React surfaces, where it's already a zero-cost dependency [14][18]. Use LayerChart/unovis only inside standalone Svelte 5 builds. Never hand-port Recharts JSX into Svelte or vice versa \u2014 re-point the same underlying option object instead; that's the actual reuse boundary, not the component code. Confidence: High \u2014 grounded directly in the fetched MKStack manifest, this manual's own prior Ditto/Agora architecture findings, and the maintainers' own standing Svelte 5 convention. 5. Recommendation Option Map-heavy equity-data fit Static-host compatible Bilingual labeling AI/agent generatable Bundle weight License MapLibre GL JS + PMTiles High \u2014 purpose-built vector-tile map engine High \u2014 confirmed GitHub Pages/R2 patterns [30][35] Medium \u2014 labels are app strings, not lib-native High \u2014 dedicated agent-skills repo exists [22][23] Medium (~200KB core + separate tile files) BSD-3 [10] deck.gl High \u2014 WebGL layers for large point/polygon counts High \u2014 client-only, syncs to MapLibre's camera [7] Medium \u2014 same as above Medium \u2014 general WebGL/React knowledge, no dedicated skill repo found Heavy (full WebGL2 stack) MIT, OpenJS/vis.gl [9] Apache ECharts Medium-High \u2014 native geo/map chart type, less GIS-purpose-built than MapLibre High \u2014 pure client JS, no build step required Medium \u2014 locale config exists, set manually High \u2014 huge training corpus, framework-agnostic Medium (~1MB full; tree-shakeable) Apache 2.0 [5] Observable Plot / Framework Medium \u2014 has a geo mark [32][33], not a full interactive map engine High \u2014 Framework is a static-site generator [1] Medium \u2014 build-time loaders can bake per-locale files Medium-High \u2014 concise grammar is a good LLM target Light (Plot) / build-tool (Framework) ISC Recharts (via shadcn/ui) Low \u2014 no native geo support High \u2014 pure client bundle Medium \u2014 standard React i18n patterns apply High \u2014 MKStack ships it by default; Claude/LLMs default to it for React asks [18][21] Light (~150\u2013290KB) MIT LayerChart / unovis (Svelte) Low (LayerChart) / Medium (unovis has map primitives) High \u2014 pure client bundle Medium Medium \u2014 smaller training-data footprint than React libs Light MIT evidence.dev Medium \u2014 SQL-first framework, not GIS-first High for output; build step needs Node + a real DB connection Low \u2014 not a localization-focused tool Medium \u2014 ships its own AI dev agent in-IDE [17] N/A (full framework, not a component) MIT DuckDB-WASM (data layer, not a chart lib) Enabling \u2014 pairs with any option above High \u2014 the mechanism that makes \"static yet queryable\" possible [38] N/A Medium Heavy (~33MB wasm binary) [39] MIT [40] Ranked pick: MapLibre GL JS + PMTiles \u2014 the map layer, non-negotiable for anything Atlas-shaped. Apache ECharts \u2014 the general chart layer: framework-agnostic, highest-adoption, one spec reusable across the React and Svelte shells in \u00a74. Recharts (shadcn) inside Shakespeare/MKStack surfaces; LayerChart/unovis inside standalone Svelte 5 \u2014 not a single winner, a routing rule per \u00a74. Gap list \u2014 what still needs an external service: Address/geocoding lookups need the Census Geocoder API (or similar) called at request time \u2014 the one piece that can't be fully baked static. Range+CORS-verified tile hosting on Blossom/nsite specifically is unverified end-to-end (\u00a72, \u00a73) \u2014 Cloudflare R2/Pages is the proven fallback. The bilingual string/number pipeline itself is intentionally out of scope here \u2014 hook points only (\u00a73, step 8); full design lives in the parallel i18n chapter. Any query workload that outgrows what DuckDB-WASM can hold client-side (multi-GB full-resolution microdata, not summary tables) needs a real backend or a hosted DuckDB/MotherDuck endpoint \u2014 the static pattern has a ceiling. Confidence: Medium-High \u2014 license/adoption facts are High confidence; the equity-data-fit scoring is this chapter's judgment call, not a third-party benchmark. Open Questions Whether any production Blossom server in the wild actually serves Accept-Ranges: bytes on blob GETs \u2014 BUD-01 only recommends it [27]; untested against a real nsite deployment this pass. Whether Ditto has any embed/widget surface beyond CSS theme tokens that simply isn't publicly documented yet \u2014 two independent doc sweeps found none, which is evidence of absence, not proof of it. Exact current version numbers for Vega-Lite and Observable Framework's newest release notes beyond the ~1.13.x line observed on npm \u2014 worth a fresh check before a client-facing commitment. Whether MKStack's dependency set (React 19.2.5, Vite 8.0.10, Tailwind v4.2.4, Recharts v3.8.1, observed live 2026-07-09) has moved again by the time this is read \u2014 re-fetch package.json from the GitLab repo rather than trusting this snapshot or any secondary blog description [18][43]. No live example of a Nostr-stack census/civic-data dashboard was found \u2014 TresPies would be building the reference case, not following one. Sources observablehq/framework \u2014 GitHub \u2014 static-site generator description, data-loader language support. Accessed 2026-07-09. Data loaders \u2014 Observable Framework \u2014 build-time data loaders, multi-language + binary invocation (DuckDB, ffmpeg). Accessed 2026-07-09. @observablehq/framework \u2014 npm \u2014 current release line (~1.13.x, ~2026-03). Accessed 2026-07-09. d3/d3 LICENSE \u2014 GitHub \u2014 ISC license confirmation. Accessed 2026-07-09. Best Apache ECharts Alternative In 2026 \u2014 LightningChart and echarts vs vega-lite \u2014 npm trends \u2014 Apache 2.0 license, relative weekly-download adoption. Accessed 2026-07-09. Vega and D3 \u2014 Vega docs \u2014 Vega-Lite BSD-3 license, relationship to D3. Accessed 2026-07-09. deck.gl homepage and Using with MapLibre \u2014 deck.gl docs \u2014 MapView/MapboxOverlay camera sync with MapLibre. Accessed 2026-07-09. Choropleths, Four Ways \u2014 Parker Ziegler \u2014 worked example of deck.gl choropleths on ACS 5-year California tract data. Accessed 2026-07-09. Open Source Data Visualization Project deck.gl v9 Released \u2014 OpenJS Foundation and visgl/deck.gl LICENSE \u2014 MIT license, OpenJS/vis.gl governance. Accessed 2026-07-09. maplibre/maplibre-gl-js \u2014 GitHub and LICENSE.txt \u2014 BSD-3 license, Linux Foundation incubation, fork lineage from Mapbox GL JS pre-Dec-2020. Accessed 2026-07-09. Recharts v3 vs Tremor vs Nivo: React Charts 2026 \u2014 PkgPulse \u2014 bundle-size and positioning comparison. Accessed 2026-07-09. Best React chart libraries in 2026 \u2014 LogRocket \u2014 bundle sizes, use-case framing for Recharts/Tremor/Nivo/visx. Accessed 2026-07-09. airbnb/visx \u2014 GitHub \u2014 MIT license, low-level D3+React primitives, adoption figures. Accessed 2026-07-09. Chart \u2014 shadcn/ui and Beautiful Charts & Graphs \u2014 shadcn/ui \u2014 official shadcn/ui chart components built directly on Recharts. Accessed 2026-07-09. techniq/layerchart \u2014 GitHub \u2014 Svelte 4/5-compatible composable chart components, MIT. Accessed 2026-07-09. f5/unovis \u2014 GitHub \u2014 multi-framework (incl. Svelte) viz framework, CSS-variable theming, MIT. Accessed 2026-07-09. evidence-dev/evidence \u2014 GitHub and Evidence Docs \u2014 MIT license, SQL+Markdown static BI site, DuckDB-powered, in-app AI agent. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 package.json (raw) \u2014 primary dependency manifest: React 19.2.5, Vite 8.0.10, Tailwind v4.2.4, Recharts v3.8.1, Radix UI, TanStack Query, Nostrify. Accessed 2026-07-09. MKStack \u2014 Soapbox \u2014 product framing, \"AI-Powered Nostr App Framework.\" Accessed 2026-07-09. microsoft/data-formulator \u2014 GitHub and Data Formulator 0.7 \u2014 Microsoft Research \u2014 2026 AI-native iterative chart-authoring tool. Accessed 2026-07-09. I Vibe-Coded a Complex Data Visualization Dashboard \u2014 Generative AI in the Newsroom \u2014 LLM default to Recharts/Chart.js when generating React chart code. Accessed 2026-07-09. maplibre/maplibre-agent-skills \u2014 GitHub \u2014 MIT-licensed, community-maintained AI coding-assistant skills for MapLibre. Accessed 2026-07-09. maplibre-pmtiles-patterns SKILL.md \u2014 GitHub \u2014 PMTiles generation/hosting/connection patterns for AI agents. Accessed 2026-07-09. NIP-23 \u2014 nostr-protocol/nips (raw) \u2014 primary spec text: HTML prohibition, optional image tag definition. Accessed 2026-07-09. Kind 30023: Long-form Content \u2014 Nostrbook \u2014 secondary confirmation of kind 30023 structure. Accessed 2026-07-09. lez/nsite \u2014 GitHub README \u2014 kind 34128 path/hash mapping, \"a simple application that doesn't use a backend,\" redundant frontend/relay/Blossom architecture. Accessed 2026-07-09. Blossom BUD-01 \u2014 hzrd149/blossom (raw) \u2014 primary spec text: range-request \"should\" language, CORS \"MUST\" requirement. Accessed 2026-07-09. soapbox-pub/ditto \u2014 GitHub \u2014 9 theme presets, 19 CSS token properties, 100+ UI components. Accessed 2026-07-09. about.ditto.pub \u2014 customization docs: theme/profile personalization, Shakespeare-based deep customization framing (\"completely redesign the UI\"), no widget/embed architecture found. Accessed 2026-07-09. Creating PMTiles \u2014 Tippecanoe / Protomaps Docs \u2014 Tippecanoe v2.17+ direct PMTiles output, CLI workflow. Accessed 2026-07-09. Mapping 650,000+ Texas Census blocks with PMTiles \u2014 Walker Data \u2014 tigris + Tippecanoe pipeline at census-block scale, hosting notes. Accessed 2026-07-09. Geo mark \u2014 Observable Plot \u2014 GeoJSON/TopoJSON-based choropleth mark, Albers-USA projection example. Accessed 2026-07-09. Build your first choropleth map with Observable Plot \u2014 worked county-level choropleth tutorial. Accessed 2026-07-09. protomaps/basemaps \u2014 GitHub and LICENSE_DATA.md \u2014 BSD-3 code license, CC0 cartographic styling, OpenStreetMap ODbL data license (\"Produced Works of the OpenStreetMap dataset under the Open Database License\"). Accessed 2026-07-09. Cloudflare Integration \u2014 Protomaps Docs \u2014 documented PMTiles-on-Cloudflare hosting pattern. Accessed 2026-07-09. Cloudflare Community \u2014 R2 CORS for PMTiles \u2014 practical CORS/range header configuration for R2-hosted tiles. Accessed 2026-07-09. maplibre/demotiles Issue #35 \u2014 reported case of Cloudflare's CDN corrupting PMTiles range responses; Worker/R2-direct as the fix. Accessed 2026-07-09. Query \u2014 DuckDB Wasm docs \u2014 client-side SQL over remote Parquet via HTTP range requests. Accessed 2026-07-09. DuckDB Wasm: Analytical SQL Database in Your Browser \u2014 MotherDuck \u2014 in-browser analytics benefits, ~33MB wasm binary size note. Accessed 2026-07-09. Is DuckDB Open Source? Yes \u2014 the MIT License, Explained \u2014 Definite \u2014 MIT license, DuckDB Foundation perpetuity statute. Accessed 2026-07-09. Vercel acquires Tremor \u2014 Vercel Blog \u2014 Jan 2025 acquisition, Tremor Blocks made free/MIT. Accessed 2026-07-09. react-i18next / i18next Issue #1201 \u2014 confirms i18next has no built-in number/date formatting; Intl API or a date library is required alongside it \u2014 the i18n hook-point boundary referenced in \u00a73. Accessed 2026-07-09. Using MKStack to Build Nostr Apps \u2014 PayPerQ Blog \u2014 secondary source describing MKStack as \"React 18.x... TailwindCSS 3.x\"; superseded by the primary manifest fetch [18] and flagged in Open Questions as a live-verify caution."
    },
    {
      "id": "manual/10-mkstack",
      "kind": "manual",
      "lang": "en",
      "title": "MKStack \u2014 The Framework Layer",
      "url": "/manual/#ch10",
      "md_url": "/manual/md/10-mkstack.md",
      "sha256": "dd91633bf92352fff6cb56278319831fb96f4e2d13ff5f07b67beedabb627369",
      "bytes": 31244,
      "headings": [
        "What It Is",
        "License \u2014 Flagged Loudly",
        "Scaffold Anatomy",
        "The Agent Contract: AGENTS.md, Not NIP.md",
        "Provider-Agnostic Lanes",
        "Deploy + Distribution",
        "Extensibility for the Mod Plan",
        "Maturity + Community",
        "Open Questions",
        "Sources"
      ],
      "body": "The React/Vite/Tailwind scaffold every Nostr client on this stack forks from \u2014 and the piece that decides whether Claude Code, Cursor, Windsurf, or a custom Dojo-driven orchestrator can build here without Shakespeare, on any model provider. Verified: 2026-07-09 \u00b7 Delta pass: 2026-07-10 (NostrDeploy.com DNS tripwire; Stacks-platform relationship sharpened) Amended: 2026-07-10 (v2 wave) \u2014 resolved .mcp.json concretely (nostr/js-dev packages + the five nostrbook tools, live-confirmed); cross-referenced new ch. 12 for the full 19-skill enumeration; catalogued all 17 Toybox experiments and disambiguated Chorus/Treasures/Blobbi source status; added the commit-pin + fetch-only-upstream pinning discipline, cross-ref ch. 15; flagged NostrHub's shared license-absence class with MKStack. Confidence: High \u2014 scaffold anatomy, dependency versions, and the AGENTS.md/.mcp.json/opencode.json agent-compatibility findings (all fetched directly from the live repo). Also high for mkstack-nsp's AGPLv3 license (full text fetched). Medium-High \u2014 the mkstack template's license absence: well-evidenced (four 404s, no SPDX identifier, no GitLab-detected license, silent toolbox page), but Soapbox wasn't asked directly. Medium \u2014 Cursor/Windsurf compatibility: no dedicated rules file found for either; plausible but unconfirmed. Low \u2014 MKStack's exact public launch date: no dedicated announcement post found; repo-creation date used as proxy. What It Is MKStack is Soapbox's Nostr client scaffold: a React 19 + Vite + Tailwind v4 template pre-wired with Nostrify, shadcn/ui, and roughly twenty documented NIPs, at gitlab.com/soapbox-pub/mkstack [2], marketed at soapbox.pub/mkstack [1], product domain mkstack.xyz [2][13]. It is a template you fork, not a standalone CLI \u2014 the CLI that scaffolds it is a separate product, Stacks (@getstacks/stacks on npm) [16][17]. Get the direction of that relationship right: Stacks 1.0 (released 2025-08-20) is the generic template-sharing platform \u2014 templates publish as kind 30717 events and anyone can publish one [17][18] \u2014 and MKStack is just one published stack on it: Soapbox's own flagship stack, not the platform itself. Shakespeare is one client of a shared protocol, not MKStack's only front door. Fact Value Source Canonical repo gitlab.com/soapbox-pub/mkstack [2][10] Product domain mkstack.xyz [2][13] Repo created 2025-04-17 [10] Commits on main / branches / tags 509 / 20 / 0 [10] Last activity 2026-07-09 \u2014 today [10] GitLab stars / forks 2 / 2 [10] GitHub mirror None found (404 on both mkstack and mkstack-nsp) [20] package.json name/version \"mkstack\", \"0.0.0\", private: true [4] Timeline: mkstack created 2025-04-17 \u2192 mkstack-nsp (the NSP backend, AGPLv3) created 2025-06-23 [12] \u2192 Shakespeare announced/launched 2025-07-10/14 (ch. 04) \u2192 Stacks 1.0 released 2025-08-20 [18] \u2192 Shakespeare Act 2, 2025-10-01 (ch. 04) \u2192 both repos still live today, mkstack committed this same day [10][21]. Is Shakespeare just a hosted UI over MKStack? Yes, precisely. mkstack-nsp's own service-discovery event hardcodes the flow identifier \"n\": \"https://shakespeare.diy/#nsp\" [13] \u2014 direct evidence Shakespeare and MKStack's reference NSP share one wire protocol. Shakespeare, the Stacks CLI's agent command, and (in principle) any other client can all target the same NSP. License \u2014 Flagged Loudly This manual's ch. 01/07 call Soapbox frameworks \"permissive,\" grouped with Nostrify (confirmed MIT). That does not hold for MKStack's own template repo \u2014 it ships no license file at all. Four filename variants 404 [11]; package.json has no license field [4]; GitLab's API detects none [10]; the toolbox page states none [19]. The README's only statement on the subject: \"\ud83d\udcc4 License: Open source - build amazing Nostr applications and help grow the decentralized web!\" [3] That is marketing language, not an SPDX grant. Component License Evidence mkstack (the template you fork) No LICENSE file found 4\u00d7 404 on LICENSE/.md/.txt/COPYING [11]; no package.json field [4]; no GitLab-detected license [10] mkstack-nsp (the AI-generation backend / NSP) AGPLv3 \u2014 confirmed, full text present Direct fetch: \"GNU AFFERO GENERAL PUBLIC LICENSE, Version 3\" verbatim [15] Nostrify (@nostrify/nostrify, a dependency) MIT (established ch. 01) Cross-reference; consistent with its use as a normal npm import [4] Practical read, not legal advice: forking the scaffold to start one project mirrors the unenforced norm around tools like create-vite \u2014 nobody expects a boilerplate's license silence to bind the app built from it, and ch. 04 already found Shakespeare-generated code carries no imposed license either. Same license-absence class, same fix in flight: NostrHub. nostrhub.io's repo (gitlab.com/soapbox-pub/nostrhub) was created 2026-06-11 \u2014 a one-month-old \"2.0\" codebase \u2014 and shows the identical pattern: no license detected on direct fetch, 0 stars/forks per the GitLab-API sweep this manual's ch. 01 already ran [29][30]. This isn't a separate problem needing a separate email: the pending Soapbox license outreach (ADR 0001, still unsent as of this pass per the maintainers' companion production audit) already covers both mkstack and NostrHub in one ask \u2014 send one email, not two [30]. The sharper exposure is the NSP, not the template. Self-hosting a modified mkstack-nsp \u2014 e.g. wiring a Dojo Gateway adapter in place of its OpenAI/OpenRouter adapters [14] \u2014 trips AGPLv3's network-use clause: you'd owe that modified server's source to whoever uses it. Verify template-reuse terms with Soapbox before a commercial closed fork; treat any self-hosted NSP as AGPL-bound from day one. Confidence: Medium-High \u2014 the absence is well-triangulated across four independent checks, but \"no license file\" was not confirmed by Soapbox saying so, only by its repeated absence. Scaffold Anatomy The live dependency manifest [4] contradicts the template's own README \u2014 a sharper version of ch. 09's secondary-source caution, except here it's the repo's own marketing copy that's stale against its own package.json and AGENTS.md: README: \"MKStack is an AI-powered framework for building Nostr applications with React 18.x, TailwindCSS 3.x, Vite, shadcn/ui, and Nostrify.\" [3] AGENTS.md: \"This project is a Nostr client application built with React 19.x, TailwindCSS 4.x, Vite, shadcn/ui, and Nostrify.\" [5] AGENTS.md and the live manifest agree; the README does not. Trust the manifest. Layer Package Live version Note Framework react / react-dom 19.2.5 README says \"18.x\" \u2014 stale [3][4] Build vite 8.0.10 (devDep) matches ch. 09 Styling tailwindcss / @tailwindcss/vite 4.2.4 README says \"3.x\" \u2014 stale Components shadcn/ui, unified radix-ui pkg 48+ not per-package @radix-ui/react-* [5] Nostr @nostrify/nostrify / react / nostr-tools 0.52.2 / 0.6.2 / 2.23.3 Nostrify is MIT Data / routing @tanstack/react-query / react-router-dom 5.100.5 / 7.14.2 catch-all /:nip19 route Forms / charts react-hook-form+zod / recharts 7.74/4.3.6 / 3.8.1 recharts reconfirms ch. 09 Testing / types vitest+RTL+jsdom / typescript+eslint see [4] gated in the test script The test script is a compound gate \u2014 tsc --noEmit && eslint --cache && vitest run \u2026 && vite build [4] \u2014 mirroring AGENTS.md's validate-before-commit order exactly [5]. NIP support out of the box \u2014 \"50+ NIPs\" is the marketing claim [1]; independently traced to a hook, component, or rule: NIP Feature Where in scaffold 01/02/05 Profiles, follows, verified IDs useAuthor, NostrMetadata [3][5] 07/46 Extension signing / remote signer LoginArea, AuthDialog, NostrLoginProvider [3][5] 19 npub/note/nevent/naddr/nsec catch-all /:nip19 route, nip19-routing skill [5] 17/44/18/25/23/28/29 DMs, encryption, reposts, reactions, articles, chat listed in README + skills [3][5] 31 alt tag on custom kinds AGENTS.md rule, mandatory [5] 47/57/60/61 NWC / zaps / Cashu / nutzaps useZaps hook, nwc skill [3][8] 65 Relay list / outbox AppProvider+NostrSync, auto-publishes kind 10002 [5] 94 + Blossom File metadata + media storage useUploadFile, file-uploads skill [5][8] The Agent Contract: AGENTS.md, Not NIP.md Correction to this manual's own working assumption (ch. 07: \"MKStack's NIP.md agent contract\"): the file that actually governs what a coding agent does inside MKStack is AGENTS.md, not NIP.md. NIP.md is real, fetched in full below [13] \u2014 but it lives in a different repo (mkstack-nsp) and documents a wire protocol, not coding conventions. AGENTS.md, 348 lines, sits at the template repo's root [5] and names its own role directly: \"The assistant's behavior is defined by this file (AGENTS.md). Edit it directly to change guidelines \u2014 updates take effect the next session.\" [5] File Lives in What it is Status AGENTS.md (348 ln) mkstack template Real system prompt: stack, structure, kind/tag rules, XSS-first security, validate-then-commit DOCUMENTED, native to all [5] .mcp.json mkstack template Claude Code's own MCP config \u2014 wires nostr + js-dev servers DOCUMENTED for Claude Code [6] opencode.json mkstack template OpenCode's own config, same nostr server DOCUMENTED for OpenCode [7] .agents/skills/*/SKILL.md \u00d719 mkstack template Topic skills, YAML frontmatter Claude-Skill-shaped format [8] NIP.md (1,085 ln) mkstack-nsp \u2014 different repo \"Nostr SPA Builder\" wire protocol, thin-client \u2194 NSP RPC (kind 31999/25742/25743) Not a coding contract [13] NIP.md (per-project) generated in your fork Documents custom kinds your app defines Per AGENTS.md's own rule [5] .cursor/rules, .windsurfrules \u2014 Neither found in the tree NOT independently confirmed .mcp.json resolved concretely (2026-07-10): the file wires exactly two stdio MCP servers, both launched via npx: Server Package Tools nostr @nostrbook/mcp@latest readnip, readkind, readtag, readprotocol, readnipsindex \u2014 live-confirmed byte-identical to the tool set documented at nostrbook.dev/mcp [28] js-dev @soapbox.pub/js-dev-mcp@latest Not independently enumerated this pass Practical read: a Claude Code session in a fresh MKStack clone can query live NIP/kind/tag/protocol docs and the full NIPs index without leaving the editor \u2014 the same reference material this manual's own research draws on, available to any agent session directly. NIP.md (mkstack-nsp) opens with: \"This document defines a Nostr Service Provider that generates, deploys, and makes updates to single-page web applications (SPAs) using AI.\" [13] It specifies discovery (kind 31999), encrypted RPC (startproject, sendprojectmessage, getmodels\u2026 over kind 25742), and notifications (25743) [13] \u2014 relevant only if you're building your own NSP or thin client; irrelevant to a Claude Code session editing files locally. Nineteen skills live under .agents/skills/ \u2014 testing, theming, encryption, relay-pools, security, nip19-routing, file-uploads, NWC, and eleven more [8] \u2014 each a SKILL.md with YAML frontmatter (name, description), structurally identical to Claude Code's own Skill format. AGENTS.md defers to them by name (\"load the nostr-security skill\") rather than inlining every detail [5]. This chapter fetched and confirmed only one skill file in full (testing/SKILL.md [8]) \u2014 ch. 12 (new) enumerates all 19 as the curriculum's definition-of-done checklist; treat that chapter, not this \"eleven more,\" as the authoritative skill directory going forward. Confidence: High for Claude Code and OpenCode (direct config files, unambiguous). Medium for the broader \"any AGENTS.md-aware agent\" claim \u2014 the convention exists and is used correctly here, but per-tool adoption wasn't verified. Provider-Agnostic Lanes The operator's question \u2014 can Claude Code, Cursor, Windsurf, or a Dojo-driven orchestrator build MKStack apps directly, on any model provider \u2014 resolves cleanly once the AGENTS.md/NIP.md split is clear. Four lanes exist; only two touch a Soapbox-controlled model roster. Lane Driver Model source Deploy path License exposure Hosted Shakespeare Dork, via Shakespeare's SPA-Builder client Free Gemini / BYOK / local / paid (\"shakespeare\"/\"tybalt\" aliases) [13] 1-click *.shakespeare.wtf, or export (ch. 04) None on generated code Stacks CLI + Dork stacks agent, terminal stacks configure: OpenRouter, Routstr, PayPerQ [3][17] npm run deploy \u2192 Blossom + NostrDeploy.com \u2014 \u26a0 tripwire, see Deploy + Distribution No LICENSE file (\u00a72) Self-hosted NSP Your server, CLONEURL-pointed at any template AIPROVIDER=openai|openrouter today; 3rd adapter buildable [14] Whatever your NSP implements AGPLv3 \u2014 must publish server changes to users [15] Local IDE/CLI agent git clone + Claude Code / OpenCode / Cursor / Windsurf, reading AGENTS.md + .mcp.json 100% yours \u2014 Dojo Gateway, Anthropic, OpenRouter, local Ollama, anything GitHub Pages (shipped CI), Vercel/Netlify, or nsite Same as Stacks lane; none from tooling INFERRED, practical read: the fourth lane is where Dojo orchestration slots in natively \u2014 Claude Code already speaks this repo's .mcp.json out of the box, and \"any provider\" is trivially true because MKStack imposes none on a local session. Only the third lane needs new code: mkstack-nsp documents exactly two adapters today (OpenAI, OpenRouter) [14]; a Dojo Gateway adapter would need to match one of those shapes, or be added as a third \u2014 unattempted by anyone found this pass. Confidence: High for lanes 1, 2, and 4 (each directly documented). Medium for lane 3's Dojo-adapter feasibility \u2014 the extension point is real and documented, but untested by anyone found in this research pass. Deploy + Distribution Path Mechanism Target Evidence Stacks / NostrDeploy npm run deploy \u2014 script is added by the Stacks CLI scaffold; absent from a raw clone's package.json [4] Blossom upload + relay-published pointer event, listed on NostrDeploy.com \u2014 \u26a0 domain dead as of 2026-07-10, see tripwire below [3][16][26] GitHub Pages (shipped CI) .github/workflows/deploy.yml, triggers on push to main actions/deploy-pages, standard dist/ build [9] Anywhere static Plain npm run build \u2192 dist/ Vercel, Netlify, Cloudflare Pages, or nsite/Blossom manually (ch. 04 precedent) [4][21] Listing NostrHub 31990 app-listing kind (ch. 05) + t:mkstack tag browse nostrhub.io/apps/t/mkstack/ [3] \u26a0 Tripwire (2026-07-10): nostrdeploy.com does not resolve. A direct check hit DNS failure (ENOTFOUND) \u2014 the domain doesn't resolve at all, which reads as dead-or-broken domain, not a server outage [26]. Every mention of the npm run deploy \u2192 NostrDeploy lane in this manual (this table, the lanes table above, and ch. 04's decentralized-deploy route) is therefore unverifiable and possibly dead. Until the domain resolves again: don't promise this lane to a client, don't build a runbook on it, and re-check DNS before any workflow that assumes it. The GitHub Pages CI and plain-static paths are unaffected. One untested nuance: the Blossom+relay substrate underneath is content-addressed and may still work even if the NostrDeploy.com index/gateway is gone \u2014 that distinction has not been exercised. A raw git clone gets a normal Vite project with no deploy script at all \u2014 npm run deploy is injected by the Stacks CLI during scaffolding, not shipped in the template's git history. A local agent lane adds its own step or rides the shipped GitHub Pages workflow. Custom-domain mechanics repeat ch. 04's open question \u2014 asserted [16] but no runbook found; verify live before promising a client one. Extensibility for the Mod Plan Addition Scaffold conflict? Evidence i18next (ch. 08's Agora-pattern fork) None found \u2014 zero i18n deps today, no LocaleProvider in App.tsx's provider stack, AGENTS.md silent on locale [4][5] \u2014 independently corroborates ch. 08 Recharts Already present, 3.8.1 [4] \u2014 reconfirms ch. 09 MapLibre GL / PMTiles None found \u2014 zero map deps today; one flagged CSS gotcha (isolate + negative z-index, called out generically in the theming skill) applies to any full-bleed canvas [4][5] Nothing in AGENTS.md's provider stack [5] structurally fights either addition \u2014 both are standard Vite/React npm installs. The one warning is procedural, not technical: \"Never write over App.tsx, AppRouter.tsx, or NostrProvider without first reading their contents\" [5] \u2014 read before wiring in a LocaleProvider or a map canvas. Maturity + Community Signal Value Source GitLab stars / forks 2 / 2 [10] Commits / branches / tags 509 / 20 / 0 [10] Last activity 2026-07-09 \u2014 same day as this research [10] GitHub mirror None (404) [20] Real apps built on it Chorus (community organizing + Cashu wallet for activists), Blobbi (persistent virtual pet), Treasures (decentralized geocaching) [3][24] One-prompt demos (README) Group chat app, \"Bookstr\" (Goodreads-alike via OpenLibrary API), chess with NIP-64 [3] Docs surface 237-line README + 348-line AGENTS.md + 19 skill files + dedicated tutorial post [3][5][8][16] Star counts read small by GitHub norms, but Soapbox operates GitLab-first and Nostr-native by design (ch. 01) \u2014 commit velocity and shipped apps are the more honest signal, and both are strong: 500+ commits in fifteen months, one landing again today. Zero tags means no formal release process \u2014 a rolling-main template, consistent with the \"ship fast, trust-based\" culture ch. 01 and ch. 04 already established. Toybox vs. \"real apps built on it,\" disambiguated (2026-07-10): the table row above names three MKStack-built apps from the README, but only Treasures is actually a Toybox entry. Soapbox's Toybox page (soapbox.pub/toybox) catalogues 17 experiments, live-reconfirmed this pass: Treasures, Birdstar, Surveil, Espy, Blobbi Island, Lief, Nests, Nostrdamus, Polaroids, Plektos, ZapTrax, Podstr, Color Slide, Relaying Earth, Clawstr, Zappix, Bookstr [27]. Chorus is a flagship product positioned outside Toybox entirely \u2014 it doesn't appear on the Toybox page at all [27] \u2014 and its source-code status, like Blobbi's, remains unconfirmed (no public repo located in this manual's research to date). Treasures is confirmed public source, and better than expected: it's third-party-built (\"Built by Chad,\" gitlab.com/chad.curtis/treasures [27]) \u2014 an independent developer's real MKStack app, arguably a stronger teardown candidate than a Soapbox-authored one for proving the scaffold works for outside builders, not just its creators. Pinning discipline, reconfirmed 2026-07-10: zero tags (still true, live-rechecked) means there is no version to pin to in the conventional sense \u2014 the house answer is a commit-SHA pin + a fetch-only upstream remote (push disabled), which makes git diff <pin> upstream/main a real, runnable command rather than a note nobody checks. This is now configured on trespies-stack; ch. 15 (new) covers the full per-component exit-playbook this discipline feeds, including when to re-pin. Open Questions Whether Soapbox would explicitly license the mkstack template if asked directly \u2014 the absence may be oversight, not decision; no dedicated \"Introducing MKStack\" post was found either, unlike Shakespeare's. The exact runbook for a fully custom domain on either deploy path \u2014 mirrors ch. 04's identical open question. Whether Cursor or Windsurf have been used against this scaffold in practice \u2014 plausible, not documented the way Claude Code and OpenCode are. Whether anyone has built a third AI_PROVIDER adapter for mkstack-nsp (Dojo-Gateway-shaped or otherwise) \u2014 not found this pass. Whether the \"shakespeare\"/\"tybalt\" aliases in get_models still map to the Claude-Sonnet-4/free-Gemini tiers ch. 04 documented \u2014 not re-confirmed. Whether NostrDeploy.com's DNS death (ENOTFOUND, 2026-07-10 [26]) is a transient misconfiguration or a discontinued service \u2014 and whether the Blossom+pointer-event substrate under npm run deploy still works without the NostrDeploy.com gateway. Re-check before relying on the Stacks deploy lane. Whether Chorus or Blobbi Island have public repos \u2014 not located this pass; if found, both become teardown candidates alongside Treasures. The full tool list for the js-dev MCP server (@soapbox.pub/js-dev-mcp@latest) \u2014 not independently enumerated this pass, unlike the nostr server's five tools. Sources MKStack \u2014 AI-Powered Nostr App Framework \u2014 product marketing page: \"AI-first\" framing, 50+ NIPs claim, Dork branding. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 repo homepage, description confirming mkstack.xyz as the product domain. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 README.md (raw) \u2014 full 237-line README: quick start, tech stack (stale versions), NIP list, real-world examples, License section. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 package.json (raw) \u2014 live dependency manifest: React 19.2.5, Vite 8.0.10, Tailwind 4.2.4, Recharts 3.8.1, Nostrify, TanStack Query, no i18n packages, no license field, no deploy script. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 AGENTS.md (raw) \u2014 full 348-line agent contract: stack (accurate versions), project structure, Nostr kind/tag rules, security model, validate-then-commit workflow, skill references. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 .mcp.json (raw) \u2014 Claude Code project-scoped MCP config, wiring nostr and js-dev servers. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 opencode.json (raw) \u2014 OpenCode agent config, wiring the same nostr MCP server. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 .agents/skills/ tree + testing/SKILL.md (raw) \u2014 19-skill directory listing (via GitLab API) plus full content of one skill file confirming SKILL.md YAML-frontmatter format. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack \u2014 .github/workflows/deploy.yml (raw) \u2014 GitHub Pages deploy workflow, triggers on push to main. Accessed 2026-07-09. GitLab API project metadata \u2014 https://gitlab.com/api/v4/projects/soapbox-pub%2Fmkstack and its /repository/tree endpoint \u2014 createdat, star/fork counts, commit/branch/tag counts, lastactivity_at, absence of a license field, full root file tree. Accessed 2026-07-09. LICENSE / LICENSE.md / LICENSE.txt / COPYING at gitlab.com/soapbox-pub/mkstack/-/raw/main/ \u2014 all four return HTTP 404, confirmed via direct request. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack-nsp + GitLab API metadata \u2014 repo description (\"Nostr Service Provider for generating Nostr web clients with AI\"), created 2025-06-23, last activity 2025-09-02. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack-nsp \u2014 NIP.md (raw, full 1,085 lines) \u2014 the \"Nostr SPA Builder\" wire-protocol spec: service discovery (kind 31999), encrypted RPC (kind 25742, incl. get_models returning \"shakespeare\"/\"tybalt\" model aliases), notifications (kind 25743), security considerations. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack-nsp \u2014 README.md (raw) \u2014 Deno/TypeScript NSP reference implementation: AIPROVIDER=openai|openrouter adapter config, CLONEURL-configurable base template, Stripe/Lightning credit system. Accessed 2026-07-09. gitlab.com/soapbox-pub/mkstack-nsp \u2014 LICENSE (raw) \u2014 full GNU Affero General Public License v3 text, confirmed present (HTTP 200) and verbatim. Accessed 2026-07-09. MKStack: Vibe Coding for Everyone \u2014 Soapbox Blog \u2014 step-by-step Stacks CLI workflow (npm install -g @getstacks/stacks, stacks mkstack, stacks agent, npm run deploy), cost-discipline warning, NostrDeploy.com mechanics. Accessed 2026-07-09. Stacks \u2014 AI-First Development Platform \u2014 Stacks CLI product page: stack.json/agent.json/CONTEXT.md, Dork provider list (OpenRouter, PayPerQ, Routstr), kind-30717 template publishing. Accessed 2026-07-09. Stacks 1.0 Released \u2014 Soapbox Blog \u2014 published 2025-08-20; multi-provider support, \"your own custom models,\" MKStack framed as \"one such stack.\" Accessed 2026-07-09. Soapbox Toolbox \u2014 full tool inventory; MKStack/Stacks/Nostrify one-line descriptions, no license stated for any. Accessed 2026-07-09. github.com/soapbox-pub/mkstack and github.com/soapbox-pub/mkstack-nsp \u2014 both return HTTP 404, confirming no GitHub mirror exists; Soapbox is GitLab-only for these repos. Accessed 2026-07-09. This manual, ch. 04 \u2014 Shakespeare \u2014 cross-referenced for Shakespeare's launch timeline, the \"MKStack + Claude Sonnet 4\" paid-NSP finding, and the AGPLv3-tool/no-license-on-output distinction reused here. This manual, ch. 08 \u2014 i18n Integration \u2014 cross-referenced; its citation of mkstack-nsp's NIP.md (independently re-fetched in full for this chapter) and its zero-i18n-dependency finding on MKStack, independently reconfirmed here via live package.json. This manual, ch. 09 \u2014 Visualization Integration \u2014 cross-referenced; its prior live package.json fetch (React 19.2.5/Vite 8.0.10/Tailwind 4.2.4/Recharts 3.8.1) matches this chapter's independent fetch exactly, and its stale-secondary-source caution is echoed here against the template's own README. Web search aggregate (Soapbox blog index, NostrHub app listings, general web) \u2014 corroborating descriptions of Chorus (community organizing + Cashu wallet), Blobbi (persistent virtual pet), and Treasures (geocaching) as real MKStack-built apps named in the README. Accessed 2026-07-09. mkstack.xyz \u2014 canonical product domain, referenced throughout the repo description and NIP.md asset URLs; page itself did not render in this pass (TLS handshake failure on direct fetch) \u2014 cited as the documented canonical domain, not independently rendered live. nostrdeploy.com \u2014 direct resolution/fetch attempt: DNS lookup fails (ENOTFOUND); the domain does not resolve at all. Checked 2026-07-10. Supports: the deploy-lane tripwire \u2014 NostrDeploy.com unreachable, service possibly dead. soapbox.pub/toybox \u2014 accessed 2026-07-10 \u2014 live re-fetch: full 17-item Toybox roster reconfirmed; Treasures' public source link (gitlab.com/chad.curtis/treasures, third-party-built) found on-page; Chorus does not appear on this page. nostrbook.dev/mcp \u2014 accessed 2026-07-10 \u2014 live tool-list confirmation for the nostr MCP server: readnip, readkind, readtag, readprotocol, readnipsindex, matching .mcp.json's @nostrbook/mcp@latest package exactly. gitlab.com/soapbox-pub/nostrhub \u2014 accessed 2026-07-10 \u2014 repo created 2026-06-11, no license detected on direct fetch. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set) \u2014 pre-positioning checklist (commit-pin + fetch-only-upstream discipline, now configured on trespies-stack; ADR 0001 license-outreach status covering mkstack + NostrHub) and correction log (NostrHub license-absence finding, 0 stars/forks per the ch. 01 GitLab-API sweep). Accessed/authored 2026-07-10."
    },
    {
      "id": "manual/11-nostrify",
      "kind": "manual",
      "lang": "en",
      "title": "11 \u2014 Nostrify: The Framework Layer",
      "url": "/manual/#ch11",
      "md_url": "/manual/md/11-nostrify.md",
      "sha256": "8a802290eb4b17fc720b6eccefa7bb61716e510fa6f02473a95bb07d0e444af2",
      "bytes": 19164,
      "headings": [
        "What It Is",
        "One Interface, Many Backends",
        "NPool: Outbox Routing \u2014 and Its Timeout Trap",
        "Signers: One Interface, Six Implementations",
        "NSchema: Validate, Don't Assert",
        "NPolicy: 20 Shipped, Not 19",
        "Uploaders",
        "@nostrify/react",
        "Testing Utilities \u2014 Repo-Only, Undocumented",
        "Longevity Note",
        "Verdict",
        "Sources"
      ],
      "body": "The interface layer every MKStack app compiles against \u2014 one shape for storage (NStore) and relays (NRelay) means swapping in-memory for Postgres, or a browser extension for a bunker, is a config change, not a rewrite. Verified: 2026-07-10 Confidence: High \u2014 NStore/NRelay/NostrSigner/NPolicy/NSchema/NUploader interface shapes and the 9-package map (fetched directly from nostrify.dev and the live GitLab repo/API). Also high for the bus-factor figure \u2014 independently reproduced via the GitHub API, matching the maintainers' own same-day companion audit to the decimal. Medium \u2014 NPool's req()-vs-query() EOSE/timeout split: documented clearly on one page, not cross-checked against the TypeScript source itself. Medium \u2014 @nostrify/react's full hook surface: two hooks confirmed (useNostr, useNostrLogin); page content came back tool-summarized rather than read as raw markdown. Low \u2014 testing-utility completeness: MockRelay/ErrorRelay/TestRelayServer confirmed present in the live repo tree; a JSONL-fixture utility referenced in this manual's source research could not be independently relocated this pass. What It Is Nostrify is Soapbox's \"Framework for Nostr on Deno and web\" [1] \u2014 the library every MKStack-scaffolded app imports for storage, relay access, signing, validation, moderation, and uploads. MIT-licensed, pnpm + Changesets monorepo [2][3], nine packages: Package Ships @nostrify/nostrify (core) NStore, NRelay, NRelay1, NPool, NostrSigner + NSecSigner/NConnectSigner/NBrowserSigner, NPolicy, NSchema, NUploader, test utilities @nostrify/react React hooks + provider @nostrify/db NPostgres, NDatabase (Kysely SQL) @nostrify/indexeddb NIndexedDB (browser cache) @nostrify/strfry policy bridge into strfry's write-policy plugin interface @nostrify/policies 20 shipped NPolicy implementations (see below) @nostrify/ndk interop with NDK (Nostr Dev Kit) @nostrify/seed NPhraseSigner, NSeedSigner, NCustodial @nostrify/types shared TypeScript types Package list confirmed live against the monorepo's packages/ directory [4]. @nostrify/ndk shows up only in nostrify.dev's integrations sidebar [5] and @nostrify/types only in the directory listing \u2014 neither package's own README was independently fetched this pass. One Interface, Many Backends Two interfaces, one shape. NStore \u2014 event(), query(), count(), remove() [6]. NRelay \u2014 req(), event(), query() \u2014 and it's explicitly built on NStore: \"Relays on Nostrify are actually just another type of storage. They implement NRelay (which is based on NStore).\" [7] That sentence is the whole chapter in miniature: a relay, an in-memory cache, a Postgres table, and a browser's IndexedDB store are all the same shape to your app code. Interface Implementation Backend Package NStore (in-memory) process memory core NStore NDatabase any SQL via Kysely \u2014 SQLite, MySQL, etc. db NStore NPostgres Postgres, jsonb tags + NIP-50 full-text search, production-tested db NStore NIndexedDB browser IndexedDB, persistent client cache; degrades to a silent no-op under iOS Lockdown Mode indexeddb NRelay NRelay1 one relay connection, auto-reconnecting core NRelay NPool many relays, outbox-model routing core NIndexedDB additionally handles replaceable/addressable-event supersession and NIP-09 deletions, with configurable tag indexing [8]. NPostgres is named the production-tested adapter; NDatabase trades raw performance for broader SQL-engine compatibility [9]. \"Storages can be used interchangeably with relays, allowing you to switch between in-memory, SQL databases, and more without changing your code\" [6] \u2014 the same query() call an app makes against a live NPool in development can run against NPostgres in a worker, or NIndexedDB in an offline-first PWA, with zero call-site changes. NPool: Outbox Routing \u2014 and Its Timeout Trap NPool is the NRelay implementation \"designed with the Outbox model in mind\" [10]. Its constructor takes two routing functions: a reqRouter mapping each relay URL to the filters it should serve (keyed on filter.authors), and an eventRouter mapping each outgoing event's pubkey to the relay URLs it should publish to. Feed it a user's NIP-65 relay list (kind 10002 \u2014 separate read/write sets) and this is outbox-model routing: the routing is the config, not a hardcoded relay array. A hardcoded relay list is the single most common reason \"my app can't find this user's events\" \u2014 it's routing to the wrong set, not a broken query. EOSE behavior splits two ways depending which method you call, and this is the part that bites in production: pool.req() \u2014 the streaming subscription generator \u2014 \"will only emit an EOSE when all relays in its set have emitted an EOSE\" [10], and there is no timeout option on it at all. One dead or silent relay in the route means that subscription's EOSE signal never fires. Events from the healthy relays still stream through; the \"stored events are exhausted\" signal just never arrives. pool.query() \u2014 the one-shot, promise-returning path most application code actually calls \u2014 is safer by default: it \"will wait up to 1 second after the first relay sends EOSE before canceling slow relays\" [10], via an eoseTimeout option (default 1000ms; set 0 to force wait-for-all). req() does accept an AbortSignal [7] \u2014 that's the documented escape hatch, but NPool does not wire one up for you. Verdict: don't trust NPool's defaults for anything long-running. If your app calls req() directly for a live subscription \u2014 chat, a live feed, notifications \u2014 you own the timeout: wrap it in AbortSignal.timeout(N) or your own watchdog, because the default is \"wait forever for the slowest relay in the set.\" query()'s 1-second default is workable for a UI-blocking fetch, but measure it against a cold NPostgres-backed relay before trusting it in a critical path. Signers: One Interface, Six Implementations NostrSigner needs getPublicKey() and signEvent(), plus nip04 and nip44 sub-objects \u2014 each with encrypt()/decrypt() \u2014 built into the interface itself [11]. Every implementation gets encryption for free; no separate library, no separate call convention. The interface's whole reason for existing: \"Signers from Nostrify are all drop-in replacements for window.nostr!\" [11] \u2014 app code written against the browser-extension API swaps to any of the six with no call-site change. Class Package Backs onto NSecSigner core raw nsec, held in-process NBrowserSigner core wraps the browser's own window.nostr (NIP-07) NConnectSigner core NIP-46 remote signer / bunker NPhraseSigner seed BIP-39 mnemonic phrase NSeedSigner seed raw HD seed NCustodial seed custodial, server-held key Class names confirmed directly against the live repo file tree [12][13]; interface shape and the drop-in claim from the docs [11]. NSecSigner and NCustodial both hold key material in-process \u2014 the named catastrophic-failure shape the maintainers' companion audit has already flagged elsewhere (raw nsec in localStorage or a server env var) [24]. NConnectSigner is the one that keeps a brand or team key out of the app entirely; prefer it for anything beyond a disposable per-session identity. NSchema: Validate, Don't Assert Zod-based; imported as import { NSchema as n } from '@nostrify/nostrify' \u2014 the n alias mirrors Zod's own z [14]. n.event().parse(data) validates a raw object into a well-formed event; chain .refine(verifyEvent) (from nostr-tools) to also check the signature. n.filter(), n.relayMsg(), n.clientMsg(), and n.bech32('npub') cover the rest of the wire format. Both .parse() (throws) and .safeParse() (returns a result object) ship on every schema [14] \u2014 the difference between \"crash on bad relay data\" and \"handle it,\" and untrusted relay input is the normal case on this protocol, not the edge case. NPolicy: 20 Shipped, Not 19 NPolicy is one method \u2014 call(event: NostrEvent): Promise<NostrRelayOK>, false means reject [15]. The live repo tree (2026-07-10) ships 20 policy implementation files, each with a matching test file [16]; nostrify.dev/policy/ currently documents 18 of them by name \u2014 AuthorPolicy and ReplyBotPolicy are shipped but not yet listed on the live docs page [15][16]. Same class of drift ch. 10 already caught between MKStack's README and its package.json [17] \u2014 trust the repo tree over the docs page. Policy Does WoTPolicy Web-of-trust filtering \u2014 reject pubkeys outside a trust radius OpenAIPolicy AI-based content moderation via OpenAI's moderation API PowPolicy Requires NIP-13 proof-of-work difficulty \u2014 a spam deterrent PipePolicy Chains multiple policies into one pipeline HellthreadPolicy Caps mass-mention (\"hellthread\") events The same NPolicy object runs in two places unmodified: in a client, to reject-before-render, or piped into a relay via @nostrify/strfry, which \"adapts Nostrify policies for use in strfry policy plugins\" and \"hooks up to stdin/stdout and runs the policy on strfry input\" [18]. Write the moderation pipeline once; run it client-side today, relay-side later. Uploaders NUploader is one method: upload(file: File): Promise<[['url', string], ...string[][]]> \u2014 the return is a NIP-94 tag array, first tag guaranteed to be url [19]. Two shipped implementations: BlossomUploader (one or more Blossom servers) and NostrBuildUploader (nostr.build or a compatible server) [19]. Output tags \u2014 url, m (MIME), x (sha256), size, dim, blurhash \u2014 drop directly into a kind 1063 (NIP-94) or inline (NIP-92) event with no reshaping. @nostrify/react NostrProvider wraps the app in relay context; useNostr() returns the pool from any component; useNostrLogin() exposes login/logout state [20][21]. Under the hood the provider constructs an NPool over NRelay1 connections [20] \u2014 this is the hook layer MKStack's own scaffold is built on (ch. 10 [17]). Pair useNostr()'s .query() calls with TanStack Query for caching; the docs' own example does exactly that [20]. Testing Utilities \u2014 Repo-Only, Undocumented The core package's test/ directory ships MockRelay.ts, ErrorRelay.ts, and TestRelayServer.ts [12] \u2014 confirmed directly against the live file tree. None of the three appear anywhere on nostrify.dev; there is no dedicated testing page in its documented section list [1][12]. An app team that wants to write tests against NPool or NRelay today has to read source, not docs, to find them. A JSONL-fixture utility was flagged in this manual's source research but could not be independently relocated this pass \u2014 treat that specific claim as unconfirmed, not disproven. Longevity Note Measured live via the GitHub API, 2026-07-10: of 1,043 total contributions to soapbox-pub/nostrify, alexgleason accounts for 889 \u2014 85.2% [22][23]. The next-largest contributor holds 141 (13.5%); five more combine for the remaining ~1.3% [23]. This reproduces, to the decimal, the figure the maintainers' own companion production-secrets-longevity audit measured earlier the same day [24] \u2014 two independent pulls, same number. Nostrify is the single most load-bearing library in the stack \u2014 every MKStack app, and everything downstream of it, imports it directly. Sitting that on one person is a real risk, not a hypothetical one. The mitigation is available and cheap precisely because the license is permissive: MIT, confirmed on the root repo and every sub-package checked this pass [2][8][9][18]. Vendoring doesn't require anyone's permission. The maintainers' standing recommendation, unchanged by this pass: vendor Nostrify source locally, and have one engineer read NStore and NRelay end-to-end \u2014 so the interface contracts aren't being learned for the first time during an incident [24]. Verdict Nostrify earns the \"framework\" label the rest of this manual has used loosely. The interface discipline is real and live-verified: NStore/NRelay share one shape, every NostrSigner is a window.nostr drop-in, and one NPolicy object runs client-side or relay-side unchanged. Build against the interfaces, not a specific backend, and the \"swap not rewrite\" promise holds. Two traps: NPool.req() has no default timeout and will hang a subscription's EOSE forever on one bad relay \u2014 build the AbortSignal layer yourself, don't discover this live. And the whole framework sits at 85.2% single-author \u2014 MIT licensing makes vendoring cheap insurance; not vendoring it is the actual risk, not a hypothetical one. Sources nostrify.dev \u2014 homepage: tagline, framework description, documented section list (Relays/Storages/Signers/Schemas/Moderation Policies/Uploaders/Integrations \u2014 no testing section). Accessed 2026-07-10. gitlab.com/soapbox-pub/nostrify \u2014 README.md (raw) \u2014 monorepo description, pnpm + Changesets, MIT license. Accessed 2026-07-10. GitLab API project metadata \u2014 gitlab.com/api/v4/projects/soapbox-pub%2Fnostrify \u2014 created 2024-01-16, 8 stars / 6 forks, last activity 2026-07-08. Accessed 2026-07-10. GitLab API repository tree \u2014 packages/ (depth 1) \u2014 confirms the 9-package list: db, indexeddb, ndk, nostrify, policies, react, seed, strfry, types. Accessed 2026-07-10. nostrify.dev/integrations/ \u2014 integrations page: React, NDK, Zaps, MCP, Welshman listed; links to JSR API reference. Accessed 2026-07-10. nostrify.dev/store/ \u2014 NStore interface (event/query/count/remove), implementation list, \"interchangeable... without changing your code\" line. Accessed 2026-07-10. nostrify.dev/relay/ \u2014 NRelay/NRelay1 definitions, \"based on NStore\" quote, req()'s AbortSignal parameter. Accessed 2026-07-10. gitlab.com/soapbox-pub/nostrify \u2014 packages/indexeddb/README.md (raw) \u2014 NIndexedDB: filter support, supersession/NIP-09 deletion handling, Lockdown Mode degradation to a silent no-op. Accessed 2026-07-10. gitlab.com/soapbox-pub/nostrify \u2014 packages/db/README.md (raw) \u2014 NPostgres (jsonb + NIP-50 FTS, production-tested) vs NDatabase (Kysely, broad SQL compatibility). Accessed 2026-07-10. nostrify.dev/relay/pool \u2014 NPool outbox routing (reqRouter/eventRouter), the pool.req() vs pool.query() EOSE/timeout split, eoseTimeout default and override. Accessed 2026-07-10. nostrify.dev/sign/ \u2014 NostrSigner interface, built-in nip04/nip44, \"drop-in replacements for window.nostr\" quote. Accessed 2026-07-10. GitLab API repository tree \u2014 packages/nostrify/ (recursive) \u2014 confirms NSecSigner.ts, NConnectSigner.ts, NBrowserSigner.ts, NRelay1.ts, RelayError.ts, and test/MockRelay.ts / test/ErrorRelay.ts / test/TestRelayServer.ts. Accessed 2026-07-10. GitLab API repository tree \u2014 packages/seed/ (recursive) \u2014 confirms NCustodial.ts, NPhraseSigner.ts, NSeedSigner.ts; no root README present. Accessed 2026-07-10. nostrify.dev/schema/ \u2014 NSchema (NSchema as n), Zod basis, .parse()/.safeParse(), event/filter/relayMsg/bech32 examples. Accessed 2026-07-10. nostrify.dev/policy/ \u2014 NPolicy interface (call() returning NostrRelayOK), 18 policies enumerated by name on this page. Accessed 2026-07-10. GitLab API repository tree \u2014 packages/policies/ (recursive) \u2014 confirms 20 policy implementation files incl. AuthorPolicy.ts and ReplyBotPolicy.ts, absent from the docs page. Accessed 2026-07-10. This manual, ch. 10 \u2014 MKStack \u2014 cross-referenced for the README-vs-manifest drift pattern (reused here for docs-page-vs-repo-tree) and for @nostrify/react's role as MKStack's hook layer. gitlab.com/soapbox-pub/nostrify \u2014 packages/strfry/README.md (raw) \u2014 the strfry write-policy bridge, stdin/stdout adapter, MIT license reconfirmed. Accessed 2026-07-10. nostrify.dev/upload/ \u2014 NUploader interface, BlossomUploader/NostrBuildUploader, NIP-94 tag output shape. Accessed 2026-07-10. nostrify.dev/react/ \u2014 NostrProvider, useNostr(), setup pattern, TanStack Query pairing example. Accessed 2026-07-10. gitlab.com/soapbox-pub/nostrify \u2014 packages/react/README.md (raw) \u2014 cross-check: NostrContext.Provider, NostrLoginProvider, useNostrLogin(). Accessed 2026-07-10. github.com/soapbox-pub/nostrify \u2014 confirms a live GitHub mirror exists (unlike MKStack, ch. 10): 1,050 commits, 17 stars, MIT. Accessed 2026-07-10. GitHub API \u2014 api.github.com/repos/soapbox-pub/nostrify/contributors \u2014 full contributor list: alexgleason 889, xyzshantaram 141, patrickReiis 6, hzrd149 2, sergey3bv 2, marykatefain 1, dentropy 1, Sjors 1 (1,043 total). Accessed 2026-07-10. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set) \u2014 same-day bus-factor measurement (Nostrify 85.2% Gleason, independently cross-checked here) and the standing pre-positioning recommendation to vendor Nostrify source + read NStore/NRelay end-to-end."
    },
    {
      "id": "manual/12-building-consumer-apps",
      "kind": "manual",
      "lang": "en",
      "title": "12 \u2014 Building Consumer Apps: The Curriculum and the Workflow",
      "url": "/manual/#ch12",
      "md_url": "/manual/md/12-building-consumer-apps.md",
      "sha256": "dab589d576a4c6337e912baf1c665fea74250b72cdd84a74731def4d248246cc",
      "bytes": 25895,
      "headings": [
        "What This Chapter Is",
        "The Soapbox Dev Ladder",
        "The 19-Skill Curriculum: The Definition of Done",
        "Hook and Component Inventory, by Consumer Domain",
        "Scaffold vs. Product: An Opportunity, Not a Contradiction",
        "Five Load-Bearing Concepts",
        "The AI-Team Pattern",
        "Open Questions",
        "Sources"
      ],
      "body": "Ch. 10 established that MKStack is buildable outside Shakespeare, on any model provider. This chapter answers the next question: once you can build there, what counts as \"done\" \u2014 the 19-skill directory as the definition-of-done checklist, the three-rung workflow Soapbox's own team uses to decide what to build and how, and the five concepts that separate a working prototype from a Nostr-native one. Verified: 2026-07-10 Confidence: High \u2014 all 19 skill files (fetched live, raw, this pass), the dev-ladder quotes and the 48h Agora/HRF data point (fetched live from the source post), the domain/NIP mapping (independently re-verified against the live marketing page \u2014 matches the earlier gap-analysis draft exactly). Medium \u2014 builder-criticality ratings (Core/Common/Situational) in the skill table below: this manual's own judgment call, applied consistently, not a ranking Soapbox publishes anywhere. Medium \u2014 the AI-team roster: three personas confirmed live (Dirk Rost, Quilly, Sheila), each announced independently with no roster page tying them together. Treat as a plurality snapshot, not a closed list, and re-verify currency before citing any one as \"the\" example. Low \u2014 whether the \u00a79.0 lane mapping to the dev ladder (below) is a parallel Soapbox intends or one this manual draws by analogy; no source states the two frameworks correspond. What This Chapter Is Three chapters now stack on top of each other. Ch. 10 covers MKStack's scaffold anatomy, dependency versions, and the AGENTS.md/.mcp.json agent contract. Ch. 11 covers Nostrify, the interface layer every scaffolded app compiles against \u2014 NStore/NRelay, signers, policies, uploaders. Neither is repeated here. This chapter covers the layer above both: what a coding agent (or the human directing it) must still get right after the scaffold compiles clean and the interfaces are wired, and how Soapbox's own team decides what to build in the first place. Two threads, in order: the 19-skill curriculum as the spec for \"done,\" and the workflow culture that produces Soapbox's own apps 48 hours at a time. The Soapbox Dev Ladder Soapbox doesn't build consumer Nostr apps with one tool \u2014 it picks a rung based on how well the shape of the thing is already known [1]: Rung Tool When What it optimizes for 1 Shakespeare \"where ideas start\" fastest path from a thought to a working Nostr app \u2014 ideation and quick prototyping [1] 2 OpenCode \"once an idea is worth building for real\" agentic AI coding, fine control over every file \u2014 going deep [1] 3 Clone MKStack \"when we already know exactly what we're making\" known shape; the template is the starting point, not a re-derivation [1] The ladder isn't strictly one-way \u2014 a team that already knows the shape can start straight at rung 3. Ch. 07 \u00a79.0 codifies TresPies's own parallel structure: four lanes (Enterprise / TresPies-hosted / IDE agents / Local-routed) picked by who's driving and which model provider, not by how well-known the shape is \u2014 a different axis on the same instinct: match the tool to how much is already decided before you start. Read loosely rather than as a Soapbox-stated equivalence, the two frameworks line up: Dev-ladder rung Nearest \u00a79.0 lane Shared logic Shakespeare (ideation) Local / routed \u2014 cost-floor mockup volume Cheapest, fastest, most disposable output; nothing here is meant to survive OpenCode (deep work) IDE agents \u2014 operator-in-the-loop editing Fine-grained control, a human steering every file, not a one-shot generation Clone MKStack (known shape) TresPies-hosted / Enterprise \u2014 house builds, contract work The shape is already decided; the remaining choice is execution, not exploration The culture behind the ladder is stated twice in the same post. First, the producer framing: \"In music, the producer doesn't play every instrument; they bring taste, direction, and the judgment to know when it's done. That's the role.\" [1] \"The AI writes the code; the human owns the vision and the standard.\" [1] Second, prompting itself is named as a craft with a learning curve, not a shortcut around one: \"Prompting is a skill. Learning how to speak to an AI, how to frame a problem, how much context to give, when to steer and when to get out of the way, how to recognize why a model went sideways and correct it, is a real, earned craft.\" [1] \"The best people on our team aren't the ones with the fanciest setup; they're the ones who've put in the reps.\" [1] The data point behind the claim: Agora \u2014 ch. 03's non-custodial BTC fundraising product \u2014 was built in 48 hours at the HRF hackathon, using both Shakespeare and OpenCode, and \"Venezuelan activists were on it within hours\" of shipping [1]. That is the ladder under real time pressure, not a marketing abstraction. The 19-Skill Curriculum: The Definition of Done Ch. 10 established that .agents/skills/*/SKILL.md is a Claude-Skill-shaped directory an agent loads by name from AGENTS.md. What ch. 10 didn't do is open all 19 files \u2014 this chapter does, live, and treats the resulting list as the operational definition of \"done\": a shipped app that never touched a skill's territory hasn't finished that dimension, whether or not an agent wrote code near it. Legend: Core = load-bearing for nearly any consumer app on this stack. Common = frequent, but scoped to a feature category. Situational = specific product shape only. Ratings are this manual's judgment \u2014 no Soapbox-published ranking exists. Skill Teaches Criticality nostr-security XSS threat model for a client holding nsec in localStorage: CSP, URL/CSS sanitization, author-filtering on trust-sensitive queries [6] Core testing Vitest + RTL unit tests via the TestApp wrapper and pre-mocked browser APIs; run the full suite, not just one file [7] Core nip19-routing One root /:nip19 route decodes npub/nprofile/note/nevent/naddr; decode before filtering, scope addressable queries by author, never render a decoded nsec [9] Core nostr-relay-pools Target specific relays or curated groups via nostr.relay()/nostr.group(); read write-relays from NIP-65 metadata, never hardcode a relay list [5] Core nostr-infinite-scroll useInfiniteQuery + intersection observer, paginated by until timestamp, deduplicated by event id [19] Core note-content The NoteContent renderer: linkifies URLs/hashtags/mentions, embeds media/invoices/quoted notes, sanitizes all of it; guard recursive embeds against unbounded nesting [20] Core theming Fonts via @fontsource, light/dark CSS variables, shadcn/ui-consistent styling; the isolate + negative-z-index stacking-context gotcha [8] Common file-uploads useUploadFile posts to a Blossom server, returns NIP-94 imeta tags; requires a signed-in signer, prefer mutateAsync before publishing the referencing event [10] Common nostr-encryption NIP-44 (legacy NIP-04 fallback) encrypt/decrypt through the logged-in user's signer only; never derive a shared secret yourself [12] Common edit-profile Drop-in kind-0 profile form (name/about/picture/banner/nip05), reusing useUploadFile for images [15] Common nostr-comments Threaded comments (NIP-22 kind 1111) attachable to events, URLs, hashtags, or NIP-73 identifiers; NIP-09 deletion isn't guaranteed network-wide [18] Common relay-management User-facing NIP-65 relay-list editor, publishes kind 10002 \u2014 the write-side companion to the outbox model's login-time auto-sync [23] Common nwc Nostr Wallet Connect (NIP-47) + WebLN + NIP-57 zap requests; NWC connection strings are secrets, store like passwords [11] Situational onchain-bitcoin Derives a Taproot BTC address straight from the Nostr pubkey (same secp256k1 key), PSBT signing across all three signer types, kind-8333 onchain zaps; verify amounts on-chain, the amount tag is self-reported [21] Situational capacitor Wraps the web app as native iOS/Android \u2014 haptics, Keychain/KeyStore, deep links, no Swift/Kotlin; bootstrapNative() must run before React mounts [14] Situational lockdown-mode Maps what Apple Lockdown Mode blocks (IndexedDB, Service Workers, WASM, WebGL, WebRTC) and the fallback per API; no official detection API exists [16] Situational nip85-stats Pulls pre-computed engagement stats from a trusted NIP-85 assertion provider instead of scanning raw events; always author-filtered, not a source of truth for per-user interactivity [17] Situational ai-chat useShakespeare hook wires Nostr-authenticated chat completions to the Shakespeare API, streaming plus dynamic model discovery [13] Situational plausible-analytics Privacy-friendly analytics via @plausible-analytics/tracker, wired through AppConfig and VITEPLAUSIBLE* env vars; guard init() with a ref, it only runs once [22] Situational Scope warning: nostr-security covers XSS/CSP/content-sanitization only. It documents the consequence of nsec living in localStorage \u2014 \"Nostr private keys (nsec) are stored in plaintext in localStorage\" [6] \u2014 not how to secure that storage, and it says nothing about .env/VITE discipline. Other skills in this table hand an agent raw secrets to wire up with no shared skill governing where those values may live or how they stay out of a client bundle \u2014 plausible-analytics's VITEPLAUSIBLE vars [22], nwc's connection strings [11]. This is not hypothetical: a same-day production audit of this stack found VITE vars get \"baked into the public bundle as literal strings\" and that \"default gitleaks has zero Nostr rules \u2014 a committed nsec1\u2026 passes CI today\" [29]. Key-custody architecture and env-var discipline are specced for ch. 15 (forthcoming, already scoped) [29]. A clean nostr-security pass is not a security audit of either. Hook and Component Inventory, by Consumer Domain The marketing page organizes its \"50+ NIPs\" claim [2] around four consumer domains; independently re-verified against the live page this pass, the mapping matches the earlier gap-analysis draft exactly: Domain NIPs Skills / components that implement it Social 01, 02, 18, 25 (profiles, follows, reposts, reactions) edit-profile [15], useAuthor, LoginArea [2] Messaging 17, 28, 29, 44 (DMs, public chat, groups, encryption) nostr-encryption [12]; gift-wrap DMs and groups \u2014 see Scaffold vs. Product, below Payments 47, 57, 60, 61 (NWC, zaps, Cashu, nutzaps) nwc [11]; onchain-bitcoin [21] as the kind-8333 alternative rail Content 23, 52, 53, 94 (long-form, calendar, live events, file metadata) file-uploads [10], note-content [20], nostr-comments [18], nostr-infinite-scroll [19] Eight named hooks and components recur across the marketing page, the skill files, and ch. 10's scaffold anatomy \u2014 the primitives worth knowing by name before reading any app's source: Name Role useNostr Base hook: the active relay pool, underneath every query and publish [2] useNostrPublish Signs and broadcasts an event through the current user's signer [2] useAuthor Resolves a pubkey to kind-0 profile metadata, cached [2] useCurrentUser The logged-in identity plus signer; gates any action requiring auth (uploads, publishes) [2][10] useUploadFile Blossom upload, returns NIP-94-ready metadata [2][10] LoginArea Account-switching UI, the NIP-07/NIP-46 login entry point [2][10] RelaySelector User-facing relay picker [2] NoteContent Sanitized, embed-aware note renderer \u2014 see the note-content skill row, above [2][20] Scaffold vs. Product: An Opportunity, Not a Contradiction Ch. 10's NIP-support table, read against ch. 02's Ditto findings, produces a fact worth stating plainly rather than leaving as a footnote: the MKStack scaffold documents support for NIP-17 (gift-wrap DMs) and NIP-29 (relay-based groups) that Ditto \u2014 Soapbox's own flagship community server \u2014 does not have. Ch. 02 confirms the Ditto side directly: NIP-17/NIP-04 is \"absent from Ditto's own official NIP reference list,\" and NIP-29 groups are \"Flotilla's model, not Ditto's\" [24]. Ch. 10 confirms the scaffold side: the template's README lists NIP-17 and NIP-29 among the roughly twenty NIPs it ships wired [26]. Read as a contradiction, this looks like the manual disagreeing with itself. It isn't. Ditto is a product \u2014 one opinionated deployment of the stack, scoped to what its own team chose to ship. MKStack is the scaffold every product forks from, and it carries broader protocol coverage than any single downstream app needs or exposes. A builder who wants private DMs or relay-based groups doesn't wait for Ditto to add them \u2014 the scaffold already has the pieces (nostr-encryption [12] for the crypto, the README's NIP-17/29 wiring for the event shapes). Ditto's gap is a product-scoping decision, not a stack ceiling. Carry that distinction into every future \"does the stack support X\" question: check the scaffold, not just the flagship app built on it. Five Load-Bearing Concepts Five ideas recur across all 19 skills and both chapters this one draws from. Miss one and an agent-built app still compiles, still passes tsc/eslint/vitest (ch. 10's validate-then-commit gate) \u2014 and still breaks in ways that gate never catches. Concept Statement What breaks if ignored One interface, many backends Storage is a swap, not a rewrite: ch. 11 documents NStore (event/query/count/remove) and NRelay as one shape shared by an in-memory store, NPostgres, NIndexedDB, a single relay, or a full NPool [28]. Every skill in this table is written against that shape, not a specific relay Locking a component to one relay implementation forecloses the in-memory/IndexedDB/Postgres swaps the framework exists to allow Signer discipline across three standards NIP-07 (extension) and NIP-46 (remote/bunker) are detailed in ch. 06 [25]; NIP-55 (Android signer intents, e.g. Amber) is the third standard MKStack's own contract names, not yet covered there. Ch. 11 confirms the shape underneath all three: six NostrSigner implementations, each a window.nostr drop-in with nip04/nip44 built in [28]. Every skill above that touches a key routes through that interface, never a raw nsec nostr-encryption [12], nostr-security [6], and onchain-bitcoin [21] each independently name the same failure mode: a raw nsec reachable by client-side JS turns any XSS into full account \u2014 and, with onchain-bitcoin installed, wallet \u2014 compromise Outbox is routing, not config NIP-65 read/write relay sets, auto-synced on login (ch. 10's NostrSync) and user-editable via relay-management [23]. nostr-relay-pools states the rule directly: \"Don't hard-code user-facing relay lists\" [5]; ch. 11 names the failure mode in the same words this chapter's skills point at: \"a hardcoded relay list is the single most common reason 'my app can't find this user's events'\" [28] Hardcoded relay URLs are this stack's most common \"can't find events\" report \u2014 an event published to a user's write relays never reaches a reader whose client only queries a fixed default Local-first, not CRUD-with-a-backend Frontends are disposable; data lives on relays plus a local cache. lockdown-mode [16] makes the dependency legible in reverse: strip IndexedDB, which Apple Lockdown Mode does outright, and the caching layer most apps quietly lean on is simply gone. Ch. 11 confirms the same weak point from the framework side \u2014 NIndexedDB \"degrades to a silent no-op under iOS Lockdown Mode\" [28] Builders arriving from a typical web-app background reach for a backend database by reflex; there isn't one here, and code assuming persistent server-side state has no home in this architecture Skills-as-spec The 19-skill directory (table, above) is the audit checklist for \"done,\" not a menu an agent copies boilerplate from Shipping a skill's happy path without its warnings \u2014 e.g. file-uploads without the useCurrentUser guard [10] \u2014 ships the documented failure mode still live The three chapters compose rather than compete: ch. 11 supplies the interface guarantee (a relay and a Postgres table look the same to your code), this chapter supplies the feature-by-feature checklist for using that guarantee correctly, and ch. 10 supplies the agent contract that loads both by name. An app that only reads one of the three will compile \u2014 tsc/eslint/vitest don't check for a hardcoded relay list or a signer bypass \u2014 but won't hold up past the first relay outage or the first security review. The AI-Team Pattern Soapbox's own build culture is not purely human. At least three named AI personas do production work, each announced independently, with no roster page connecting them \u2014 a plurality snapshot, not a closed team list; re-verify currency before citing any one as \"the\" example [1][3][4]. Persona Role Runs on Announced Dirk Rost Code review, merge-request approval, \"a bird's-eye view across every project\" [1] Open-source infra; personality \"defined in plain markdown anyone can read\" [1] Referenced in the ships-fast post; no dedicated announcement found this pass Quilly Docs, Nostr community engagement, GitLab contributions (blog posts, team-page updates), real-world Shakespeare testing, team coordination via Signal [3] OpenClaw (open-source agent framework) in an LXC container; personality split across SOUL.md/AGENTS.md/USER.md/TOOLS.md [3] 2026-01-26 [3] Sheila Full contractor-payment lifecycle \u2014 invoices, ACH/wire/Bitcoin payouts, bookkeeping, expense tracking, OpenCollective submissions [4] OpenCode, human-supervised (\"I see what she's doing before it goes out\" [4]); 50+ single-purpose TypeScript scripts under a 600-line AGENTS.md [4] 2026-03-06 [4] The pattern holds across all three: markdown-defined personality on infrastructure Soapbox controls, not a closed-source assistant product. Quilly's own SOUL.md states the operating principle plainly: \"Be genuinely helpful, not performatively helpful. Have opinions. Be resourceful before asking.\" [3] The same open-infra, plain-markdown-personality shape that governs AGENTS.md's relationship to a coding agent (ch. 10) governs Soapbox's relationship to its own AI teammates \u2014 one contract format, applied to both code-writing and operational work. Open Questions Whether the Core/Common/Situational criticality ratings in the skill table would look different if Soapbox published its own ranking \u2014 no such ranking exists in any source found this pass; treat these as this manual's judgment, re-derivable, not authoritative. Whether nostr-security's XSS-only scope is a deliberate boundary or a gap Soapbox hasn't yet closed \u2014 the same-day production audit [29] reads it as the latter; Soapbox has not stated a position either way. Whether Cursor or Windsurf read .agents/skills/*/SKILL.md the same way Claude Code and OpenCode do \u2014 ch. 10 flagged this as unconfirmed, and it remains unconfirmed here; no dedicated rules file for either was found this pass. Whether a fourth AI persona exists beyond Dirk Rost, Quilly, and Sheila \u2014 no roster page surfaced in this pass either; given the cadence of the three found (Jan, then Mar 2026), the count may already be stale by the time this is read. Sources How Soapbox Ships Fast \u2014 Soapbox Blog \u2014 the Shakespeare/OpenCode/clone-MKStack ladder, producer-role quotes, prompting-as-craft quotes, the 48h Agora/HRF hackathon data point, Dirk Rost's role. Accessed 2026-07-10. MKStack \u2014 AI-Powered Nostr App Framework \u2014 marketing page: named hooks/components, NIP-to-domain mapping, \"50+ NIPs\" / \"8 minutes\" claims. Accessed 2026-07-10. Meet Quilly \u2014 Soapbox Blog \u2014 Quilly's role, OpenClaw infrastructure, SOUL.md quote. Published 2026-01-26. Accessed 2026-07-10. Announcing Sheila \u2014 Soapbox Blog \u2014 Sheila's role, OpenCode operation, human-oversight model. Published 2026-03-06. Accessed 2026-07-10. mkstack \u2014 .agents/skills/nostr-relay-pools/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nostr-security/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/testing/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/theming/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nip19-routing/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/file-uploads/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nwc/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nostr-encryption/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/ai-chat/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/capacitor/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/edit-profile/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/lockdown-mode/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nip85-stats/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nostr-comments/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/nostr-infinite-scroll/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/note-content/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/onchain-bitcoin/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/plausible-analytics/SKILL.md (raw) \u2014 accessed 2026-07-10. mkstack \u2014 .agents/skills/relay-management/SKILL.md (raw) \u2014 accessed 2026-07-10. This manual, ch. 02 \u2014 Community Ops \u2014 cross-referenced for Ditto's documented absence of NIP-17/NIP-04 DMs and NIP-29 groups. This manual, ch. 06 \u2014 Nostr Foundations \u2014 cross-referenced for NIP-07/NIP-46 signer mechanics; does not yet document NIP-55. This manual, ch. 10 \u2014 MKStack \u2014 cross-referenced for scaffold anatomy, the AGENTS.md agent contract, and the README-derived NIP-support table; not duplicated here. This manual, ch. 15 (forthcoming) \u2014 planned home for .env/VITE_* discipline and key-custody architecture, outside nostr-security's XSS/CSP scope. This manual, ch. 11 \u2014 Nostrify \u2014 cross-referenced for NStore/NRelay's shared interface shape, NPool outbox routing and its hardcoded-relay-list finding, the six NostrSigner implementations, and NIndexedDB's Lockdown Mode degradation; not duplicated here. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set) \u2014 same-day audit grounding the ch. 15 spec; source of the VITE_ public-bundle finding and the zero-Nostr-rules gitleaks finding cited in this chapter's scope warning."
    },
    {
      "id": "manual/13-relay-operations",
      "kind": "manual",
      "lang": "en",
      "title": "13 \u2014 Relay Operations for an App Team",
      "url": "/manual/#ch13",
      "md_url": "/manual/md/13-relay-operations.md",
      "sha256": "a7b650db85bc79b16fada018a1a78b8ce7e22fbae11de7f6ee55a80a4bf54f92",
      "bytes": 20439,
      "headings": [
        "Why Run Your Own Relay At All",
        "Implementation Menu",
        "The @nostrify/strfry Policy Bridge",
        "The Archive Pattern",
        "Monitoring",
        "Backup",
        "Spam and Abuse Controls",
        "Budget",
        "TresPies Hooks",
        "Open Questions",
        "Sources"
      ],
      "body": "When an app team should run its own Nostr relay, which implementation to run, how to bridge one moderation policy across backends, and the archive/monitoring/backup/spam disciplines none of these ship with by default. Verified: 2026-07-10 Confidence overview: High for strfry, khatru, and ditto-relay mechanics \u2014 all fetched directly from their own GitLab/GitHub READMEs this pass. High for the arXiv economics findings \u2014 the paper was fetched directly rather than trusted secondhand, and one correction is logged below: the companion audit's \"median zap income \u2248$67/6mo\" framing understates the problem; the paper's actual figure is a 90th-percentile number among the minority of relays that receive zaps at all. High for NIP-13, NIP-66, and NIP-77 (spec text fetched directly). High for the @nostrify/strfry bridge mechanism (fetched directly); Medium for \"the same policy runs on Ditto directly,\" which is architectural inference (Ditto is Nostrify-native \u2014 ch. 11) rather than a demonstrated example. Medium for ditto-relay's CAUTION verdict \u2014 real product, real docs, but \"no known external production use\" is an absence-of-evidence finding. Medium-Low for PlebOne's self-reported \"zero spam\" claim \u2014 no independent audit found. Medium for backup guidance, which is generic infrastructure discipline applied into a confirmed documentation gap, not a Nostr-specific practice. Why Run Your Own Relay At All The short version: because on the public network, nobody else is contractually keeping your users' data. Wei and Tyson's empirical study of the Nostr relay ecosystem [1], measuring 712 relays over a six-month window (2023-07-01 to 2023-12-31), fetched directly for this chapter: 95% of free-to-use relays cannot cover their operating costs from zap income alone [1]. The zap-income picture is worse than a median framing suggests. 64% of relays received zero zap transactions in the entire window. Among the roughly one-third that received any zaps, the 90th percentile totaled only ~150,000 sats (~$67) over six months [1]. There is effectively no meaningful \"median zap income\" to quote \u2014 most relays' zap income is zero, and even the strong performers among the rest are not making a living. Most paid relays in the 50-1,000-user \"medium\" tier can cover their operating costs [1] \u2014 the inverse finding, and the basis for the budget note near the end of this chapter. No relay or Blossom media host anywhere offers a contractual SLA. This is not from the paper \u2014 it is an exhaustive-search finding from the maintainers' companion production-audit notes (\u00a72 fact 1): zero found, searched exhaustively, across every relay and Blossom host list. Put together: public relays are a cache, not a database. They are mostly run by enthusiasts, funded by donations that mostly never arrive, with no contractual promise to keep an event past today. The NIP-65 outbox model (ch. 06) already assumes multiple write relays for redundancy \u2014 but redundancy across relays that all share the same economic exposure is not durability, it is the same failure mode running in parallel. The rule this chapter follows: if your app has any user whose data needs to outlive the current session, run one relay whose only job is to be the source of truth. Every public relay your app also writes to per NIP-65 is then correctly understood as reach and redundancy \u2014 not as the place you depend on for durability. Archive relay now; public-facing community relay later. These are two different decisions with two different risk profiles, and this chapter is scoped to the first one. An archive relay that only pulls copies of your own app's events and never accepts public writes carries the durability benefit above with almost none of the downside \u2014 it isn't \"mere hosting\" for anyone else's content. A public-facing relay that accepts writes from strangers is a heavier legal class: Section 230 does not cover federal criminal CSAM liability, and EU DSA liability attaches on actual notice plus failure to act (ch. 15). Stand up the archive relay now; defer opening it to public writes until a moderation posture \u2014 report queues, a takedown process, a human in the loop \u2014 actually exists. Implementation Menu Relay Stack Best for Maturity / adoption Operational notes strfry C++ / LMDB, no external DB Your archive relay; raw throughput Mature \u2014 runs on ~23% of reachable relays, the most-deployed single implementation after nostr-rs-relay [16] Originated the negentropy sync protocol now used ecosystem-wide [4]; strfry export --fried / strfry import moves JSONL; strfry sync <url> (up/down/both) reconciles against a remote relay; first-party Prometheus /metrics [4] khatru Go framework, not a turnkey relay Bespoke relay logic \u2014 custom accept/reject policies, custom AUTH, custom storage Framework-maturity, judged by what's built on it \u2014 GRASP's reference implementation ngit-relay is a khatru relay [6] Hook-based: StoreEvent / QueryEvents / DeleteEvent / RejectEvent callback arrays [5]; pairs with the eventstore module for SQLite/Postgres/LMDB-backed storage [5] Ditto's built-in /relay Deno + PostgreSQL Teams already self-hosting Ditto for community ops \u2014 the relay ships free inside the server Mature, ~2 years of public Ditto releases (ch. 02) Recommended VPS: 4 cores / 8GB RAM / 100GB disk [13]; NIP-50 full-text search via Postgres; full self-host runbook already lives in ch. 02 \u2014 not repeated here ditto-relay (separate product) Bun runtime + OpenSearch Apps that need NIP-50 search with language: / sentiment: / media: filters plus a trending engine feeding NIP-85 signed assertions CAUTION \u2014 born 2026-02-08, ~5 months old; 99.3% single-author; no known external production deployment NIPs: 01/09/11/40/42/45/50/62/70/77/85 [2]; worker pool keeps signature verification, language detection, sentiment analysis, and media detection off the hot path [2]; stateless, scales horizontally behind a load balancer [2]; Prometheus /metrics [2]; NOSTR_NSEC is a required plain env var \u2014 flag this now, full treatment in ch. 15 (secrets) The @nostrify/strfry Policy Bridge Nostrify's moderation model is NPolicy \u2014 a class with one method that looks at an event and returns accept or reject (ch. 11). Nineteen ship in @nostrify/policies, from WoTPolicy to PowPolicy to an OpenAI-backed content-scoring policy. The problem this section solves: strfry doesn't speak TypeScript, so how does a Deno/TS moderation policy reach a C++ relay? @nostrify/strfry is the bridge. strfry's own plugin interface reads accept/reject decisions over stdin/stdout; the package wraps that protocol so any composed NPolicy can sit behind it [3]. Its own example composes six policies through PipePolicy \u2014 FiltersPolicy (kind allow-listing), KeywordPolicy (banned phrases, e.g. Telegram-link spam), RegexPolicy, PubkeyBanPolicy, HellthreadPolicy (reply-storm limiting), and AntiDuplicationPolicy (Deno KV-backed) \u2014 then a single call connects it to strfry [3]. In shape: The same policy object also runs directly inside Ditto, since Ditto is Nostrify-native (ch. 11) \u2014 write the moderation set once, point it at either backend. That is the whole value of the bridge: abuse and spam rules stop being a strfry-specific plugin script or a Ditto-specific admin toggle and become one portable TypeScript module. The Archive Pattern Your archive relay's job is to hold a durable copy of every event your app or its users have written \u2014 not to serve production traffic. Three moving parts: Sync in. strfry sync <relay-url> --dir down pulls everything from each relay your app writes to, using negentropy set-reconciliation so only the delta transfers [4]. Run this against every relay in your app's NIP-65 write set, on a schedule. Export out. strfry export --fried writes JSONL with precomputed fried elements to stdout; cron it to cold storage \u2014 object store or offsite disk \u2014 on whatever cadence matches your data's value [4]. The negentropy caveat. NIP-77, the spec negentropy implements, is merged into the NIPs repo as draft, optional [15]. \"Merged\" describes the spec's repo status, not relay adoption \u2014 most public relays you sync from will not support it, strfry sync falls back to slower reconciliation against those, and your schedule should assume the slow path is the common path, not the exception. Minimum viable archive setup: Provision a small VPS \u2014 strfry's LMDB footprint is modest, and there is no separate database process to run [4]. Install strfry, point its config at local storage, start it as a service [4]. For each relay in your app's NIP-65 write set, run strfry sync <relay-url> --dir down once to seed the archive from history [4]. Cron the same sync command going forward \u2014 hourly or daily depending on write volume. Cron strfry export --fried > backup-$(date +%F).jsonl and ship the file to cold storage [4]. Wire /metrics into whatever Prometheus instance you already run (Monitoring, below) [4]. Do not open the relay to public writes \u2014 see the archive-vs-community-relay distinction above. Monitoring Surface What it gives you Coverage Notes NIP-66 / nostr.watch Liveness + capability observations published as ordinary Nostr events \u2014 kind 30166 discovery events, kind 10166 monitor announcements [7] 8 automated monitoring stations across 6 continents [8] Decentralized by design \u2014 anyone can run a competing monitor; no single authority owns the data [8] First-party Prometheus /metrics scraped directly off your own relay process Ships in strfry [4], nostr-rs-relay [14], and ditto-relay [2]; Ditto (Deno+Postgres) documents metrics too [12] No first-party alerting rules ship with any of them Community Grafana dashboard Pre-built panels for Ditto's Prometheus output Dashboard ID 21844 [11]; a second, independent community project (Ditto-Dash) also exists Neither is a Soapbox first-party artifact No alerting norms exist anywhere in this stack \u2014 no shipped Alertmanager rules, no documented paging thresholds, nothing Nostr-specific. Inherit generic Prometheus/Alertmanager discipline (disk-full, process-down, sync-lag, queue-depth) the same way you would for any other self-hosted service; nothing about Nostr changes what a relay alert should watch for. Backup Component Backup mechanism Status Ditto (Postgres) Generic pg_dump / pgBackRest discipline No first-party Ditto backup runbook exists \u2014 confirmed absent across two research passes; you own this strfry (LMDB) strfry export --fried to JSONL, already covered under Archive Pattern above Doubles as both your sync mechanism and your backup/restore mechanism ditto-relay (OpenSearch) OpenSearch's own snapshot/restore API Generic OpenSearch discipline \u2014 the product itself is too young to have documented backup guidance The pattern across this whole stack: newer, thinner products document search and moderation in detail and say nothing about disaster recovery. Treat that absence as the default, not the exception, and provision backup discipline yourself regardless of which relay you run. Spam and Abuse Controls Control Mechanism Precedent Proof of work NIP-13: difficulty = leading zero bits of the event id; a relay advertises its floor via NIP-11's minpowdifficulty and rejects anything below it [9] PowPolicy ships in @nostrify/policies (ch. 11) \u2014 same bridge as above Relay-level auth NIP-42: gate REQ/EVENT behind an authenticated pubkey before accepting writes or serving reads (ch. 06 \u2014 stable, gates paid and DM-sensitive traffic) khatru exposes custom AUTH handlers [5]; Ditto and strfry both support NIP-42 Web-of-trust filtering Accept events only from pubkeys within N hops of a trusted set PlebOne (relay.pleb.one): a free, public WoT relay self-reporting zero spam \u2014 no payment required, the trust graph does the filtering instead [10] WoTPolicy ships alongside PowPolicy in the same @nostrify/policies library (ch. 11) \u2014 both the PlebOne pattern and the PoW pattern above are one PipePolicy line away, on either backend. Budget The economics in the first section converge on one number: at least one relay in your budget should be paid. Free relays fail the durability test 95% of the time; medium-scale paid relays (50-1,000 users) mostly clear their costs [1]. This does not require a commercial paid relay service specifically \u2014 a VPS you pay for and control is functionally a paid relay in the paper's own terms: money in, durability out. What it rules out is treating an entirely free relay stack as your durability plan. Line-item this before scoping the app budget, not after. TresPies Hooks What follows is the maintainers' own integration notes, published as a worked example of where relay-ops decisions intersect a real firm's other priorities \u2014 adapt the shape, swap the specifics for your own. Two hooks worth flagging, not resolving here. First: ditto-relay's NIP-50 language:<code> search filter [2] means the maintainers' own bilingual thesis is not only a UI/content decision \u2014 it is a data-layer one. A relay or search index that filters and ranks language:es results natively is infrastructure for their Spanish-language product surface, not a nice-to-have bolted on later \u2014 swap in whatever locale your own product targets. Second, a concrete note from the maintainers' own backlog: a relay-provisioning task is already queued on their operator side \u2014 this chapter does not act on it; the general lesson is to run any queued infrastructure task through your own team's intake process before touching it. Open Questions Whether @nostrify/strfry's PipePolicy composition runs byte-identical inside Ditto's own moderation config, or needs a thin Ditto-specific wrapper \u2014 asserted as architectural inference from Ditto being Nostrify-native (ch. 11), not confirmed against a working Ditto deployment this pass. Whether ditto-relay's trending engine (followers/engagers/comment-count scoring feeding signed NIP-85 assertions [2]) has been independently verified to produce sane rankings at any real scale \u2014 the README documents the mechanism, not a production trace. The exact strfry sync behavior against a relay that only partially supports negentropy (advertises it but times out) is not documented in the fetched README [4] \u2014 worth a smoke test before depending on the archive pattern's schedule. PlebOne's \"zero spam\" claim [10] is the relay operator's own framing; no independent measurement of its web-of-trust filter's false-negative rate was found. Sources Yiluo Wei and Gareth Tyson, \"An Empirical Analysis of the Nostr Social Network: Decentralization, Availability, and Replication Overhead,\" arXiv:2402.05709v2. Accessed 2026-07-10. Supports: 95% free-relay cost-coverage failure, 64% zero-zap relays, 90th-percentile zap income (~150k sats / ~$67 over 6 months), medium-scale paid-relay cost coverage. gitlab.com/soapbox-pub/ditto-relay/-/raw/main/README.md. Accessed 2026-07-10. Supports: ditto-relay stack (Bun + OpenSearch), NIP list, NIP-50 language:/sentiment:/media: filters, trending engine feeding NIP-85 publishing, worker-pool/stateless/horizontal-scaling architecture, Prometheus /metrics, NOSTR_NSEC env var. gitlab.com/soapbox-pub/nostrify/-/raw/main/packages/strfry/README.md. Accessed 2026-07-10. Supports: @nostrify/strfry bridge mechanism, stdin/stdout connection to strfry's plugin interface, PipePolicy composition example. github.com/hoytech/strfry (README). Accessed 2026-07-10. Supports: strfry stack (C++/LMDB), negentropy sync origin, export --fried / import JSONL, strfry sync command, Prometheus /metrics. github.com/fiatjaf/khatru (README). Accessed 2026-07-10. Supports: khatru as a Go framework (not turnkey), hook-based architecture (StoreEvent/QueryEvents/DeleteEvent/RejectEvent), eventstore-backed storage options, custom AUTH handlers. ngit.dev/grasp/ \u2014 \"Grasp: Git Repositories Authorized via Signed-Nostr Proofs.\" Accessed 2026-07-10. Supports: GRASP's reference implementation ngit-relay runs on khatru. nips.nostr.com/66 \u2014 NIP-66, Relay Discovery and Liveness Monitoring. Accessed 2026-07-10. Supports: kind 30166 (discovery) / 10166 (monitor announcement) event definitions. Search-index results on github.com/sandwichfarm/nostr-watch and nostr.watch. Accessed 2026-07-10. Supports: nostr.watch's 8 automated monitoring stations across 6 continents, decentralized-monitor design. nips.nostr.com/13 \u2014 NIP-13, Proof of Work. Accessed 2026-07-10. Supports: difficulty = leading zero bits of event id; PoW as spam deterrence; delegated PoW for constrained devices. github.com/PlebOne/relay.pleb.one. Accessed 2026-07-10. Supports: free public web-of-trust relay self-reporting zero spam without payment. grafana.com/grafana/dashboards/21844-ditto/. Accessed 2026-07-10. Supports: community Grafana dashboard ID 21844 for Ditto's Prometheus metrics. docs.soapbox.pub/ditto/metrics (301 redirect to about.ditto.pub). Accessed 2026-07-10. Supports: Ditto's own metrics documentation is mid-migration (consistent with ch. 02's finding); Ditto exposes Prometheus metrics. Nostr note (nevent), recommended Ditto VPS specs, surfaced via search index on nostr.com. Accessed 2026-07-10. Supports: 4 cores / 8GB RAM / 100GB disk recommended for self-hosting Ditto. nostr-rs-relay community references (nutcroft.mataroa.blog; github.com/scsibug/nostr-rs-relay), via search index. Accessed 2026-07-10. Supports: nostr-rs-relay exposes a first-party /metrics endpoint for Prometheus. nips.nostr.com/77 \u2014 NIP-77, Negentropy Syncing. Accessed 2026-07-10. Supports: range-based set reconciliation; spec status \"draft, optional\" \u2014 merged into the NIPs repo, not a relay-adoption guarantee. nostr.watch relay-software statistics, via search index. Accessed 2026-07-10. Supports: strfry runs on 283 of 1,341 reachable relays (~23.1%), the software-share figure used in the Implementation Menu."
    },
    {
      "id": "manual/14-distribution-native",
      "kind": "manual",
      "lang": "en",
      "title": "14 \u2014 Distribution and Native for Consumer Nostr Apps",
      "url": "/manual/#ch14",
      "md_url": "/manual/md/14-distribution-native.md",
      "sha256": "01a6cb0128e588fe22c28a77ce7e4b3761b42c2d9ba3f3f64140ce1886a8649f",
      "bytes": 22022,
      "headings": [
        "1. The channel map",
        "2. Zapstore \u2014 Android's permissionless catalog",
        "3. Zapstore's neighbor: the App Store, mid-2026",
        "4. Capacitor \u2014 native features without Swift or Kotlin",
        "5. Lockdown Mode \u2014 the sandbox gets smaller",
        "6. PWA install and push \u2014 a real gap, not a documentation gap",
        "7. Signer distribution for consumer onboarding",
        "8. Nostr-native docs, dogfooded",
        "Open Questions",
        "Sources"
      ],
      "body": "How a consumer Nostr app actually reaches a phone: Zapstore's permissionless Android store, a Capacitor wrap for native features without touching Swift or Kotlin, what Apple's Lockdown Mode silently breaks, and the standards gap \u2014 no Nostr NIP for push \u2014 that a PWA install papers over but doesn't solve. Verified: 2026-07-10 Confidence: High for Zapstore's publishing/verification mechanics (its own FAQ, publish guide, and OpenSats grant page, fetched directly) and for the absence of a ratified Nostr push NIP (the full NIP index scanned directly, plus the one serious prior attempt read in full). High for NIP-55's same-device signing model (spec fetched directly) and for the capacitor/lockdown-mode skill content (both SKILL.md files fetched directly). Medium for Ditto's current iOS distribution \u2014 its own install guide and a live App Store search result disagree, and this pass didn't reconcile them. Medium for the two Apple 2026 policy facts (each confirmed against a primary Apple page, but that's two targeted checks, not a guideline audit). Low for \"no Nostr-specific App Store friction\" as a general claim \u2014 Apple's Bitcoin/crypto-payment provisions (Guideline 3.1.5) weren't examined this pass. 1. The channel map A consumer app built on MKStack ends up choosing among four channels: ship as a PWA (zero review, zero native code, but a background-push hole under one condition below), or wrap it in Capacitor for Google Play, Zapstore, and/or the App Store. They aren't mutually exclusive \u2014 one Capacitor-wrapped codebase produces both Android artifacts, and most teams ship the PWA on day one regardless of native plans. 2. Zapstore \u2014 Android's permissionless catalog Zapstore is not a Soapbox product. It's an independently OpenSats-funded project (10th Wave of Nostr Grants, announced 2025-03-27 [1]), founded by Franzap and incubated by And Other Stuff, with OpenSats and HRF named as donors [2]. Its own tagline states the design goal plainly: \"You shouldn't need permission to use apps\" [2]. Today it's Android-only \u2014 \"Available for Android and more platforms soon,\" with iOS on the roadmap for Q3 2026 [2] \u2014 running 3,000+ listed apps and roughly 4,000 active users [2]. Ditto ships through it alongside Google Play and the web, as one Android option among several [2][5] \u2014 but it isn't Soapbox's channel; Soapbox is a customer of it, same as any other Android Nostr app (Agora is also Zapstore-only on Android, no iOS listing found \u2014 ch. 03). Publishing is free, permissionless, and keypair-keyed [1][4]: Step Mechanism Install zsp CLI (go install github.com/zapstore/zsp@latest) [4] Configure zsp publish --wizard walks source selection, metadata, signing, and writes zapstore.yaml to the repo \u2014 committed, not gitignored [4] Sign SIGN_WITH env var: nsec1..., a hex key, a bunker:// NIP-46 URL, or browser (NIP-07) \u2014 bunker URLs as CI secrets are the recommended non-interactive path [4] Link identity to build First publish requires the actual Android signing keystore (.jks/.p12/.pem) to cryptographically link the APK's signing certificate to the Nostr pubkey \u2014 this is NIP-C1, certificate linking [4] Get whitelisted Wizard-written zapstore.yaml commits the pubkey to the repo; the relay fetches and verifies the match on first publish \u2014 or skip repo verification entirely if the npub already carries social reputation, via the Vertex system [4] No listing fee, no revenue share, no review queue \u2014 updates ship \"as often as you like\" [3]. Verification at install time stacks two independent checks, not one: a Nostr-layer check (signature on the catalog event, publisher identity) and an Android-layer check (the APK's actual signing certificate compared against the NIP-C1 declaration, enforced by Android's own OS-level cert-pinning at install time) [3]. The Nostr key signs metadata \u2014 explicitly not a substitute for the APK's own Android signing certificate [3]. Ditto's own distribution is where this chapter corrects the manual's working assumption. Soapbox's install guide confirms Android ships as a real native app via Google Play (\"the standard way\") and Zapstore, with the Android build carrying \"full push notifications, secure credential storage, native file downloads\" [5]. iOS, per that same guide, is web-app-only today \u2014 Safari's Share sheet \u2192 \"Add to Home Screen\" \u2192 a full-screen installed PWA with working push \u2014 with a native app explicitly framed as \"in development,\" not shipped [5]. A live App Store search independently surfaced a listing, \"Ditto: Fun Social Media\" under Soapbox Technology LLC [6] \u2014 but the fetched page returned stale version metadata predating this year's relaunch, so it's unclear whether that's a dormant earlier build, a soft-launched beta, or a caching artifact. Treat iOS-native Ditto distribution as unconfirmed; verify live before promising a client an App Store listing exists. 3. Zapstore's neighbor: the App Store, mid-2026 No Nostr-specific App Store friction turned up in this pass \u2014 no rejection pattern, no guideline naming Nostr, zaps, or decentralized identity as a special case. What did turn up are two generic 2026 rules that apply to any MKStack-derived native build: Rule Since What it means for a Capacitor-wrapped MKStack app iOS 26 SDK / Xcode 26 mandatory 2026-04-28, already in effect [7] Every new submission and every update to an existing app must be built with Xcode 26 against an iOS/iPadOS/tvOS/visionOS/watchOS 26 SDK \u2014 deployment target (oldest device supported) is unaffected, only the build toolchain. Apps built against the 26 SDK also inherit Apple's Liquid Glass UI treatment on native chrome by default [7]. Guideline 5.1.2(i): third-party AI data sharing Added 2025-11, still current Verbatim: \"You must clearly disclose where personal data will be shared with third parties, including with third-party AI, and obtain explicit permission before doing so\" [8]. Any MKStack app wiring up the ai-chat skill (ch. 12, forthcoming) and sending user messages to an external LLM needs an explicit opt-in screen before that first request \u2014 a privacy-policy mention alone doesn't satisfy this. Confidence: Medium \u2014 both rules confirmed against Apple's own pages, but this is two targeted lookups, not a guideline audit; Bitcoin/crypto-specific provisions weren't checked. 4. Capacitor \u2014 native features without Swift or Kotlin The capacitor MKStack skill wraps a web app into iOS and Android binaries, exposing native capability through helper functions the app calls unconditionally \u2014 on web they no-op or fall back, on native they hit the real API [9]: Web behavior Capacitor-native behavior Basic vibration Haptics \u2014 taptic engine (iOS) / Android haptics [9] Browser download Write directly to the app's Documents directory [9] <a href> to an external URL Native share sheet [9] localStorage iOS Keychain / Android KeyStore, with automatic migration of any plaintext values already stored [9] Client-side route change only OS deep-link (app-open) events routed through React Router [9] CSS-only notch handling Safe-area Tailwind utilities for the actual notch/gesture-bar geometry [9] The design rule is explicit in the skill itself: helpers are \"SSR-safe and web-safe \u2014 import and call unconditionally from shared components\" [9] \u2014 there's no if (native) branching scattered through the app. Setup is mechanical: install the Capacitor runtime, plugins, and CLI; copy eight utility files plus one config file into the project; register the safe-area Tailwind plugin; call bootstrapNative() before React mounts; render <DeepLinkHandler /> inside the router; then npx cap add ios / npx cap add android and build [9]. It's opt-in \u2014 \"not included in the project by default\" [9]. Agora and Armada's Android builds already run on Capacitor (ch. 02, ch. 03); this pass didn't independently confirm Ditto's own native build uses the same skill rather than a separate codebase. 5. Lockdown Mode \u2014 the sandbox gets smaller Apple's Lockdown Mode (opt-in, iOS/iPadOS 16+, macOS Ventura+, watchOS 10+) restricts the exact WKWebView shell a Capacitor app \u2014 and any PWA \u2014 runs inside [10]. The restrictions aren't cosmetic: Blocked entirely Still works IndexedDB, Service Workers, Cache API, WebAssembly, Web Locks, WebRTC (critical/high) [10] localStorage/sessionStorage, fetch/XHR, WebCrypto (crypto.subtle), Credential Management, cookies, inline PDF [10] WebGL, FileReader, OPFS, SharedArrayBuffer (medium) [10] File constructor, URL.createObjectURL() [10] Notifications API, WebCodecs, Gamepad, Web Share, Speech Synthesis (low) [10] \u2014 The skill's own recommendations: localStorage as the primary store, no hard IndexedDB dependency (in-memory fallback instead), pure-JS crypto (@noble/secp256k1) rather than WASM builds, WebGL treated as progressive enhancement only, and native Capacitor equivalents (@capacitor/share, @capacitor/local-notifications, @capacitor/filesystem) standing in for the blocked web APIs [10]. There is no official detection API for Lockdown Mode \u2014 the only way to know is to probe the disabled surfaces directly, and testing on a real Lockdown-enabled device beats trusting feature-detection alone [10]. This is exactly where MKStack's NIndexedDB \u2014 the persistent browser cache on the same NStore interface, covered in ch. 11 (Nostrify, forthcoming) \u2014 earns its keep: it's built directly on the API this table strips out, and it's designed to degrade gracefully when IndexedDB isn't there. The localStorage-first discipline recommended above is that degradation path, not a separate concern. 6. PWA install and push \u2014 a real gap, not a documentation gap Installing a Nostr PWA is unremarkable: Safari's Share \u2192 \"Add to Home Screen\" produces a full-screen app with working push, confirmed directly on Ditto's own install guide [5]. The mechanism underneath is entirely generic \u2014 the Push API, the Notification API, and a Service Worker to receive events in the background. No Nostr-specific push standard exists, and none of MKStack's 19 skills covers it \u2014 confirmed by scanning the full NIP index directly: nothing numbered, lettered, or hex-coded addresses push or notification delivery [11]. One serious attempt exists, and it's instructive in exactly the way ch. 08's language-tag story is instructive: Proposal Author Status What it would have added \"Push Notification \u2014 Event Watcher API\" (PR #1528) vitorpamplona (Amethyst) Closed, unmerged, 2025-07-31 A NIP-96-shaped registration spec for push-relay servers: POST interface, multi-account registration in one event, wrapped encryption to hide the destination pubkey, multi-server/relay/token support [12] It wasn't a paper proposal \u2014 it had \"been running on Amethyst for the last year or so\" before the PR was even opened [12]. It still didn't merge; the author's own closing note: \"after seeing how well Pokey has been doing, I am not sure if this idea is worth pursuing anymore\" [12]. Read plainly: this is an ecosystem gap, and it's contribution-shaped \u2014 the same class of opening as the es-i18n upstream play in ch. 08. A working reference implementation already ran in production; what's missing is someone carrying it (or a redesign) back through ratification, or an MKStack skill that at least standardizes the non-Nostr fallback so app teams stop re-solving it per app. The Lockdown Mode interaction from \u00a75 matters here directly: Web Push requires an active Service Worker to receive events in the background, and Service Workers sit in Lockdown Mode's blocked-entirely tier [10]. So the fallback isn't \"PWA push degrades\" \u2014 under Lockdown Mode it's absent, full stop, regardless of the Notification API's own lower severity rating there. The only remaining path for a Lockdown Mode user who needs real background push is a Capacitor-native build wired to @capacitor/push-notifications (APNs/FCM) \u2014 not @capacitor/local-notifications, which only schedules device-local notifications and doesn't solve remote delivery at all. Don't conflate the two when scoping a build. 7. Signer distribution for consumer onboarding Ch. 06 already covers NIP-07 (browser extension) and NIP-46 (relay-based remote signing/bunker) as two of the three standards Soapbox names for signing without ever handling a raw nsec. NIP-55 is the third, and it's new to this manual. It solves a narrower problem than NIP-46: 2-way communication between an Android signer app and a Nostr client on the same device, via Android Intents (a visible approval popup, one per request) or a Content Resolver (silent, background, only for previously \"remember my choice\" grants) [13]. The spec is explicit about why you'd pick the other standard instead: \"Consider using NIP-46 for web applications. With the approach here the web client can't call the signer in the background, so the user sees a popup for every request\" [13] \u2014 NIP-55 is same-device-only and relay-free; NIP-46 is cross-device and relay-based. The spec text names no reference implementation, but the ecosystem's is unambiguous: Amber, whose author is widely credited with having written NIP-55 itself [14]. diVine (divine.video) \u2014 Vine's 6-second-loop format rebuilt on Nostr [15], independent of Soapbox, which has only written about it, not built it [17] \u2014 takes a third onboarding path worth contrasting: Keycast, a managed key-custody service offering OAuth2 login with NIP-46 remote signing underneath, keys encrypted server-side rather than held in a device app [16]. That's a materially different trust model from Amber's on-device custody \u2014 closer to \"sign in with Google\" UX at the cost of a custodian in the loop \u2014 and a legitimate pattern for a consumer app whose users won't install a second app just to hold a key. Standard Custody Device model Best fit NIP-07 Browser extension storage Single machine Daily web use \u2014 ch. 06 NIP-46 Signer app/daemon/service Cross-device, relay-based Multi-device, team accounts, OAuth-style services like Keycast NIP-55 Signer app (e.g. Amber) Same Android device only Mobile-first, no relay dependency, visible per-request consent 8. Nostr-native docs, dogfooded Stacks' own onboarding practices what it sells: its Getting Started flow has a new user run stacks add naddr1qvzqqqrhl5pzqprpljlvcnpnw3pejvkkhrc3y6wvmd7vjuad0fg2ud3dky66gaxaqqy8qeedwfjkcctehjfz9x to pull in a starter template, then stacks list and stacks mkstack [18] \u2014 the first thing the platform teaches a new user is the exact kind-30717 template-publishing mechanism it runs on. The intended companion piece \u2014 NostrDeploy.com as the index/gateway for the nsite+Blossom deploy lane \u2014 is DNS-dead as of this manual's 2026-07-10 delta pass; full tripwire detail lives in ch. 10 and ch. 04 and isn't re-litigated here. Open Questions Whether Ditto ships a native iOS app today or the App Store listing found is stale/dormant \u2014 the primary install guide and a live App Store search disagree; re-check before any client commitment. Whether Ditto's own native Android build actually uses the capacitor MKStack skill or a separate codebase \u2014 the feature list matches closely but wasn't independently confirmed. Whether PR #1528's design (or a successor) gets picked up by anyone in the MKStack/Soapbox orbit specifically \u2014 no roadmap signal found either way. Apple's Bitcoin/Lightning/zap-specific App Store provisions (Guideline 3.1.5 family) \u2014 out of scope this pass, worth a dedicated check before an app with native zaps ships to the App Store. Sources OpenSats \u2014 Zapstore \u2014 10th Wave of Nostr Grants (announced 2025-03-27), mission statement, ecosystem scope (relays, indexer, signing tools, zapstore-cli). Accessed 2026-07-10. zapstore.dev \u2014 homepage: tagline, founder (Franzap), incubator (And Other Stuff), donors (OpenSats, HRF), Android-only today / iOS Q3 2026 roadmap, 3,000+ apps / ~4,000 active users. Accessed 2026-07-10. zapstore.dev/docs/faq \u2014 publishing model (free, permissionless, no fees/review queue), dual Nostr+Android verification model. Accessed 2026-07-10. zapstore.dev/docs/publish and zapstore.dev/docs/quickstart \u2014 zsp CLI, zapstore.yaml, SIGN_WITH signing methods, NIP-C1 certificate linking, whitelisting/Vertex-reputation bypass. Quickstart returned mostly navigational content; mechanism detail sourced from the publish guide. Accessed 2026-07-10. soapbox.pub/blog/how-to-install-ditto-mobile \u2014 Android via Google Play + Zapstore with native-app feature list; iOS as PWA-only today with native \"in development\"; web at ditto.pub. Accessed 2026-07-10. Ditto: Fun Social Media \u2014 App Store \u2014 live listing under Soapbox Technology LLC, but returned stale version metadata (2.23.4, dated 2024) inconsistent with the 2026 relaunch timeline; conflict flagged, not resolved. Accessed 2026-07-10. Apple Developer \u2014 Upcoming Requirements \u2014 Xcode 26 / iOS 26 (+ iPadOS/tvOS/visionOS/watchOS 26) SDK requirement for all App Store Connect uploads, in effect since 2026-04-28; applies to build toolchain, not deployment target. Accessed 2026-07-10. TechCrunch \u2014 Apple's new App Review Guidelines clamp down on apps sharing personal data with 'third-party AI' \u2014 Guideline 5.1.2(i) verbatim text, third-party-AI-specific disclosure/consent requirement. Accessed 2026-07-10. gitlab.com/soapbox-pub/mkstack \u2014 .agents/skills/capacitor/SKILL.md (raw) \u2014 full skill content: haptics, native downloads, share sheet, Keychain/KeyStore storage, deep linking, safe areas, setup steps, SSR/web-safe design rule. Accessed 2026-07-10. gitlab.com/soapbox-pub/mkstack \u2014 .agents/skills/lockdown-mode/SKILL.md (raw) \u2014 full skill content: platform availability, blocked/available API tables, storage/crypto/media recommendations, native-alternative mapping, no official detection API. Accessed 2026-07-10. github.com/nostr-protocol/nips \u2014 README (NIP index) \u2014 full index scanned directly; no NIP addresses push notifications or web/mobile push delivery. Accessed 2026-07-10. github.com/nostr-protocol/nips \u2014 PR #1528, \"Push Notification - Event Watcher API\" \u2014 author vitorpamplona, closed unmerged 2025-07-31, in production on Amethyst for roughly a year before submission, verbatim closing quote. Accessed 2026-07-10. github.com/nostr-protocol/nips \u2014 55.md \u2014 full NIP-55 spec text: Intent/Content-Resolver mechanism, same-device scope, verbatim comparison to NIP-46. Accessed 2026-07-10. github.com/greenart7c3/Amber \u2014 Android NIP-55 signer app, corroborating community sources (reviews, client lists) crediting its author with authoring NIP-55. Accessed 2026-07-10 (also cited in ch. 06 as source 13). divine.video and about.divine.video/faqs \u2014 diVine product description (Nostr-native short-form video), independence from Soapbox. Accessed 2026-07-10. github.com/divinevideo/keycast \u2014 Keycast managed key-custody service: OAuth2 login, server-encrypted keys, NIP-46 bunker / HTTP RPC signing. Accessed 2026-07-10. soapbox.pub/blog/what-is-nostr-divine \u2014 Soapbox explainer post about diVine, confirming an editorial rather than ownership relationship. Accessed 2026-07-10. getstacks.dev \u2014 Getting Started flow (stacks add naddr1... \u2192 stacks list \u2192 stacks mkstack); homepage is a client-rendered SPA (confirmed via direct fetch of an empty #root shell), so the exact command was recovered via a search-index cache rather than a direct page render. Accessed 2026-07-10."
    },
    {
      "id": "manual/15-production-secrets-longevity",
      "kind": "manual",
      "lang": "en",
      "title": "15 \u2014 Production: Durability, Secrets, Law, Longevity",
      "url": "/manual/#ch15",
      "md_url": "/manual/md/15-production-secrets-longevity.md",
      "sha256": "f719f8cd1b6dd34e78fac96fb1a439f0e4eb92a40070041e1abd1630b0814f8b",
      "bytes": 42120,
      "headings": [
        "Confidence",
        "1. Data Durability: The Economics of \"Free\"",
        "2. Media Persistence: Blobs Are Not Backups",
        "3. Deletion vs. Privacy Law",
        "4. Operator Legal Exposure",
        "5. Degradation Engineering",
        "6. Monitoring + Backup",
        "7. Secrets + Custody",
        "Secrets architecture (the maintainers' own adopted pattern \u2014 a reusable template for your own Nostr work)",
        "8. Longevity: Funding, Bus Factor, Exit Playbook",
        "Per-component exit playbook",
        "Pre-positioning checklist (ranked by cost)",
        "9. Incident Catalog",
        "Sources"
      ],
      "body": "This is the chapter that decides whether \"we run on Nostr\" survives contact with a lost key, a deleted file, a subpoena, or a regulator's letter. Chapters 01-13 answer \"how does this work.\" This one answers \"what breaks, who is liable when it does, and what do we do before it happens\" \u2014 the audit rendered as teaching. Grounded in a same-day, three-agent production audit (durability economics, secrets/custody, longevity) plus live re-verification of every load-bearing citation below. Verified: 2026-07-10 Confidence # Section Confidence Why 1 Data-durability economics High Direct fetch of the source paper's own numbered sections; two figures corrected from this chapter's source audit (below) 2 Media persistence High Direct ToS + spec fetch; the media-cap figure is corrected from the source audit 3 Deletion vs. privacy law Medium \u2014 inference-flagged NIP text is High; \"no ruling exists\" is a documented absence, not a citable presence; the defensible-posture recommendation is explicitly SYNTHESIZED, not documented industry practice 4 Operator legal exposure Medium Statute/regulation text is High; applying it to a Ditto instance's classification is reasoned analysis, not an actual ruling; the nearest precedent is fediverse (Mastodon), not Nostr-specific 5 Degradation engineering High Direct fetch of Nostrify and nostr-ux.com docs; corrects this chapter's own source audit's premise (below) 6 Monitoring + backup High for spec/tooling; Medium for the Ditto-runbook absence (a negative claim) NIP-66/Prometheus/Grafana directly confirmed live 7 Secrets + custody High Verified against the maintainers' own configuration files, not just vendor docs 8 Longevity Medium-High Bus-factor/funding figures are this session's own audit measurement, not independently re-run here; pinning/remote evidence is directly verified against the maintainers' own repository 9 Incident catalog Medium The Black Hat paper is High; two of the source audit's named incidents could not be verified live \u2014 substituted with verified adjacent evidence, flagged below 1. Data Durability: The Economics of \"Free\" A 2025 measurement study of the live network \u2014 Wei and Tyson, \"An Empirical Analysis of the Nostr Social Network: Decentralization, Availability, and Replication Overhead\" (arXiv:2402.05709v2, accepted CoNEXT '25) [1] \u2014 puts a number on what operators feel anecdotally: free relay infrastructure does not pay for itself. Its own finding: \"our estimates show 95% of the free-to-use relays cannot cover their operational cost\" from donations/zaps alone [1]. Not a governance failure \u2014 the base economics of the model. Correcting this chapter's source audit: the audit cited \"median zap \u2248$67.\" The paper reports no median \u2014 it reports a 90th percentile: relays that receive zaps at all see a 90th-percentile total of 150,000 sats (\u2248$67) [1]. That is a more damning number, not the same one \u2014 if the top 10% of zap-earning relays top out near $67, the true median sits lower. Separately, 64% of all relays receive zero zaps in the observed window [1]. The paper describes medium-scale paid relays (50-1k users) only qualitatively as \"most... able to cover their operational costs\" [1] \u2014 no exact percentage is given, so this manual does not repeat a \"64% of medium paid relays\" figure; that 64% belongs to a different statistic (relays earning nothing at all). What the paper measures precisely is replication and waste: the average post lands on 34.6 relays across 12.4 distinct Autonomous Systems [1] \u2014 real redundancy \u2014 while 98.2% of download/retrieval traffic network-wide is duplicate, an estimated 144 TiB wasted [1]. The network already over-replicates data it then fails to fund. The zero-SLA finding. No relay or Blossom media host surfaced in this or the source audit's research publishes a contractual uptime or durability guarantee \u2014 free or paid. Public infra is a cache. An owned archive relay, plus BUD-04 media mirroring (\u00a72), is storage. The practical answer: own your archive relay. NIP-65 already establishes that a user's write relays are the outbox clients SHOULD check first [2]. The corollary for an operator: run a self-hosted strfry as one of your write relays, treat it as source of truth, and let every public relay you also write to be exactly what \u00a71's economics say it is \u2014 a cache with no promises attached. The negentropy caveat. NIP-77 wraps the Negentropy set-reconciliation protocol so an archive relay can catch up with peers without re-transferring events it already holds [3]; it carries draft optional status as of this verification [3]. Merged into the spec is not the same claim as deployed across the relay population \u2014 most public relays do not yet support it. Budget for targeted REQ backfill from each write relay as the default, with negentropy as an accelerant once a peer confirms support, not a dependency. 2. Media Persistence: Blobs Are Not Backups nostr.build's free-tier Terms of Service state that for free-service media, nostr.build \"has the unrestricted right to delete any uploaded content\" [4], and more broadly that it \"may ban any user, delete any Media, or terminate any account for any reason or no reason, at their sole discretion, without notice or liability\" [4]. Paid plans carry one floor free accounts don't: media stays online for a stated period after account expiration [4] \u2014 implying no equivalent floor below that tier. Correcting this chapter's source audit: the audit cited a \"100MB cap.\" Live-checked against nostr.build's own plan and README pages, the actual free-tier ceiling is far lower \u2014 5MB per file on the free service, roughly 20MB as a hard limit on unauthenticated/free uploads; the entry paid tier raises that to 450MB per file. Treat \"100MB\" as a figure this manual cannot stand behind; re-check the live plan page at time of adoption, since these numbers move. The resilience mechanism is BUD-04, not hope. Blossom's server-to-server mirroring spec defines a PUT /mirror endpoint: server B fetches a blob from a URL on server A, verifies the downloaded content's hash against the authorization token, and stores its own copy [5]. Paired with BUD-03 (a user's published server list, per ch06 \u00a75), mirroring is what makes a single host's ToS survivable \u2014 if nostr.build deletes a file, a client can still resolve it from another server in the uploader's list, provided a mirror was actually made first. Mirroring is opt-in and per-upload; nothing forces it to happen. Any media this organization treats as important \u2014 logos, policy-post attachments, anything cited from a long-form NIP-23 post \u2014 needs an explicit mirror-on-upload step to a server you control, not an assumption that Blossom's redundancy story covers you by default. 3. Deletion vs. Privacy Law Two Nostr-native deletion primitives exist, and they are not the same strength. NIP-09 is advisory: relays \"SHOULD\" honor a kind-5 deletion request [6]. NIP-62 (\"Request to Vanish\") is the strong version, merged into the spec on 2025-02-19 [7] \u2014 missing from this manual's ch06 NIP table, which currently jumps 61 to 65; add it there. Its language is MUST-level: \"Relays MUST fully delete any events from the .pubkey if their service URL is tagged in the event,\" relays \"MUST ensure the deleted events cannot be re-broadcasted,\" and even \"paid relays or relays that restrict who can post MUST also follow the request to vanish regardless of the user's status\" [7]. Merged status is not the same claim as universal implementation \u2014 adoption is thin, and this manual found no data quantifying it. No Nostr-specific privacy ruling exists anywhere. This chapter searched for a GDPR or CCPA enforcement action, regulatory guidance, or court decision naming Nostr specifically and found none. The nearest general analog: the European Data Protection Board finalized blockchain-specific GDPR guidance on 2026-07-08 \u2014 two days before this verification \u2014 ruling that encrypted or hashed on-chain data remains personal data, that immutability and encryption are not technical exemptions from GDPR obligations, and that the right to erasure applies \"even when blockchain technology makes deleting records technically challenging\" [8]. On the US side, commentary on decentralized social platforms generally (Mastodon-class, not Nostr-specific) describes the same structural tension: fragmented server operators and unclear liability assignment under CCPA's comply clock, which assumes a single accountable party exists to receive the request [9]. Neither source rules on Nostr; both describe the exact problem Nostr shares with any federated or append-only architecture \u2014 there may be no single entity who can legally \"control\" a user's data once it has propagated to relays outside your operation, and \"technically hard to delete\" is not a recognized excuse. The defensible posture \u2014 [SYNTHESIZED INFERENCE, not documented industry practice; no source found states this as a standard]: Scope every deletion promise to \"systems we control\" \u2014 your own relays, your own Blossom mirrors, your own database exports. Do not promise deletion from relays or clients you do not operate; NIP-62 [7] is a best-effort ask once content has left your infrastructure, not a guarantee. Issue a NIP-62 request as standard practice on any verified deletion ask, understood as best-effort beyond your own systems. For content that must never be recoverable even from your own cold storage, prefer NIP-17/NIP-59 gift-wrapped encryption [10] at time of creation over after-the-fact deletion \u2014 destroying the decryption context (\"crypto-shredding\") is something you can actually guarantee for content you hold the keys to, in a way \"delete the plaintext everywhere\" is not. 4. Operator Legal Exposure Two liability regimes matter, and both turn on the same mechanism: knowledge plus inaction, not mere hosting. United States \u2014 Section 230 has a criminal-law hole. 47 U.S.C. \u00a7230(e)(1): \"Nothing in this section shall be construed to impair the enforcement of section 223 or 231 of this title, chapter 71 (relating to obscenity) or 110 (relating to sexual exploitation of children) of title 18, United States Code, or any other Federal criminal statute\" [11]. Section 230's civil immunity was never a shield against federal criminal prosecution, CSAM statutes included. Separately, 18 U.S.C. \u00a72258A obligates a provider that obtains actual knowledge of apparent CSAM to report it to NCMEC's CyberTipline \"as soon as reasonably possible\" [12] \u2014 most recently amended 2025-12-18 (Pub. L. 119-60) [12]. This duty attaches to knowledge, not to platform size or architecture. European Union \u2014 actual-knowledge-plus-inaction, with size-tiered duties layered on top. Article 6(1) of Regulation (EU) 2022/2065 exempts a host from liability for stored content only if it \"(a) does not have actual knowledge of illegal activity or illegal content... or (b) upon obtaining such knowledge or awareness, acts expeditiously to remove or to disable access to the illegal content\" [13]. Correcting this chapter's source audit: small and micro enterprises are exempted from Chapter III Section 3 (Articles 19-28 \u2014 internal complaint handling, trusted flaggers, most transparency reporting) except Article 24(3)'s active-user-count reporting, which still applies [14]. Independent-audit duties sit at Article 37, not 42, and apply only to designated Very Large Online Platforms/Search Engines in the first place \u2014 small/micro operators were never in that scope, so this isn't something they're \"exempted\" from so much as categorically outside of [14]. What size never exempts anyone from: Article 16's notice-and-action mechanism, in Section 2, applying to every hosting provider regardless of size [14] \u2014 a visible, working way to flag illegal content is baseline, not a large-platform-only duty. Enforcement is not staying at the top of the size ladder. National Digital Services Coordinators, not only the European Commission, are \"the primary point of contact for users and the enforcers of the DSA's obligations on smaller platforms\" [15] \u2014 enforcement structurally reaches non-VLOP platforms through this national layer, even though public attention has focused on designated giants. Product shape sets the liability tier \u2014 [reasoned application of the DSA's structure, not a ruling that has classified either product]. A bare relay \u2014 a WebSocket server storing and forwarding events with no public-facing dissemination surface \u2014 reads as mere hosting. A Ditto instance bundles a Mastodon-API-compatible web UI that disseminates content to the public at a recipient's request, the DSA's own definitional shape for \"online platform\" \u2014 a heavier class carrying Article 16's duty regardless of size, plus Section 3's obligations once large enough to matter. Treat a Ditto-based community instance as if it is an \"online platform,\" not a bare relay, when scoping compliance work. The nearest real precedent is the fediverse, not Nostr. The Stanford Internet Observatory's \"Child Safety on Federated Social Media\" (Thiel & DiResta, 2023-07-24) scanned the 25 most popular Mastodon instances over two days and found 112 PhotoDNA hash matches for known CSAM, plus nearly 2,000 posts using the top 20 hashtags associated with CSAM-trading communities [16] \u2014 all reported to NCMEC. Mastodon is federated, not relay-based, but it is the closest architecturally-similar network anyone has actually audited for this failure mode, and the finding generalizes uncomfortably well: decentralized, low-moderation-friction networks accumulate this content measurably, not hypothetically, once they reach any scale. What mitigation looks like in practice: a visible, working notice-and-action mechanism; a real NCMEC relationship established before it's needed, not after; human-reviewed report queues. NIP-56 itself warns against pure automation \u2014 \"reports are easily manipulated,\" with \"trusted moderator judgment\" as the intended backstop [17] \u2014 which happens to match what both US and EU law expect: a human acting on knowledge, not a bot acting on volume. 5. Degradation Engineering The hang risk is real but method-specific \u2014 not the blanket claim this chapter's source audit assumed. Nostrify's NPool exposes two request shapes [18]. pool.req() waits for an EOSE from every relay in the pool with no documented timeout at all \u2014 one unresponsive relay can hang the whole call indefinitely. pool.query(), by contrast, ships a documented default: 1000ms after the first relay's EOSE before giving up on the rest (eoseTimeout, configurable, settable to 0 to force wait-for-all) [18]. Correction: \"no documented default timeout\" only holds for pool.req(). Use pool.query() for anything user-facing; treat pool.req() as the specific call that needs an operator-added timeout wrapper if used at all. Ship the pattern, don't invent it. nostr-ux.com's core-interaction patterns give implementable numbers: a 5-second timeout on the primary publish flow (timeout: 5000, \"Pattern A: Reliable Post Publishing\") [19]; treat an action as successful once at least 3 relays confirm (successful.length >= 3) [19]; render partial success explicitly \u2014 \"[!] Posted (2/4 relays) [Retry]\" [19]; retry stragglers in the background with exponential backoff, never blocking the user on them [19]. This is shared infrastructure every consumer-facing app needs and no framework in this stack provides by default. The replaceable-event wipeout class is real and documented, though not at the specific citation this chapter's source audit named. Live re-verification could not locate the \"franzap\" stacker.news post the audit cited. What is directly verifiable: nostr-protocol/nips issue #261 documents the identical failure class \u2014 kind-0 (profile) and kind-3 (contact list) events are fully replaceable, so \"for each combination of pubkey and kind, only the latest event must be stored,\" and a client publishing its own partial view of a profile (missing a field it doesn't understand, e.g. a lightning address) silently erases that field for every other client, because the relay has no mechanism to merge two partial updates [20]. Never publish a replaceable event kind from a partial local model of it \u2014 merge against the latest known state first, or you become the client that wipes someone's profile. 6. Monitoring + Backup Relay health has a NIP. NIP-66 (\"Relay Liveness Monitoring\") defines kind 30166 (a monitor's probe results \u2014 RTT for open/read/write, auth requirements, DNS resolution, geolocation) and kind 10166 (a monitor announcing itself) [21]. Its own text builds in graceful degradation: \"Clients MUST NOT require 30166 events to function. Absence of monitoring data MUST NOT prevent relay connections\" [21] \u2014 a signal layered on top of \u00a75's degradation patterns, not something they can depend on. nostr.watch is the ecosystem's most visible public implementation of relay monitoring, useful for spot-checking a relay's general reputation before depending on it \u2014 a third-party view, not your own instrumentation. Metrics are first-party on the relay software itself. strfry ships built-in Prometheus metrics: \"Metrics are exposed via HTTP at the /metrics endpoint on the same port as the relay WebSocket server\" [22]. nostr-rs-relay carries the same shape internally \u2014 a create_metrics() Prometheus registry wired into its server code, exposed at its own /metrics endpoint [23]. Either pairs directly with Grafana dashboard 21844, a community-maintained Ditto dashboard published on Grafana Labs [24] \u2014 the fastest path to a working operational view if Ditto is any part of the stack. Ditto's backup story is a gap, not an oversight you missed. This chapter's source audit searched twice for a first-party Ditto backup runbook and found none either time [25]. Ditto's storage is Postgres \u2014 which makes the discipline here entirely conventional, not Nostr-specific: pg_dump on a schedule at minimum, pgBackRest (or an equivalent WAL-archiving tool) for anything called production. Pair this with \u00a71's archive-strfry backup story \u2014 event data and Ditto's relational state are two different backup problems, and Ditto ships a runbook for neither. 7. Secrets + Custody The mental model every other stack teaches does not transfer here. There is no \"rotate the key\" button. No rotation mechanism exists, full stop. NIP-41 (key migration) has been an open pull request since October 2023 \u2014 three approvals, over 100 comments, still unmerged as of its most recent activity (2025-11-25) [26], blocked on an unresolved fight over automatic migration's griefing window (\"stolen recovery kits enable permanent griefing... you will always worry whether you're losing your social graph to scammers,\" per one maintainer's objection) [26]. NIP-26 (delegated signing), once floated as a workaround, is deprecated [27]. If an nsec leaks, there is no protocol-level undo \u2014 every mitigation below is blast-radius reduction, not a rotation story. FROSTR is the closest exception, and it is early. FROSTR implements FROST threshold signatures over Nostr relays: split an nsec into t-of-n shares across signing devices, and a threshold of shares signs without ever reconstituting the full key [28]. Rotation, in FROSTR's model, means destroying the old shares and issuing a new set \u2014 the npub never changes [28]. Its browser-extension component is explicitly documented as \"under heavy development\" [29]; its core library (Bifrost) is further along \u2014 v2.0.2, released 2026-01-25, with a documented threat model [28] \u2014 but nothing in the ecosystem carries a completed third-party audit as of this verification. Revisit for brand-key custody once it exits that phase. Keycast is the team-custody answer, with its own caveat attached. Keycast targets teams specifically (versus nsec.app/Amber for individuals, ch06 \u00a71), with row-level AES-256 encryption, file- or AWS-KMS-backed key storage, and policy-gated NIP-46 remote signing [30]. Its own README states the caveat this manual adopts: \"Keycast is an early-stage project. A May 2026 audit found and fixed several auth, permission, data integrity, and dependency issues, but this should still get a deployment review before it is trusted with real team keys on the public internet\" [30]. Read that as audited, not yet trust-worn. Structurally, there is no HSM/KMS integration and no keyless-signing analog anywhere in this ecosystem. Every custody tool above is a software wallet with better or worse blast-radius properties \u2014 none hands signing authority to a hardware security module or a short-lived, identity-bound credential the way mainstream software-supply-chain tooling (Sigstore/Fulcio, cloud KMS) does. This is a gap in the protocol's tooling, not any one product's oversight. The stack's own defaults point the wrong way. Both products in this manual that document their server-side signing pattern do it the same way \u2014 a raw nsec in an environment variable. Ditto (Deno + Postgres) documents DITTONSEC; ditto-relay (Bun + OpenSearch) documents NOSTRNSEC [31] \u2014 do not conflate the two; they are different products with different variable names. Secrets architecture (the maintainers' own adopted pattern \u2014 a reusable template for your own Nostr work) Secret type Storage Rotation story Detection Brand nsec Keycast (self-hosted, deployment-reviewed) or nsec.app interim [30] None \u2014 grant revocation on teammate departure, not rotation; revisit FROSTR once it exits heavy development [28][29] gitleaks custom rule (below) Per-service nsec (relay identity, bots, publishers) Injected from a secret store at deploy only \u2014 never in repo, Dockerfile, or wrangler.toml None \u2014 one npub per service keeps blast radius small and audit trails attributable via authors queries gitleaks custom rule (below) Human-touchable backups ncryptsec (NIP-49) [32], passphrase in its own secret-store entry Re-encrypt on passphrase rotation only gitleaks custom rule (below) CI signing key Encrypted blob + passphrase from secret store (same shape as GPG signing), own npub per pipeline Passphrase rotation only gitleaks custom rule (below) VITE_* build-time config Public by construction \u2014 baked into the client bundle as literal strings N/A \u2014 never put a secret here Treat as already public; anything sensitive goes in a Worker secret (wrangler secret put) gitleaks has zero Nostr coverage by default, and that is now fixed in the maintainers' own workspace. The default ruleset ships roughly 190+ rules covering AWS/Azure/GCP, Stripe/PayPal, Slack/Discord, GitHub/GitLab, and more [33] \u2014 and not one pattern for nsec1\u2026, ncryptsec1\u2026, or a bunker:// secret. A committed raw nsec would pass CI today on the default config alone. The maintainers' own .gitleaks.toml now extends the default set with three custom rules \u2014 nostr-nsec (nsec1[a-z0-9]{58}), nostr-ncryptsec (ncryptsec1[a-z0-9]{80,}), and nostr-bunker-secret (an embedded secret= parameter in a bunker:// URI) \u2014 landed the same day as this audit [34]. If you fork this pattern into your own repo, copy that file before the first Nostr credential exists there, not after. The nostr-security skill shipped with this stack does not cover any of the above, and should not be mistaken for doing so. Read directly, its threat model is entirely XSS/CSP: localStorage key theft via script injection, URL and CSS sanitization for untrusted event data, authors filtering for trust-sensitive queries [35]. It never mentions .env discipline, VITE_ exposure, key rotation, or custody. That is a correct and useful scope for what it covers \u2014 the risk is an operator reading \"we have a nostr-security skill\" and assuming secrets sit inside its perimeter. They do not; extend this fork's AGENTS.md with a dedicated secrets section rather than growing this skill past its stated scope. 8. Longevity: Funding, Bus Factor, Exit Playbook Funding is one demonstrated line. This chapter's source audit measured the funding picture directly: OpenSats is the one confirmed, self-reported funding relationship; the Human Rights Foundation, previously assumed a grantor, reclassifies on closer reading to a prize/event partner \u2014 no 2026 grant naming Soapbox, Ditto, or Agora was found anywhere [25]. MIT/AGPL licensing makes forking every component in this stack legal. It does not make forking cheap once a maintainer disappears \u2014 that is a bus-factor problem, and pre-positioning against it now is inexpensive; doing it after a maintainer goes dark is not. Bus factor, measured this session via each repo's contributor history [25]: Repo Primary-author share Read Nostrify 85.2% (Gleason) High-risk \u2014 the framework every MKStack app compiles against has one author mkstack 71.9% (Gleason) High-risk ditto-relay 99.3% (Gleason) Highest concentration measured Ditto 47.4% (Gleason) Healthiest of the four \u2014 the only repo with real secondary maintainers Two cheap moves, one already partly done here. First: add a fetch-only upstream remote to any fork of an upstream Soapbox/MKStack repo, so git diff <pin> upstream/main is a live command instead of a dead note. The maintainers' own trespies-stack fork already has one \u2014 git remote -v shows upstream \u2192 gitlab.com/soapbox-pub/mkstack.git (fetch), push disabled [verified directly, 2026-07-10] \u2014 extend the same pattern to any other forked component before treating a commit pin as more than documentation. Second: schedule recurring re-verification of this manual's highest-churn claims (tags, licenses, DNS, funder pages, bus factor) \u2014 every number in the table above has a shelf life. Per-component exit playbook Component Exit posture Why Ditto YES \u2014 fork and self-maintain AGPL; 47.4% bus factor is the healthiest measured; Postgres backend is boring and portable Nostrify CONDITIONAL \u2014 vendor the source 85.2% bus factor on the one library every MKStack app depends on; vendoring plus one engineer who has read NStore/NRelay end-to-end is the insurance MKStack CONDITIONAL \u2014 license ask outstanding A license-clarification ask to Soapbox is drafted but unsent; confirm before treating forked output as unencumbered Shakespeare YES \u2014 export and go AGPL; output is a static/portable site \u2014 the tool disappearing doesn't strand what it already built NostrHub CONDITIONAL \u2014 license: None, repo one month old Created 2026-06-11, zero stars/forks at last check, no license file at all \u2014 treat anything built against it as provisional until that changes ditto-relay CAUTION 99.3% bus factor, roughly five months old, no known external production deployment found beyond Soapbox's own \u2014 use behind an exit hatch, not as a dependency without a workaround Pre-positioning checklist (ranked by cost) Send the outstanding MKStack + NostrHub license outreach. The ask is drafted; NostrHub's license: None gap is a new finding this closes at the same time. One email; the window closes permanently if the maintainer goes dark first. Add fetch-only upstream remotes to every forked component that doesn't have one yet (one already does \u2014 see above). Schedule recurring re-verification of this manual's high-churn claims via your own scheduling tooling. Vendor Nostrify's source locally, and have one engineer read NStore/NRelay end-to-end \u2014 insurance on the single highest-leverage bus-factor risk in the stack. Stand up the archive strfry from \u00a71, syncing from every relay this organization writes to, with a cron export to cold storage. Open a light relationship with Ditto's non-Gleason maintainers \u2014 low-touch, before it's needed. Keep at least one paid relay in the relay budget, on the economics established in \u00a71. 9. Incident Catalog Black Hat USA 2025 \u2014 \"Not Sealed: Practical Attacks on Nostr, a Decentralized Censorship-Resistant Protocol.\" Presented 2025-08-06 by Hayato Kimura, Ryoma Ito, Kazuhiko Minematsu, Shogo Shiraki, and Takanori Isobe [36]; the underlying paper (preprint title \"Not in The Prophecies: Practical Attacks on Nostr,\" eprint.iacr.org/2025/1459) [37] describes four attack classes \u2014 plaintext recovery, DM forgery, profile forgery, and Bitcoin-payment hijacking \u2014 rooted in flawed client-side signature verification compounded by CBC-mode encryption weaknesses and a link-preview mechanism that leaks a recipient's IP address and message-open timing via external HTTP fetches [36][37]. The research affected past versions of four named clients: Damus (iOS), Iris (iOS), FreeFrom (iOS/Android), and Plebstr [36]. No CVE identifiers were found assigned to any of these findings in available sources. This is the concrete answer to \"why migrate off NIP-04 at all\": the researchers' own recommendation matches this manual's ch06 guidance exactly \u2014 move to NIP-44-based encryption and NIP-17+NIP-59 gift-wrapped DMs, disable automatic link previews, and prefer clients that verify every event signature [36]. The replaceable-event wipeout class (mechanism in \u00a75) is documented directly in the protocol's own issue tracker, nostr-protocol/nips issue #261 [20] \u2014 real, citable, still open. This chapter's source audit also named a specific incident \u2014 a \"franzap\" post on stacker.news \u2014 that could not be independently re-verified live; the citation did not resolve to retrievable content this session. What live research surfaced instead: two real, narrower Damus bugs \u2014 issue #1994, \"Profile is wiped (Balaji's bug),\" a local profile-edit bug from 2024-02 [38], and issue #2264, \"bookmarks wiped on purple expiration,\" a local bug from 2024-05 [39] \u2014 neither of which is the \"relay-upgrade wipe\" the source audit described, though both confirm the same underlying lesson: client-side state and relay-side state disagreeing silently is a recurring Nostr bug class, not a one-off. Nostr's own explainer material states the broader durability risk plainly: \"If all the relays that you have used in the past go offline, all your posts will be unretrievable\" [40]. DVM decay as protocol-churn precedent. NIP-90 (Data Vending Machines) \u2014 the base spec for AI-job marketplaces relevant to DojoGenesis-style agent dispatch \u2014 is itself now marked unrecommended, its own text conceding \"this got totally out of control, prefer use-case-specific microstandards\" [41]. Governance moved to an informally-maintained sister kind-registry repo rather than the spec dying outright [41]. The lesson for anything built on this manual's NIP table: merged into the spec is a snapshot, not a guarantee. Re-verify currency verdicts on the cadence recommended in \u00a78, not once at project start. Disclosure note. ditto-relay \u2014 the Bun-based relay/search product covered in ch13 \u2014 runs on a runtime Anthropic acquired on 2025-12-02 [42][43]. This manual is Claude-authored, researching a stack whose relay layer partly depends on an Anthropic-owned runtime. Bun remains open-source and MIT-licensed under the new ownership [42], so this changes no technical recommendation above \u2014 but it's the kind of overlap a trustworthy manual states rather than leaves for a reader to notice first. Sources Wei & Tyson \u2014 \"An Empirical Analysis of the Nostr Social Network: Decentralization, Availability, and Replication Overhead\" (full text: arxiv.org/html/2402.05709v2), accepted CoNEXT '25 \u2014 accessed 2026-07-10 \u2014 free-relay cost coverage (95%), zap-income percentile ($67/90th), replication factor (34.6 relays/12.4 ASes), wasted bandwidth (98.2%/144 TiB). NIP-65: Relay List Metadata \u2014 accessed 2026-07-10 \u2014 outbox model. NIP-77: Negentropy Syncing \u2014 accessed 2026-07-10 \u2014 draft/optional status, bandwidth-efficient reconciliation. nostr.build Terms of Service (nostr.build/tos/ redirects here) \u2014 accessed 2026-07-10 \u2014 free-tier unrestricted deletion right; plan limits cross-checked against account.nostr.build/plans and the FOSS README. BUD-04: Mirroring Blobs \u2014 accessed 2026-07-10 \u2014 server-to-server mirroring mechanism. NIP-09: Event Deletion Request \u2014 accessed 2026-07-10 \u2014 advisory SHOULD-level deletion. NIP-62: Request to Vanish; merge commit 619e3be, \"Right to Vanish (#1256)\" \u2014 accessed 2026-07-10 \u2014 MUST-level deletion, merged 2025-02-19. EDPB \u2014 Guidelines on processing of personal data through blockchain technologies, finalized 2026-07-08 \u2014 accessed 2026-07-10 \u2014 no technical exemption from GDPR obligations; right to erasure applies despite technical difficulty. Decentralized Social Media and CCPA Compliance \u2014 accessed 2026-07-10 \u2014 fragmented-liability framing for federated platforms under CCPA. NIP-17: Private Direct Messages / NIP-59: Gift Wrap \u2014 accessed 2026-07-10 \u2014 encryption mechanics underlying the crypto-shredding inference. 47 U.S.C. \u00a7230 \u2014 accessed 2026-07-10 \u2014 \u00a7230(e)(1), no effect on federal criminal law. 18 U.S.C. \u00a72258A \u2014 accessed 2026-07-10 \u2014 NCMEC CyberTipline reporting duty, current through Pub. L. 119-60 (2025-12-18). Regulation (EU) 2022/2065 (Digital Services Act), Article 6 \u2014 eur-lex.europa.eu/eli/reg/2022/2065 \u2014 accessed 2026-07-10 \u2014 actual-knowledge-plus-inaction hosting liability standard. DSA Articles 16, 19, 24, and 37 \u2014 eu-digital-services-act.com/DigitalServicesAct_Articles.html \u2014 accessed 2026-07-10 \u2014 small/micro exemption scope (Section 3 minus Art. 24(3)), notice-and-action baseline (Art. 16, all sizes), audit obligation (Art. 37, VLOP/VLOSE-only). The Dawn of DSA Enforcement \u2014 Lessons from the Digital Services Coordinators' First Annual Reports, Platform Law Blog, 2025-10-06 \u2014 accessed 2026-07-10 \u2014 DSC enforcement reaching smaller platforms. Thiel & DiResta \u2014 \"Child Safety on Federated Social Media\", Stanford Internet Observatory, 2023-07-24 (see also fsi.stanford.edu coverage) \u2014 accessed 2026-07-10 \u2014 112 PhotoDNA CSAM matches, ~2,000 hashtag-flagged posts across 25 Mastodon instances. NIP-56: Reporting \u2014 accessed 2026-07-10 \u2014 warning against automated moderation on report volume. Nostrify \u2014 NPool \u2014 accessed 2026-07-10 \u2014 pool.req() vs pool.query() EOSE/timeout behavior, eoseTimeout default. nostr-ux.com \u2014 Core Interaction Loops \u2014 accessed 2026-07-10 \u2014 5s publish timeout, 3-relay confirm threshold, partial-success UI, background backoff retry. nostr-protocol/nips issue #261 \u2014 \"Metadata. Kind:0 Profiles.\" \u2014 accessed 2026-07-10 \u2014 replaceable-event field-overwrite failure class. NIP-66: Relay Liveness Monitoring \u2014 accessed 2026-07-10 \u2014 kind 30166/10166, graceful-degradation clause. strfry README \u2014 Prometheus metrics \u2014 accessed 2026-07-10 \u2014 built-in /metrics endpoint. scsibug/nostr-rs-relay (see server.rs) \u2014 accessed 2026-07-10 \u2014 built-in create_metrics() Prometheus registry. Grafana dashboard 21844 \u2014 Ditto \u2014 accessed 2026-07-10 \u2014 community-maintained Ditto operational dashboard. Maintainers' internal production-secrets-longevity audit note (companion document, not part of this public chapter set; same-session production audit) \u2014 internal source, 2026-07-10 \u2014 Ditto backup-runbook absence (twice-confirmed), funding verdict, bus-factor measurements. NIP-41 pull request #829 \u2014 accessed 2026-07-10 \u2014 unmerged since October 2023, griefing-risk objection. NIP-26: Delegated Event Signing \u2014 accessed 2026-07-10 (also ch06) \u2014 deprecated. FROSTR-ORG/bifrost \u2014 accessed 2026-07-10 \u2014 FROST threshold-signing library, v2.0.2 (2026-01-25), documented threat model. FROSTR-ORG/frost2x \u2014 accessed 2026-07-10 \u2014 browser-extension signer, \"under heavy development.\" Keycast \u2014 accessed 2026-07-10 \u2014 team key management, May 2026 audit caveat (quoted verbatim from README). This manual, ch06 \u00a73 correction log \u2014 DITTONSEC (Ditto, Deno+Postgres) vs NOSTRNSEC (ditto-relay, Bun+OpenSearch); see ch06. NIP-49: Private Key Encryption \u2014 accessed 2026-07-10 (also ch06) \u2014 ncryptsec backup format. gitleaks default config \u2014 accessed 2026-07-10 \u2014 ~190+ default rules, zero Nostr coverage. The maintainers' .gitleaks.toml (their own workspace root) \u2014 read directly, 2026-07-10 \u2014 three custom Nostr credential rules, landed same-day as the source audit. trespies-stack/.agents/skills/nostr-security/SKILL.md (the maintainers' own MKStack fork) \u2014 read directly, 2026-07-10 \u2014 confirmed XSS/CSP/injection-only scope; no custody or .env coverage. Black Hat USA 2025 \u2014 \"Not Sealed: Practical Attacks on Nostr, a Decentralized Censorship-Resistant Protocol\" (project page: crypto-sec-n.github.io) \u2014 presented 2025-08-06 \u2014 accessed 2026-07-10 \u2014 named affected clients, attack classes, mitigation recommendations. eprint.iacr.org/2025/1459 \u2014 \"Not in The Prophecies: Practical Attacks on Nostr\" \u2014 accessed 2026-07-10 \u2014 abstract, attack-class taxonomy. damus-io/damus issue #1994 \u2014 \"Profile is wiped (Balaji's bug)\" \u2014 accessed 2026-07-10 \u2014 local profile-edit data-loss bug, 2024-02. damus-io/damus issue #2264 \u2014 \"bookmarks wiped on purple expiration\" \u2014 accessed 2026-07-10 \u2014 local data-loss bug, 2024-05. nostr.how \u2014 relays explainer \u2014 accessed 2026-07-10 \u2014 \"if all the relays... go offline, all your posts will be unretrievable.\" NIP-90: Data Vending Machines (also ch06) \u2014 accessed 2026-07-10 \u2014 deprecation notice, successor governance. Anthropic \u2014 \"Anthropic acquires Bun as Claude Code reaches $1B milestone\" \u2014 accessed 2026-07-10 \u2014 acquisition announcement, 2025-12-02; Bun remains MIT-licensed. Bun \u2014 \"Bun is joining Anthropic\" \u2014 accessed 2026-07-10 \u2014 corroborating first-party announcement."
    },
    {
      "id": "nips/01-content-language.en",
      "kind": "nip",
      "lang": "en",
      "title": "Language labels clients actually use",
      "url": "/NIPs/#content-language",
      "md_url": "/NIPs/md/01-content-language.en.md",
      "sha256": "5860661049641a103fb7db790d75bc80879567cd44714e500dc18fd7965bc30e",
      "bytes": 2544,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Nostr has no ratified way to say what language an event is written in. Soapbox's own founder tried \u2014 NIP-37 \"Language Tag\" closed unmerged in 2024, with the standing objection that \"all automatic translation tools will already detect the language automatically anyway.\" A second proposal (PR #1127) is still open, still unmerged. Meanwhile the read side already shipped: NIP-50 defines a language: search filter and relay software implements it \u2014 but almost nothing on the publish side labels consistently, so there is nothing reliable to filter. Result: a Spanish-speaking user cannot dependably ask for their own language. The gap This is not a missing spec. NIP-32 labeling is ratified and its spec literally contains the example \u2014 [\"L\",\"ISO-639-1\"], [\"l\",\"en\",\"ISO-639-1\"]. What's missing is a publish-side convention plus an adoption loop. And the auto-detection objection fails exactly where we live: short notes, code-mixed Spanish/English, and relay-level filtering that shouldn't require content analysis of every event. What we're sketching A thin convention document: NIP-32 language labels on kinds 1 and 30023, localized NIP-89 handler metadata so app directories aren't English-only, and a namespace caution (NIP-C0 already uses an l tag for programming language). Reference implementations, not just prose: an MKStack skill, and our es-layer forks labeling on publish. Where PR #1127 overlaps, we support it rather than compete with it. Why us Bilingual isn't a feature for us; it's the firm's thesis. We ship Spanish layers with symmetric EN/ES parity gates, and we hit this gap on every one of them. Receipts NIP-37 \"Language Tag\" \u2014 PR #632 \u2014 closed unmerged 2024-06-07, objection quoted from the thread PR #1127 \u2014 Internationalization and Localization \u2014 still open, unmerged NIP-32: Labeling \u2014 ratified; contains the ISO-639-1 language example NIP-50: Search Capability \u2014 language: filter, read-side NIP-C0: Code Snippets \u2014 the other l tag; namespace caution ditto-relay \u2014 shipping language: search filtering today"
    },
    {
      "id": "nips/01-content-language.es",
      "kind": "nip",
      "lang": "es",
      "title": "Etiquetas de idioma que los clientes de verdad usen",
      "url": "/NIPs/#content-language",
      "md_url": "/NIPs/md/01-content-language.es.md",
      "sha256": "7f5cfe8dbac1355569a94a8a610d5246beadb9b221ef258ecff2ee395bd5e7ae",
      "bytes": 2825,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Evidencia"
      ],
      "body": "Nostr no tiene una forma ratificada de decir en qu\u00e9 idioma est\u00e1 escrito un evento. El propio fundador de Soapbox lo intent\u00f3 \u2014 NIP-37 \"Language Tag\" se cerr\u00f3 sin fusionarse en 2024, con la objeci\u00f3n de que \"las herramientas de traducci\u00f3n autom\u00e1tica ya detectan el idioma de todos modos\". Una segunda propuesta (PR #1127) sigue abierta, sin fusionarse. Mientras tanto, el lado de lectura ya existe: NIP-50 define un filtro de b\u00fasqueda language: y hay software de relay que lo implementa \u2014 pero casi nadie etiqueta al publicar de forma consistente, as\u00ed que no hay nada confiable que filtrar. Resultado: una persona hispanohablante no puede pedir su propio idioma de manera confiable. La brecha No falta una especificaci\u00f3n. NIP-32 (etiquetado) est\u00e1 ratificado y su propio texto contiene el ejemplo \u2014 [\"L\",\"ISO-639-1\"], [\"l\",\"en\",\"ISO-639-1\"]. Lo que falta es una convenci\u00f3n del lado de publicaci\u00f3n y un ciclo de adopci\u00f3n. Y la objeci\u00f3n de la detecci\u00f3n autom\u00e1tica falla justo donde vivimos nosotros: notas cortas, texto mezclado espa\u00f1ol/ingl\u00e9s, y filtrado a nivel de relay que no deber\u00eda exigir analizar el contenido de cada evento. Lo que estamos esbozando Un documento de convenci\u00f3n delgado: etiquetas de idioma NIP-32 en los kinds 1 y 30023, metadatos NIP-89 localizados para que los directorios de aplicaciones no existan solo en ingl\u00e9s, y una advertencia de espacios de nombres (NIP-C0 ya usa una etiqueta l para lenguaje de programaci\u00f3n). Implementaciones de referencia, no solo prosa: un skill de MKStack, y nuestras capas en espa\u00f1ol etiquetando al publicar. Donde PR #1127 coincida, lo apoyamos en lugar de competir. Por qu\u00e9 nosotros Para nosotros lo biling\u00fce no es una funci\u00f3n; es la tesis de la firma. Publicamos capas en espa\u00f1ol con verificaciones sim\u00e9tricas de paridad EN/ES, y chocamos con esta brecha en cada una. Evidencia NIP-37 \"Language Tag\" \u2014 PR #632 \u2014 cerrado sin fusionar el 2024-06-07; la objeci\u00f3n est\u00e1 citada del hilo PR #1127 \u2014 Internationalization and Localization \u2014 sigue abierto, sin fusionar NIP-32: Labeling \u2014 ratificado; contiene el ejemplo ISO-639-1 NIP-50: Search Capability \u2014 filtro language:, lado de lectura NIP-C0: Code Snippets \u2014 la otra etiqueta l; advertencia de espacios de nombres ditto-relay \u2014 ya implementa b\u00fasqueda con language:"
    },
    {
      "id": "nips/02-push-delivery.en",
      "kind": "nip",
      "lang": "en",
      "title": "Push delivery, revived",
      "url": "/NIPs/#push-delivery",
      "md_url": "/NIPs/md/02-push-delivery.en.md",
      "sha256": "86e7d1e599010221727c2f7f682f3b20d78e6bdc5313f7817a171c581966bbfc",
      "bytes": 2312,
      "headings": [
        "Why it matters more than it looks",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "No NIP covers push notifications. We scanned the full NIP index \u2014 nothing numbered, lettered, or hex-coded addresses how an event reaches a phone that isn't looking. The one serious attempt, Amethyst's \"Event Watcher API\" (PR #1528), had already run in production for about a year before it was even proposed \u2014 and it still closed unmerged in 2025, with the author's own note that Pokey's success made him question whether the idea was worth pursuing. The gap didn't close; the person carrying it put it down. Why it matters more than it looks Apple's Lockdown Mode blocks Service Workers entirely, so PWA web-push isn't degraded there \u2014 it's absent. The users who opt into the highest security get the least notification capability, and every consumer Nostr app re-solves this privately or ships without it. What we're sketching Study before proposing: PR #1528's design and Pokey's working model first. The likely shape is a slim registration spec with wrapped delivery \u2014 the push server should never learn which pubkey you watch. But the first deliverable is practical, not protocol: an MKStack skill that standardizes the non-protocol fallback (native push via Capacitor/APNs/FCM, web-push where it exists, honest Lockdown Mode behavior) so scaffolded apps stop re-solving it one at a time. A fallback pattern people actually ship beats a spec nobody implements. Why us We're building bilingual consumer surfaces on this stack, and civic information is time-sensitive \u2014 a deadline notice that arrives late is a notice that didn't arrive. Receipts PR #1528 \u2014 Push Notification, Event Watcher API \u2014 closed unmerged 2025-07-31; in production on Amethyst ~a year prior NIP index \u2014 scanned in full; no push standard exists MKStack lockdown-mode skill \u2014 Service Workers sit in the blocked-entirely tier MKStack capacitor skill \u2014 the native wrap the fallback rides on"
    },
    {
      "id": "nips/02-push-delivery.es",
      "kind": "nip",
      "lang": "es",
      "title": "Notificaciones push, retomadas",
      "url": "/NIPs/#push-delivery",
      "md_url": "/NIPs/md/02-push-delivery.es.md",
      "sha256": "33d6a23cb96602a91a2700c869a73ed967b596a5461d46743046c67362eeb9c8",
      "bytes": 2573,
      "headings": [
        "Por qu\u00e9 importa m\u00e1s de lo que parece",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Evidencia"
      ],
      "body": "Ning\u00fan NIP cubre las notificaciones push. Revisamos el \u00edndice completo de NIPs \u2014 nada, con n\u00famero, letra o c\u00f3digo hex, define c\u00f3mo un evento llega a un tel\u00e9fono que no est\u00e1 mirando. El \u00fanico intento serio, el \"Event Watcher API\" de Amethyst (PR #1528), ya llevaba cerca de un a\u00f1o funcionando en producci\u00f3n antes de proponerse \u2014 y aun as\u00ed se cerr\u00f3 sin fusionarse en 2025, con una nota del propio autor diciendo que el \u00e9xito de Pokey lo hizo dudar de si val\u00eda la pena seguir. La brecha no se cerr\u00f3; la persona que la cargaba la solt\u00f3. Por qu\u00e9 importa m\u00e1s de lo que parece El Lockdown Mode de Apple bloquea los Service Workers por completo, as\u00ed que el push web de una PWA ah\u00ed no se degrada \u2014 desaparece. Las personas que eligen la m\u00e1xima seguridad reciben la menor capacidad de notificaci\u00f3n, y cada aplicaci\u00f3n de consumo en Nostr resuelve esto en privado o publica sin resolverlo. Lo que estamos esbozando Estudiar antes de proponer: primero el dise\u00f1o de PR #1528 y el modelo de Pokey. La forma probable es una especificaci\u00f3n delgada de registro con entrega envuelta \u2014 el servidor de push nunca deber\u00eda saber qu\u00e9 pubkey observas. Pero el primer entregable es pr\u00e1ctico, no de protocolo: un skill de MKStack que estandarice la alternativa fuera del protocolo (push nativo v\u00eda Capacitor/APNs/FCM, push web donde exista, comportamiento honesto bajo Lockdown Mode) para que las aplicaciones dejen de resolverlo una por una. Un patr\u00f3n que la gente de verdad publica vale m\u00e1s que una especificaci\u00f3n que nadie implementa. Por qu\u00e9 nosotros Construimos superficies de consumo biling\u00fces sobre este stack, y la informaci\u00f3n c\u00edvica es sensible al tiempo \u2014 un aviso de plazo que llega tarde es un aviso que no lleg\u00f3. Evidencia PR #1528 \u2014 Push Notification, Event Watcher API \u2014 cerrado sin fusionar el 2025-07-31; en producci\u00f3n en Amethyst ~un a\u00f1o antes \u00cdndice de NIPs \u2014 revisado completo; no existe est\u00e1ndar de push Skill lockdown-mode de MKStack \u2014 los Service Workers est\u00e1n en el nivel bloqueado-por-completo Skill capacitor de MKStack \u2014 el envoltorio nativo sobre el que corre la alternativa"
    },
    {
      "id": "nips/03-replaceable-merge.en",
      "kind": "nip",
      "lang": "en",
      "title": "Stop wiping profiles: merge semantics for replaceable events",
      "url": "/NIPs/#replaceable-merge",
      "md_url": "/NIPs/md/03-replaceable-merge.en.md",
      "sha256": "2c409e08ccaa223b548d04d0bf90bfb22fb96233fb0b24f440bf58041bb46d93",
      "bytes": 2098,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Profiles (kind 0) and contact lists (kind 3) are replaceable events: last write wins, whole event. A client that publishes its own partial view of a profile silently erases every field it doesn't understand \u2014 for everyone, everywhere. The protocol's own tracker has documented this since 2023 (issue #261), and it bites real users: Damus's \"Balaji's bug\" was a profile wiped by exactly this mechanism. Relays can't fix it \u2014 for each pubkey and kind, only the latest event is stored. Only clients can. The gap There is no stated rule that a client publishing a replaceable event should first merge against the latest known state and preserve fields it doesn't recognize. Every client that gets this right does so by folklore; every new client gets a chance to wipe your lightning address. What we're sketching A small SHOULD: before publishing a replaceable kind, fetch the latest known event, deep-merge your changes into it, and preserve unknown fields verbatim. Alongside the prose, the part we think matters more: a conformance fixture set \u2014 event pairs where a correct merge has one right answer \u2014 and a reference implementation as an MKStack skill/hook, so scaffolded apps get safe publishing without reading a spec. Open question we're researching: whether unknown-field preservation can be specified tightly enough to test without freezing legitimate field deletion. Why us We're shipping apps on the scaffold this failure class lives in, and \"your app quietly destroyed my profile\" is the kind of trust failure a civic tool can't survive. Receipts nostr-protocol/nips issue #261 \u2014 the field-overwrite failure class, documented and open Damus issue #1994 \u2014 \"Profile is wiped (Balaji's bug)\" Damus issue #2264 \u2014 bookmarks wiped \u2014 same lesson, different surface"
    },
    {
      "id": "nips/03-replaceable-merge.es",
      "kind": "nip",
      "lang": "es",
      "title": "Dejar de borrar perfiles: sem\u00e1ntica de fusi\u00f3n para eventos reemplazables",
      "url": "/NIPs/#replaceable-merge",
      "md_url": "/NIPs/md/03-replaceable-merge.es.md",
      "sha256": "e388f199afade0cd28c807bd65a47fe10acd54f99bbace7e918a58f4ed9b197c",
      "bytes": 2414,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Evidencia"
      ],
      "body": "Los perfiles (kind 0) y las listas de contactos (kind 3) son eventos reemplazables: gana la \u00faltima escritura, el evento completo. Un cliente que publica su vista parcial de un perfil borra en silencio cada campo que no entiende \u2014 para todos, en todas partes. El propio rastreador del protocolo lo documenta desde 2023 (issue #261), y afecta a usuarios reales: el \"bug de Balaji\" en Damus fue un perfil borrado exactamente por este mecanismo. Los relays no pueden arreglarlo \u2014 por cada pubkey y kind solo se guarda el evento m\u00e1s reciente. Solo los clientes pueden. La brecha No existe una regla que diga que un cliente, antes de publicar un evento reemplazable, deber\u00eda fusionar contra el \u00faltimo estado conocido y preservar los campos que no reconoce. Cada cliente que lo hace bien lo hace por tradici\u00f3n oral; cada cliente nuevo tiene su oportunidad de borrar tu direcci\u00f3n de lightning. Lo que estamos esbozando Un SHOULD peque\u00f1o: antes de publicar un kind reemplazable, obtener el \u00faltimo evento conocido, fusionar los cambios sobre \u00e9l, y preservar los campos desconocidos tal cual. Junto a la prosa, la parte que creemos que importa m\u00e1s: un conjunto de casos de conformidad \u2014 pares de eventos donde una fusi\u00f3n correcta tiene una sola respuesta v\u00e1lida \u2014 y una implementaci\u00f3n de referencia como skill/hook de MKStack, para que las aplicaciones generadas publiquen de forma segura sin leer una especificaci\u00f3n. Pregunta abierta que investigamos: si la preservaci\u00f3n de campos desconocidos puede especificarse con suficiente precisi\u00f3n para probarse sin congelar el borrado leg\u00edtimo de campos. Por qu\u00e9 nosotros Publicamos aplicaciones sobre el mismo andamiaje donde vive esta clase de falla, y \"tu aplicaci\u00f3n destruy\u00f3 mi perfil en silencio\" es el tipo de falla de confianza que una herramienta c\u00edvica no sobrevive. Evidencia nostr-protocol/nips issue #261 \u2014 la clase de falla de sobreescritura de campos, documentada y abierta Damus issue #1994 \u2014 \"Profile is wiped (Balaji's bug)\" Damus issue #2264 \u2014 marcadores borrados \u2014 misma lecci\u00f3n, otra superficie"
    },
    {
      "id": "nips/04-retention-honesty.en",
      "kind": "nip",
      "lang": "en",
      "title": "Relays that say what they keep",
      "url": "/NIPs/#retention-honesty",
      "md_url": "/NIPs/md/04-retention-honesty.en.md",
      "sha256": "89c5f4c100076d4c55500c91d2931a96c7b58406cff5e81ba1c70ebdb552fbdd",
      "bytes": 2000,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Not one relay or media host we could find publishes a contractual durability promise \u2014 free or paid. The measured economics explain why: 95% of free relays can't cover operating costs from zap income, and 64% receive zero zaps at all (Wei & Tyson, CoNEXT '25). Users treat relays as storage; the economics say they're caches. NIP-11 lets a relay describe its operational limits, and NIP-66 monitors whether a relay is alive \u2014 but there is no standard, machine-readable way for a relay to declare how long it keeps events, and nothing that checks such a declaration against observed behavior. The gap Durability on Nostr is currently a vibe. A user picking write relays, or an organization with records-retention obligations, has no signal to select on \u2014 liveness isn't retention, and payment isn't a promise. What we're sketching Three pieces that only work together: a machine-readable retention declaration (a NIP-11 extension or companion event), NIP-66-class monitors that verify claims longitudinally \u2014 \"promised 30 days; observed 90\" \u2014 so declarations earn reputations, and client UX that surfaces it at relay-selection time. Declared retention that nobody verifies is marketing; verified retention is infrastructure. Why us We run the archive-relay pattern ourselves (own strfry as source of truth, public relays as reach), and we build for civic organizations that answer to actual records-retention rules. Receipts Wei & Tyson \u2014 An Empirical Analysis of the Nostr Social Network \u2014 95% / 64% / p90 zap-income figures NIP-11: Relay Information Document \u2014 limitation fields exist; no retention promise does NIP-66: Relay Discovery and Liveness Monitoring \u2014 liveness, not durability"
    },
    {
      "id": "nips/04-retention-honesty.es",
      "kind": "nip",
      "lang": "es",
      "title": "Relays que digan qu\u00e9 guardan",
      "url": "/NIPs/#retention-honesty",
      "md_url": "/NIPs/md/04-retention-honesty.es.md",
      "sha256": "5899b02068030872e9861174a6c884aef7ba39c0bfcc59d73e14cc1f09c375c9",
      "bytes": 2315,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Evidencia"
      ],
      "body": "Ning\u00fan relay ni servidor de medios que pudimos encontrar publica una promesa contractual de durabilidad \u2014 gratuito o de pago. La econom\u00eda medida explica por qu\u00e9: el 95% de los relays gratuitos no cubre sus costos operativos con ingresos por zaps, y el 64% no recibe ning\u00fan zap (Wei & Tyson, CoNEXT '25). La gente trata los relays como almacenamiento; la econom\u00eda dice que son cach\u00e9s. NIP-11 permite que un relay describa sus l\u00edmites operativos, y NIP-66 monitorea si un relay est\u00e1 vivo \u2014 pero no existe una forma est\u00e1ndar y legible por m\u00e1quina de que un relay declare cu\u00e1nto tiempo guarda los eventos, ni nada que compare esa declaraci\u00f3n con el comportamiento observado. La brecha Hoy la durabilidad en Nostr es una sensaci\u00f3n. Una persona eligiendo sus relays de escritura, o una organizaci\u00f3n con obligaciones de retenci\u00f3n de registros, no tiene ninguna se\u00f1al sobre la cual decidir \u2014 estar vivo no es retener, y cobrar no es prometer. Lo que estamos esbozando Tres piezas que solo funcionan juntas: una declaraci\u00f3n de retenci\u00f3n legible por m\u00e1quina (una extensi\u00f3n de NIP-11 o un evento compa\u00f1ero), monitores tipo NIP-66 que verifiquen las declaraciones a lo largo del tiempo \u2014 \"prometi\u00f3 30 d\u00edas; se observaron 90\" \u2014 para que las declaraciones ganen reputaci\u00f3n, y una interfaz de cliente que lo muestre al momento de elegir relays. Una retenci\u00f3n declarada que nadie verifica es publicidad; una retenci\u00f3n verificada es infraestructura. Por qu\u00e9 nosotros Nosotros mismos operamos el patr\u00f3n de relay de archivo (strfry propio como fuente de verdad, relays p\u00fablicos como alcance), y construimos para organizaciones c\u00edvicas que responden a reglas reales de retenci\u00f3n de registros. Evidencia Wei & Tyson \u2014 An Empirical Analysis of the Nostr Social Network \u2014 las cifras de 95% / 64% / p90 de ingresos por zaps NIP-11: Relay Information Document \u2014 existen campos de limitation; una promesa de retenci\u00f3n, no NIP-66: Relay Discovery and Liveness Monitoring \u2014 vivacidad, no durabilidad"
    },
    {
      "id": "nips/05-open-data-provenance.en",
      "kind": "nip",
      "lang": "en",
      "title": "Public datasets on open rails",
      "url": "/NIPs/#open-data-provenance",
      "md_url": "/NIPs/md/05-open-data-provenance.en.md",
      "sha256": "1ecbd64edc29f3e84732e69958815121227add0ca7d722d9c8aa86031604ec3c",
      "bytes": 2168,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Public-interest data \u2014 census extracts, language-access data, eviction filings \u2014 lives on servers that get defunded, redesigned, or quietly taken down. Nostr already over-replicates social events (the average post lands on 34.6 relays, measured), but it has no convention for announcing a dataset: what it is, where it came from, which vintage, what license, where the mirrors are. Before building a census atlas on this stack we looked for a precedent; none exists. The gap NIP-94 describes a file. A dataset needs more: source authority, vintage (ACS 2019\u20132023 is not ACS 2020\u20132024), geographic coverage, license, content hash, and a mirror list a client can actually resolve. Without that, \"the data is decentralized\" is a slogan \u2014 you can't verify what a dashboard is built on, and you can't re-host what you can't identify. What we're sketching A NIP-94-family announcement for datasets: source, vintage, geography, license, sha256, mirror list (Blossom BUD-04 mirroring makes the copies real). The consumer story: a civic dashboard cites the announcement event, anyone verifies the hash, anyone re-hosts the blob, and the dashboard survives its original host. We're dogfooding the substrate now \u2014 a bilingual census atlas served entirely from static tiles \u2014 and the announcement convention is the missing provenance layer under it. Why us Equity data for overlooked communities is our practice. The communities most likely to need this data are the least served by the infrastructure that currently holds it. Receipts NIP-94: File Metadata \u2014 the base shape to extend BUD-04: Mirroring Blobs \u2014 server-to-server mirroring; makes mirror lists real Wei & Tyson \u2014 replication exists (34.6 relays/event); provenance doesn't The Soapbox Stack Operator Manual, ch. 09 \u2014 the atlas substrate we're dogfooding"
    },
    {
      "id": "nips/05-open-data-provenance.es",
      "kind": "nip",
      "lang": "es",
      "title": "Datos p\u00fablicos sobre rieles abiertos",
      "url": "/NIPs/#open-data-provenance",
      "md_url": "/NIPs/md/05-open-data-provenance.es.md",
      "sha256": "dba6d98c1dfdfb812a57277076bc2313202b9a06f3a994d7dc185d7a2b77376b",
      "bytes": 2436,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Evidencia"
      ],
      "body": "Los datos de inter\u00e9s p\u00fablico \u2014 extractos del censo, datos de acceso ling\u00fc\u00edstico, registros de desalojos \u2014 viven en servidores que pierden fondos, se redise\u00f1an o se retiran sin aviso. Nostr ya sobre-replica los eventos sociales (una publicaci\u00f3n promedio llega a 34.6 relays, medido), pero no tiene una convenci\u00f3n para anunciar un conjunto de datos: qu\u00e9 es, de d\u00f3nde viene, de qu\u00e9 vendimia, con qu\u00e9 licencia, d\u00f3nde est\u00e1n los espejos. Antes de construir un atlas del censo sobre este stack buscamos un precedente; no existe. La brecha NIP-94 describe un archivo. Un conjunto de datos necesita m\u00e1s: autoridad de origen, vendimia (ACS 2019\u20132023 no es ACS 2020\u20132024), cobertura geogr\u00e1fica, licencia, hash del contenido, y una lista de espejos que un cliente pueda resolver. Sin eso, \"los datos son descentralizados\" es un eslogan \u2014 no puedes verificar sobre qu\u00e9 est\u00e1 construido un tablero, y no puedes re-hospedar lo que no puedes identificar. Lo que estamos esbozando Un anuncio de la familia NIP-94 para conjuntos de datos: origen, vendimia, geograf\u00eda, licencia, sha256, lista de espejos (el espejado BUD-04 de Blossom hace que las copias sean reales). La historia del consumidor: un tablero c\u00edvico cita el evento de anuncio, cualquiera verifica el hash, cualquiera re-hospeda el blob, y el tablero sobrevive a su servidor original. Ya estamos probando el sustrato \u2014 un atlas del censo biling\u00fce servido enteramente desde teselas est\u00e1ticas \u2014 y la convenci\u00f3n de anuncio es la capa de procedencia que le falta debajo. Por qu\u00e9 nosotros Los datos de equidad para comunidades pasadas por alto son nuestra pr\u00e1ctica. Las comunidades que m\u00e1s van a necesitar estos datos son las peor servidas por la infraestructura que hoy los guarda. Evidencia NIP-94: File Metadata \u2014 la forma base a extender BUD-04: Mirroring Blobs \u2014 espejado servidor a servidor; hace reales las listas de espejos Wei & Tyson \u2014 la replicaci\u00f3n existe (34.6 relays/evento); la procedencia no Manual del operador del stack Soapbox, cap. 09 \u2014 el sustrato del atlas que estamos probando"
    },
    {
      "id": "nips/06-provenance-envelope.en",
      "kind": "nip",
      "lang": "en",
      "title": "One envelope for everything we publish",
      "url": "/NIPs/#provenance-envelope",
      "md_url": "/NIPs/md/06-provenance-envelope.en.md",
      "sha256": "60df5c75cd34c596e7a48a1db936fc6bbf694c7e77eaf80257e8c200b6294c92",
      "bytes": 2512,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Our open-data idea (#5) sketches dataset announcements: source, vintage, license, hash, mirrors. Designing an agent-navigable search layer taught us the problem isn't dataset-shaped \u2014 it's everything-shaped. A document, a UI component, and a search-corpus entry raise the identical questions: who published this, from what source, which version, under what license, and how do I verify the bytes? Today each artifact class answers differently or not at all, and an agent acting on retrieved content inherits whichever answer is missing. The gap NIP-94 describes a file; idea #5 extends it to datasets. Nothing extends it to the general case. Without one envelope shape, every consumer writes per-type verification or skips it \u2014 and \"verifiable\" quietly narrows to \"verifiable if it happens to be a dataset.\" What we're sketching One provenance envelope, NIP-94-family, with an artifact-type tag: source authority, vintage, license, content hash, mirror list (BUD-04 makes mirrors real), signing key \u2014 the same fields whether the artifact is a dataset, a document, a component manifest, or a search-corpus entry. Consumers verify hashes opportunistically; retrieval surfaces display what was and wasn't verified instead of laundering the difference. We've adopted this as internal architecture law (decision record 0009, ratified 2026-07-10 \u2014 internal), and our publishing pipeline already emits a per-file sha256 index for every page on this site; the envelope is the standard shape missing around practice we already run. Per idea #3's lesson: conformance fixtures alongside the prose, or it doesn't graduate. Why us We build civic surfaces where \"what is this dashboard built on\" must have a checkable answer, and we're building search whose results agents act on. Unverifiable retrieval is how confident errors scale. Receipts NIP-94: File Metadata \u2014 the base shape to generalize BUD-04: Mirroring Blobs \u2014 mirror lists become real Idea #5 \u2014 Public datasets on open rails \u2014 the dataset-shaped ancestor Wei & Tyson \u2014 replication exists (34.6 relays/event); provenance doesn't This site's own index.json faces \u2014 per-file sha256, the practice the envelope standardizes"
    },
    {
      "id": "nips/06-provenance-envelope.es",
      "kind": "nip",
      "lang": "es",
      "title": "Un sobre para todo lo que publicamos",
      "url": "/NIPs/#provenance-envelope",
      "md_url": "/NIPs/md/06-provenance-envelope.es.md",
      "sha256": "390f30cd61fe0b4218c25a969546fc3c92a802550508a9e65b53d6fe60091691",
      "bytes": 2801,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Recibos"
      ],
      "body": "Nuestra idea de datos abiertos (#5) esboza anuncios de conjuntos de datos: fuente, vigencia, licencia, hash, r\u00e9plicas. Dise\u00f1ar una capa de b\u00fasqueda navegable por agentes nos ense\u00f1\u00f3 que el problema no tiene forma de dataset \u2014 tiene forma de todo. Un documento, un componente de interfaz y una entrada del corpus de b\u00fasqueda plantean las mismas preguntas: qui\u00e9n public\u00f3 esto, desde qu\u00e9 fuente, qu\u00e9 versi\u00f3n, bajo qu\u00e9 licencia, y c\u00f3mo verifico los bytes. Hoy cada clase de artefacto responde distinto o no responde, y un agente que act\u00faa sobre contenido recuperado hereda la respuesta que falte. La brecha NIP-94 describe un archivo; la idea #5 lo extiende a datasets. Nada lo extiende al caso general. Sin una forma \u00fanica de sobre, cada consumidor escribe su propia verificaci\u00f3n por tipo o la omite \u2014 y \"verificable\" se reduce en silencio a \"verificable si resulta ser un dataset.\" Lo que estamos esbozando Un solo sobre de procedencia, de la familia NIP-94, con una etiqueta de tipo de artefacto: autoridad de la fuente, vigencia, licencia, hash del contenido, lista de r\u00e9plicas (BUD-04 hace reales las r\u00e9plicas), llave firmante \u2014 los mismos campos sea el artefacto un dataset, un documento, un manifiesto de componente o una entrada de corpus. Los consumidores verifican hashes de manera oportunista; las superficies de b\u00fasqueda muestran qu\u00e9 se verific\u00f3 y qu\u00e9 no, en vez de lavar la diferencia. Ya lo adoptamos como ley interna de arquitectura (registro de decisi\u00f3n 0009, ratificado 2026-07-10 \u2014 interno), y nuestra tuber\u00eda de publicaci\u00f3n ya emite un \u00edndice sha256 por archivo para cada p\u00e1gina de este sitio; el sobre es la forma est\u00e1ndar que le falta a una pr\u00e1ctica que ya corremos. Con la lecci\u00f3n de la idea #3: pruebas de conformidad junto a la prosa, o no se grad\u00faa. Por qu\u00e9 nosotros Construimos superficies c\u00edvicas donde \"de qu\u00e9 est\u00e1 hecho este tablero\" debe tener respuesta comprobable, y construimos b\u00fasqueda cuyos resultados los agentes usan para actuar. La recuperaci\u00f3n no verificable es c\u00f3mo escalan los errores confiados. Recibos NIP-94: File Metadata \u2014 la forma base a generalizar BUD-04: Mirroring Blobs \u2014 las listas de r\u00e9plicas se vuelven reales Idea #5 \u2014 Datos p\u00fablicos sobre rieles abiertos \u2014 el ancestro con forma de dataset Wei & Tyson \u2014 la replicaci\u00f3n existe (34.6 rel\u00e9s/evento); la procedencia no Las caras index.json de este mismo sitio \u2014 sha256 por archivo, la pr\u00e1ctica que el sobre estandariza"
    },
    {
      "id": "nips/07-agent-face-discovery.en",
      "kind": "nip",
      "lang": "en",
      "title": "Tell agents where your agent face is",
      "url": "/NIPs/#agent-face-discovery",
      "md_url": "/NIPs/md/07-agent-face-discovery.en.md",
      "sha256": "c9e41837865b1d53a15c8ffa3b141aa2c8970c9ff161340d60332bcf84a99333",
      "bytes": 2296,
      "headings": [
        "The gap",
        "What we're sketching",
        "Why us",
        "Receipts"
      ],
      "body": "Dual-face surfaces exist: sites ship llms.txt front doors, apps expose MCP endpoints, docs publish verbatim markdown beside the rendered page. We ship several ourselves. But nothing tells an arriving agent the machine face exists \u2014 on the web the convention is a well-known filename you have to guess at, and on Nostr there is nothing at all. NIP-89 announces which app can handle a kind; no event announces where a surface's agent-native representation lives. So agents scrape human pages even when a structured, hash-verified face sits one URL away. The gap Discovery. The faces exist; the pointer doesn't. Without a convention, every dual-face surface is dual-face only for agents that already know it \u2014 which mostly means the builder's own. What we're sketching A small announcement convention \u2014 likely NIP-89-adjacent \u2014 declaring, for a surface (a domain, an naddr, an app): where its agent faces live (llms.txt, markdown mirror, hash index, MCP endpoint) and what each speaks (contract, version, language coverage \u2014 the labels from idea #1 apply here too). The client story: resolve a surface \u2192 check for the announcement \u2192 consume the declared face; scraping demotes to fallback. Reference implementations before prose: our own pages announce their faces, and an MKStack skill packages the convention so scaffolded apps ship it by default. Why us Both our public pages already ship dual faces (rendered page + verbatim md + llms.txt + per-file sha256), and we're building search that consumes agent faces across surfaces \u2014 we're the first consumer this missing pointer bites. Publishing a face nobody can find is dual navigability in name only. Receipts llms.txt \u2014 the web-side front-door convention this extends past guessable filenames NIP-89: Recommended Application Handlers \u2014 the adjacent announcement shape Model Context Protocol \u2014 the live-query face agents already speak This site's own faces \u2014 /manual/llms.txt + /manual/index.json, the things an announcement would point at"
    },
    {
      "id": "nips/07-agent-face-discovery.es",
      "kind": "nip",
      "lang": "es",
      "title": "Dile a los agentes d\u00f3nde est\u00e1 tu cara para agentes",
      "url": "/NIPs/#agent-face-discovery",
      "md_url": "/NIPs/md/07-agent-face-discovery.es.md",
      "sha256": "8b495b96d9c204095c82e5692405ad49a3c58adc9cd6c55b6132c8b4ec7d578a",
      "bytes": 2645,
      "headings": [
        "La brecha",
        "Lo que estamos esbozando",
        "Por qu\u00e9 nosotros",
        "Recibos"
      ],
      "body": "Las superficies de doble cara existen: los sitios publican portadas llms.txt, las apps exponen endpoints MCP, la documentaci\u00f3n publica markdown literal junto a la p\u00e1gina renderizada. Nosotros mismos publicamos varias. Pero nada le dice a un agente que llega que la cara para m\u00e1quinas existe \u2014 en la web la convenci\u00f3n es un nombre de archivo conocido que hay que adivinar, y en Nostr no hay nada. NIP-89 anuncia qu\u00e9 app puede manejar un kind; ning\u00fan evento anuncia d\u00f3nde vive la representaci\u00f3n nativa-para-agentes de una superficie. As\u00ed que los agentes raspan p\u00e1ginas humanas aun cuando una cara estructurada y verificada por hash est\u00e1 a una URL de distancia. La brecha Descubrimiento. Las caras existen; el puntero no. Sin una convenci\u00f3n, cada superficie de doble cara lo es solo para los agentes que ya la conocen \u2014 es decir, casi siempre los del propio constructor. Lo que estamos esbozando Una convenci\u00f3n peque\u00f1a de anuncio \u2014 probablemente adyacente a NIP-89 \u2014 que declara, para una superficie (un dominio, un naddr, una app): d\u00f3nde viven sus caras para agentes (llms.txt, espejo markdown, \u00edndice de hashes, endpoint MCP) y qu\u00e9 habla cada una (contrato, versi\u00f3n, cobertura de idiomas \u2014 las etiquetas de la idea #1 aplican aqu\u00ed tambi\u00e9n). La historia del cliente: resolver una superficie \u2192 buscar el anuncio \u2192 consumir la cara declarada; raspar queda degradado a plan B. Implementaciones de referencia antes que prosa: nuestras propias p\u00e1ginas anuncian sus caras, y una habilidad de MKStack empaqueta la convenci\u00f3n para que las apps armadas con la plantilla la traigan por defecto. Por qu\u00e9 nosotros Nuestras dos p\u00e1ginas p\u00fablicas ya publican doble cara (p\u00e1gina renderizada + md literal + llms.txt + sha256 por archivo), y construimos b\u00fasqueda que consume caras de agente entre superficies \u2014 somos el primer consumidor al que este puntero ausente le muerde. Publicar una cara que nadie encuentra es doble navegabilidad solo de nombre. Recibos llms.txt \u2014 la convenci\u00f3n de portada del lado web que esto extiende m\u00e1s all\u00e1 de nombres adivinables NIP-89: Recommended Application Handlers \u2014 la forma de anuncio adyacente Model Context Protocol \u2014 la cara de consulta en vivo que los agentes ya hablan Las caras de este mismo sitio \u2014 /manual/llms.txt + /manual/index.json, lo que un anuncio se\u00f1alar\u00eda"
    },
    {
      "id": "nips/_intro.en",
      "kind": "nip-meta",
      "lang": "en",
      "title": "NIPs in progress",
      "url": "/NIPs/#intro",
      "md_url": "/NIPs/md/_intro.en.md",
      "sha256": "bd51a407ba0b230a66404cbffcdeffa50b3dabec86340ad745056f1b4add5177",
      "bytes": 868,
      "headings": [],
      "body": "TresPies is a bilingual equity-data and civic firm building on the Nostr stack \u2014 a census atlas on MKStack, Spanish layers for Soapbox-family apps, an archive relay. These are the protocol gaps we keep hitting while we build, published before they're polished. The status labels are honest: most of these are research, not drafts. Nothing here is a ratified NIP, or even a submitted one. We publish anyway because the venue works that way \u2014 NostrHub calls itself \"a meritocracy you configure yourself,\" and the way into a meritocracy is work, in public, with receipts. Every idea links its evidence. When one matures, we'll propose it where proposals belong \u2014 as a long-form draft on NostrHub \u2014 and this page will say so. Tell us where we're wrong: cruz@trespiesdesign.com."
    },
    {
      "id": "nips/_intro.es",
      "kind": "nip-meta",
      "lang": "es",
      "title": "NIPs en progreso",
      "url": "/NIPs/#intro",
      "md_url": "/NIPs/md/_intro.es.md",
      "sha256": "c6e1bc3236d893258c0df03e69b736920ee1aeff258899a21b003f35c82d9090",
      "bytes": 1018,
      "headings": [],
      "body": "TresPies es una firma biling\u00fce de datos de equidad y trabajo c\u00edvico que construye sobre el stack de Nostr \u2014 un atlas del censo sobre MKStack, capas en espa\u00f1ol para las aplicaciones de la familia Soapbox, un relay de archivo. Estas son las brechas del protocolo con las que seguimos tropezando mientras construimos, publicadas antes de estar pulidas. Las etiquetas de estado son honestas: la mayor\u00eda de esto es investigaci\u00f3n, no borradores. Nada aqu\u00ed es un NIP ratificado, ni siquiera uno presentado. Publicamos de todos modos porque as\u00ed funciona este espacio \u2014 NostrHub se describe como \"una meritocracia que t\u00fa mismo configuras\", y a una meritocracia se entra con trabajo, en p\u00fablico, con evidencia. Cada idea enlaza sus fuentes. Cuando alguna madure, la propondremos donde corresponde \u2014 como borrador de formato largo en NostrHub \u2014 y esta p\u00e1gina lo dir\u00e1. Dinos en qu\u00e9 nos equivocamos: cruz@trespiesdesign.com."
    },
    {
      "id": "nips/_watching.en",
      "kind": "nip-meta",
      "lang": "en",
      "title": "Watching, not carrying",
      "url": "/NIPs/#watching",
      "md_url": "/NIPs/md/_watching.en.md",
      "sha256": "26b2ba689d4b0c2d21471ee870f74e200c5094298a2185601a8c592ca2035fde",
      "bytes": 1095,
      "headings": [],
      "body": "Gaps we track without presuming to lead them. Listed so you know we know. NIP-41 key migration (PR #829) \u2014 open since October 2023, stalled on the griefing debate. Key custody is upstream of everything on this page; we watch it and design around its absence. NIP-62: Request to Vanish \u00d7 the EDPB's blockchain guidance (finalized 2026-07-08) \u2014 MUST-level deletion meets \"technically hard to delete is not an exemption.\" An operator-focused explainer is in progress. NIP-77: Negentropy syncing \u2014 draft/optional; adoption determines how cheap archive-relay sync gets. NIP-55: Android signer application \u2014 the third signing standard consumer apps must support alongside NIP-07 and NIP-46."
    },
    {
      "id": "nips/_watching.es",
      "kind": "nip-meta",
      "lang": "es",
      "title": "Observando, sin cargar",
      "url": "/NIPs/#watching",
      "md_url": "/NIPs/md/_watching.es.md",
      "sha256": "a6a25474671ca0b338b362fa885c88b5a42ed55b6daa0f5f30e17b316bfba353",
      "bytes": 1283,
      "headings": [],
      "body": "Brechas que seguimos sin pretender liderarlas. Las listamos para que sepas que las conocemos. Migraci\u00f3n de claves NIP-41 (PR #829) \u2014 abierto desde octubre de 2023, estancado en el debate sobre abuso (\"griefing\"). La custodia de claves est\u00e1 aguas arriba de todo lo que hay en esta p\u00e1gina; la observamos y dise\u00f1amos alrededor de su ausencia. NIP-62: Request to Vanish \u00d7 la gu\u00eda de blockchain del EDPB (finalizada el 2026-07-08) \u2014 el borrado de nivel MUST se encuentra con \"que sea t\u00e9cnicamente dif\u00edcil de borrar no es una exenci\u00f3n\". Hay un explicador para operadores en camino. NIP-77: Sincronizaci\u00f3n negentropy \u2014 borrador/opcional; su adopci\u00f3n determina qu\u00e9 tan barata resulta la sincronizaci\u00f3n de un relay de archivo. NIP-55: Aplicaci\u00f3n firmante en Android \u2014 el tercer est\u00e1ndar de firma que las aplicaciones de consumo deben soportar junto a NIP-07 y NIP-46."
    },
    {
      "id": "nips/_outro.en",
      "kind": "nip-meta",
      "lang": "en",
      "title": "Contact and provenance",
      "url": "/NIPs/#outro",
      "md_url": "/NIPs/md/_outro.en.md",
      "sha256": "798f6f2b2b61a83df4b6c383144408096f7d9498fd3810acdb43e9d06e45c62e",
      "bytes": 576,
      "headings": [],
      "body": "Write to cruz@trespiesdesign.com. An npub with NIP-05 verification on this domain ships with our first git-anchored repo \u2014 we're setting up key custody deliberately, not quickly, for the reasons this page keeps citing. Everything above is grounded in the Soapbox Stack Operator Manual we maintain on this same domain \u2014 16 chapters, live-verified citations, raw markdown and an llms.txt for agents. The raw markdown for this page is indexed at /NIPs/llms.txt, same convention."
    },
    {
      "id": "nips/_outro.es",
      "kind": "nip-meta",
      "lang": "es",
      "title": "Contacto y procedencia",
      "url": "/NIPs/#outro",
      "md_url": "/NIPs/md/_outro.es.md",
      "sha256": "b8ccc56f1c461d707943924f126e2df5e2f41f9704fe2fb8ebc08c11adea885f",
      "bytes": 676,
      "headings": [],
      "body": "Escr\u00edbenos a cruz@trespiesdesign.com. Un npub con verificaci\u00f3n NIP-05 en este dominio llegar\u00e1 con nuestro primer repositorio anclado en git \u2014 estamos configurando la custodia de claves con calma deliberada, no con prisa, por las mismas razones que esta p\u00e1gina cita una y otra vez. Todo lo anterior est\u00e1 fundamentado en el Manual del operador del stack Soapbox que mantenemos en este mismo dominio \u2014 16 cap\u00edtulos, citas verificadas en vivo, markdown crudo y un llms.txt para agentes. El markdown crudo de esta p\u00e1gina est\u00e1 indexado en /NIPs/llms.txt, misma convenci\u00f3n."
    }
  ]
}
