diff --git a/apps/web/content/blog/smirk-v0-3-0-nostr-and-self-hosting.mdx b/apps/web/content/blog/smirk-v0-3-0-nostr-and-self-hosting.mdx
index 304f3e7..ad58406 100644
--- a/apps/web/content/blog/smirk-v0-3-0-nostr-and-self-hosting.mdx
+++ b/apps/web/content/blog/smirk-v0-3-0-nostr-and-self-hosting.mdx
@@ -1,109 +1,204 @@
---
-title: "Build notes: Smirk v0.3.0, Nostr identity, and running your own backend"
+title: "Smirk Wallet v0.3.0: Nostr identity, three slate transports, and a backend you can run"
date: "2026-08-20"
-excerpt: "Notes from the v0.3.0 release window: a NIP-07 provider in the wallet, why a Nostr signature had to be treated as a credential rather than a UX prompt, and the self-hostable backend that came out of it."
+excerpt: "v0.3.0 makes Smirk federated end to end: a NIP-07 provider with tiered signing, Grin slates that travel over Nostr instead of a shared server, and smirk-backend-core released so you can host the whole thing yourself."
draft: false
---
-# Build notes: Smirk v0.3.0, Nostr identity, and running your own backend
+# Smirk Wallet v0.3.0
-Smirk v0.3.0 is cut and in store review, so it is not on anyone's machine yet. These are
-working notes from the release window rather than an announcement. Two things dominated it:
-putting Nostr identity into the wallet properly, and finishing the work that lets somebody
-else run the backend.
+v0.3.0 is out. It is the release that removes the last places Smirk assumed our
+infrastructure: the backend host is configurable, Grin is fully non-custodial, and the
+server that used to be ours is now a public repo you can run yourself.
-## A Nostr signature is a credential, not a prompt
+The wallet ships as a Chrome MV3 and Firefox extension, plus a Tauri 2.x desktop shell for
+Windows, macOS and Linux built from the same code path. Capacitor mobile is deferred to
+v0.4.
-The wallet now exposes a NIP-07 `window.nostr` provider, so Nostr-native sites can ask for
-your public key and have events signed without a second extension installed. That part is
-ordinary. The interesting part was deciding what a connected site may sign without asking
-again.
+## Federation
-The obvious design is a "remember this site" checkbox. We started there and it is wrong,
-because Nostr kinds are not equally dangerous and a signature is a bearer token. Signing a
-note is not the same act as signing a payment authorization, but both arrive through one
-function call.
+Nothing in the wallet points at `api.smirk.cash` any more. `homeDomain` is per-wallet
+configuration, and the backend it names is one instance of
+[smirk-backend-core](https://github.com/Such-Software/smirk-backend-core), which is now
+public under MIT.
-So event kinds are sorted into three tiers:
+
+
+
-- **money** (17, 27235, 30402, 22242): never auto-signed, never session-grantable. Every one
- gets an explicit per-event approval.
-- **session-grantable** (1, 7, 1059): notes, reactions, gift wraps. High volume, low
- consequence. A user may grant a time-boxed window where these sign without re-prompting.
-- **default**: everything else. Prompt every time. Unknown kinds land here, so a kind we
- have never seen is treated conservatively instead of permissively.
+The two backends share nothing. A wallet on `a.example` can pay a wallet on `b.example`
+because identity and message transport ride Nostr relays, not a shared database.
-Kind 27235 is the one worth dwelling on. It is NIP-98 HTTP auth, which reads like plumbing,
-and it was session-grantable in an early draft. But the backend mints a full session from a
-NIP-98 event via `POST /auth/nostr`. Leaving it grantable meant a connected site could
-quietly collect an auth token for the user's own wallet backend, using a permission the user
-thought they had granted for social posts. It is now money-tier, and there is an origin guard
-on the event's `u` tag as well.
+## Nostr identity, and why signing is tiered
-The enforcement lives in the wallet handler, not the approval dialog. The handler computes
-`sessionCovered=false` for anything not session-grantable and refuses to persist a money-tier
-kind into a session at all. The rule holds even if the approval UI is buggy, or hostile,
-which is the only version of that rule worth having.
+The wallet exposes a NIP-07 `window.nostr` provider, so Nostr-native sites request a public
+key and get events signed without a second extension. A multi-identity vault keeps separate
+keypairs apart, with an in-wallet switcher.
-## Paying a name instead of an address
+The part worth explaining is what a connected site may sign *without asking again*. A Nostr
+signature is a bearer credential, so that is a security decision rather than a convenience
+setting. Kinds are sorted into three tiers, and the wallet handler is the enforcement point:
+it computes `sessionCovered=false` for anything not session-grantable and refuses to persist
+a money-tier kind into a session at all, so the rule holds even if the approval UI is
+compromised.
-You can pay a NIP-05 address (`name@domain`) directly. The counterparty's key is pinned on
-first use, so a later key swap is surfaced rather than silently trusted. TOFU is not perfect,
-but the failure it prevents is the one that actually happens: a name resolving to a new key
-and the payment going somewhere else without comment.
+
+
+
-Grin got a specific benefit here. Grin is an interactive protocol, so a payment needs a round
-trip of slatepacks between sender and receiver, which historically meant a shared server or
-copy-pasting blobs by hand. Those can now travel as NIP-59 gift-wrapped direct messages. No
-shared server, no coordination step outside the wallet.
+Kind 27235 is the instructive one. NIP-98 HTTP auth reads like plumbing, and it was
+session-grantable in an early draft. But the backend mints a full session from a NIP-98 event
+via `POST /auth/nostr`, so a grant meant for social posting would have let a site collect an
+auth token for the user's own backend. It is money-tier now, with an origin guard on the
+event's `u` tag.
-## Federation, and the backend that came with it
+## Three transports for a Grin slate
-The wallet no longer assumes `api.smirk.cash`. The backend host is configurable per wallet,
-which is only a meaningful claim if there is something else to point it at. That is
-[smirk-backend-core](https://github.com/Such-Software/smirk-backend-core): Rust, Axum,
-PostgreSQL, MIT, and now public.
+Grin is interactive: a payment needs slatepack legs to travel between sender and receiver.
+A slate is one payload, and how it gets there is a separate choice with different trust
+properties.
-The design constraint was that the backend must never be able to spend your money, and the
-schema should make that structural rather than a promise. It stores public addresses, public
-keys, and for Monero and Wownero the incoming view keys. Never a spend key, never a seed.
-View credentials are forwarded per request to the chain backends that scan with them and are
-not persisted server-side. The wallet signs and broadcasts locally; the backend reads chains
-and relays bytes.
+
+
+
-Chain access is delegated rather than reimplemented:
+What you type in the send box picks the transport. An npub or NIP-05 handle routes over
+Nostr. A bare `grin1…` address falls back to clipboard, unless a same-instance lookup can
+bridge that address to its owner's npub, in which case it is upgraded to gift-wrap. The
+backend relay is a convenience for two users on one host and is never on the critical path,
+because there is no cross-backend relay federation and there deliberately isn't going to be.
+
+## The backend
+
+Rust, Axum, PostgreSQL. It gives a wallet chain reads, fee estimation and broadcast, Nostr
+identity, a price feed, a Grin slatepack mailbox and the public social-tips subsystem,
+without ever holding a spend key or a seed.
+
+It stores public addresses, public keys, and for Monero and Wownero the incoming view keys.
+View credentials are forwarded per request to whatever scans with them and are not persisted.
+Signing and broadcast happen in the wallet.
| Chain | Source |
-|-------|--------|
+|---|---|
| Bitcoin, Litecoin | Electrum / Fulcrum |
| Monero, Wownero | light-wallet-server, stateless view-key forwarding |
-| Grin | grin-lws, or grin-wallet in view-only mode plus a node |
+| Grin | grin-lws, or grin-wallet view-only plus a node |
-Each chain is independently feature-flagged, and a chain whose source is not configured
-reports `enabled: false` from `/capabilities` rather than failing when someone calls it. That
-distinction matters more than it sounds: a self-hoster who only cares about Bitcoin should
-get a working backend, not a broken Monero path.
+Chains are independently feature-flagged. One that is not configured reports
+`enabled: false` from `/capabilities` instead of failing when something calls it, so a
+Bitcoin-only deployment is a supported outcome rather than a half-broken one.
The HTTP contract is generated from the handlers into `openapi.json`, which is also what the
-wallet's client is generated from, with a CI gate that fails on drift. One artifact, two
-consumers, no hand-written client to fall out of date.
+wallet's client is generated from, with a CI gate that fails on drift.
-Grin ended up fully non-custodial as part of this. The backend used to hold Grin balances,
-outputs and transaction records; those endpoints and the server-side wallets table are gone.
-Grin outputs now use the standard deterministic rewind-nonce scheme, so a wallet restored
-from a seed phrase rediscovers its outputs from the chain, the way Bitcoin and Monero
-restores already worked. Outputs from earlier builds stay spendable.
+Grin became fully non-custodial in this release. The backend no longer holds Grin balances,
+outputs or transaction records; those endpoints and the server-side wallets table are gone.
+Grin outputs use the standard deterministic rewind-nonce scheme, so a wallet restored from a
+seed phrase rediscovers its outputs from the chain the way Bitcoin and Monero restores
+already did. Outputs from earlier builds stay spendable.
-Two smaller pieces are public for the same reason: a standalone
-[grin-lws](https://github.com/Such-Software/grin-lws) light wallet server, and a small
-non-custodial BTC/LTC payment processor that exposes a BTCPay-style invoice surface where
-funds go straight to operator-controlled addresses.
+Two supporting pieces are public for the same reason:
+[grin-lws](https://github.com/Such-Software/grin-lws), a standalone Grin light wallet server,
+and a small non-custodial BTC/LTC payment processor exposing a BTCPay-style invoice surface
+where funds go straight to operator-controlled addresses.
-## Status
+## Notes
-v0.3.0 is feature-complete and has been through a security review, but it is young. The
-schema and the API may still move. If you run it, run your own chain backends where you can,
-read the code first, and size your early deployments accordingly.
+v0.3.0 is feature-complete and has been through a security review, but the schema and API are
+young and may still move. If you self-host, run your own chain backends where you can and
+read the code first.
-The desktop shell (Tauri 2.x, Windows/macOS/Linux) ships alongside the extension from the
-same code path. Capacitor mobile is deferred to v0.4.
+Also in this release: taproot (`bc1p…`, `ltc1p…`) recipients, cross-chain sends blocked
+before they can destroy funds, encrypted public tip keys at rest, a fee you sign that matches
+the fee you were shown, and connected sites made visible and revocable in Settings.