Satscribe is a web application that transforms Bitcoin blocks and transactions into insightful, human-readable conversations.
Enter a transaction ID, block hash, or block height. The app fetches the blockchain data via the Blockstream API and generates a plain-language explanation with an AI model. Each chat is stored, so you can revisit or share it anytime.
Satscribe doesn’t require user accounts or passwords. Instead, it leverages the Nostr protocol to establish ownership of chats in a decentralized, privacy-friendly way.
- 🔎 Search the blockchain by txID, block hash or height
- 🤖 Streaming AI summaries from OpenAI, Groq or OpenRouter
- 🆓 Free-tier models by default — or bring your own API key
- 🌐 Fetches data from Blockstream and CoinGecko
- 💬 Ask follow-up questions and pick a persona (Educator, Developer, Storyteller)
- 💾 Chats are saved and can be shared or kept private
- 📈 Shows the latest block height and BTC price
- ⚡️ Lightning tipping after the free quota is reached
- 🗂️ View and search your previous chats
- 🔐 Login via Nostr
- PHP 8.2+
- Composer
- Node.js 20+ and npm
- SQLite
- Laravel 12.x
- An API key for one AI provider — see AI providers
Satscribe talks to any OpenAI-compatible chat-completions API. Three are allowlisted; a provider not in that list can never become an outbound request.
| Provider | Env var | Free tier |
|---|---|---|
| Groq | GROQ_API_KEY |
✅ every listed model — Llama 3.3 70B, GPT-OSS 120B, Llama 3.1 8B |
| OpenRouter | OPENROUTER_API_KEY |
✅ GPT-OSS 20B (also the only route to Claude) |
| OpenAI | OPENAI_API_KEY |
❌ paid only |
Three models per provider, chosen so each earns its place — cheapest, best or fastest — rather than listing everything on offer. Free models come first and paid ones cheapest-first, so the least expensive option is always nearest the top.
Set at least one. When a free-tier key is present it becomes the default, so
the app never spends OpenAI credit unless that is the only key configured.
free means "costs nothing at the provider's free tier" — every provider still
requires a key.
Claude is served with your OpenRouter key and paid for by the visitor in sats: they buy a pack of messages over Lightning, and each premium answer spends one. Credit is tied to their Nostr login so it follows them between devices.
OPENROUTER_API_KEY=sk-or-... # the key the packs are spent against
PREMIUM_PACK_SATS=500 # what a pack costs
PREMIUM_PACK_MESSAGES=20 # what it buysWithout OPENROUTER_API_KEY those models are simply bring-your-own-key, and no
price is advertised.
When no model can be reached, the app answers from the Blockstream data instead of showing an error. The summary states only figures that were actually fetched, and says plainly that no model wrote it — a graceful degradation, not a stand-in for an answer.
On by default. The failure is still logged as an error and the answer admits it,
so the outage stays visible; set AI_OFFLINE_FALLBACK=false if you would rather
a provider failure surfaced as an error card.
Visitors can also supply their own key in the model picker. It is kept in
localStorage, sent as an X-Ai-Api-Key header, and is never logged or stored
server-side.
git clone https://github.com/Chemaclass/satscribe.git
cd satscribe
composer install
npm install
cp .env.example .env
php artisan key:generateThen configure your .env. A free Groq key is the quickest way to a working install:
DB_CONNECTION=sqlite
# Pick at least one provider
GROQ_API_KEY=gsk_...
# OPENROUTER_API_KEY=sk-or-...
# OPENAI_API_KEY=sk-...
# OPENAI_MODEL=gpt-4o-miniAnd migrate the DB:
php artisan migrateRun the app for local development:
composer devOnce the server is running, open http://localhost:8000 and start a chat by entering a TXID, block hash or height. The assistant summarizes the data, and you can ask follow-up questions. All chats are stored and listed on the History page.
If your browser doesn't have a Nostr extension, you can still sign in with your private key or generate a new priv/public key to be temp stored in your local storage – more about it here.
composer test is the gate: it runs PHPStan (level 9 — the maximum — over
app, modules and tests) followed by PHPUnit.
composer fix && composer test # format, then the full gate
composer phpstan # static analysis only
vendor/bin/phpunit --testsuite=unit # fast loop
vendor/bin/phpunit --filter <name> # one class or methodUnit tests mock the interfaces in each module's Domain/ and never touch the
database or the network; anything needing the framework is a feature test.
Run formatting and tests automatically before each commit by enabling the provided pre-commit hook:
git config core.hooksPath githooksBusiness logic lives in modules/, each split into Domain, Application and
Infrastructure, with dependencies pointing one way:
Infrastructure → Application → Domain. See
docs/architecture.md for the module map and the rules
that keep those boundaries.
Notable changes are listed in CHANGELOG.md. The project deploys
continuously from main and does not tag versions.
Bug reports and pull requests are welcome. Please read the CONTRIBUTING guide and our Code of Conduct before participating.
The project is released under the MIT license.

