app 1.15.2 -> 1.16.0, appCode 460 -> 461. That single edit drives Android's versionName/versionCode, Desktop and CLI packageVersion, quartz's Maven version and geode's RelayInfo.VERSION; verified by reading the version back out of :amethyst, :quartz and :geode and from a built APK (versionCode 461, versionName 1.16.0-DEBUG). Roughly twenty substantive PRs since v1.15.2, written up in docs/changelog/v1.16.00.md. The ones a user feels: - My Fitness: a training dashboard built from both sources Amethyst has -- Health Connect and the user's own kind 1301 events -- so it works with no health permission at all. Workouts gains a "Mine" filter in the top nav, and a workout that is already published no longer offers to post itself twice. - BOLT12 offers move into the profile payment rail, where every other payment route already lived, and the zap picker finally shows a bolt for a recipient who publishes an offer and no lightning address. A refused offer falls back to BOLT11, retried only on codes that mean nothing was attempted. - Blossom uploads work again. 1.15.0's unpadded base64url token is rejected by deployed servers, so about two uploads in three had been failing since then. - A relay that sends a CLOSE frame is no longer counted as connected for up to four minutes with its REQs live, in both the shared and the Android socket. - Arti 2.3.0 -> 2.6.0 for TROVE-2026-24 and TROVE-2026-27. - amy ships ~40 MB lighter after the commonsUI split. Changelog claims were checked against the final state of each series, not the first commit: the BOLT12 retry set is the narrowed allowlist from the audit follow-up (a PAYMENT_FAILED can still settle, so retrying it could pay twice), the relay count comes from the connected flow rather than the removed members snapshot, and the OkHttp dispatcher resize is absent because it was reverted. NEEDS A MAINTAINER BEFORE THE TAG: RELEASE_NOTES_ID still points at the v1.15.0 note. RELEASE_OPS repoints it on every x.y.0, which this is, and it has to be published from Amethyst's own account -- so it is not something this commit could do. Also left alone: docs/changelog/translators.json, whose sinceLastTag is seeded with vitorpamplona credited for all 41 languages and ~50 users with no language at all, so scripts/translators.sh output is unusable this cycle. The changelog credits the three translators with real attribution. mstrofnone (the desktop keychain fixes) has no npub in mappings and is credited by handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.4 KiB
geode
A standalone Nostr relay for the JVM, built on Quartz's relay-server code (Ktor CIO). It speaks the core relay protocol plus NIP-11 (info doc), NIP-42 (AUTH), NIP-45 (COUNT), NIP-50 (full-text search), NIP-77 (Negentropy sync), and NIP-86 (relay management), stores events in SQLite (or a filesystem backend), and can mirror upstream relays strfry-router style.
geode depends only on :quartz — no Android, no Compose. amy serve (the
Amethyst CLI) embeds the same engine in-process.
Install
Pick the channel that matches how you deploy. For a real relay, the Docker
image or the .deb/.rpm + systemd are the two production paths;
Homebrew and the portable tarball are handy for local testing.
Docker (recommended for servers)
Images are published to GHCR on every release:
# Ephemeral — in-memory store, events vanish on restart:
docker run --rm -p 7447:7447 ghcr.io/vitorpamplona/geode:latest
# Persistent + configured:
docker run -d --name geode -p 7447:7447 \
-v $PWD/geode.toml:/etc/geode/geode.toml:ro \
-v geode-data:/var/lib/geode \
ghcr.io/vitorpamplona/geode:latest --config /etc/geode/geode.toml
with in_memory = false and file = "/var/lib/geode/events.db" in your
geode.toml. Pin a version (:1.16.0) instead of :latest for reproducible
deploys. To build the image yourself, from the repo root:
docker build -f geode/Dockerfile -t geode:local .
Debian/Ubuntu (.deb) and Fedora/RHEL (.rpm)
Download geode-<version>-linux-x64.deb (or .rpm) from the
release page and install
it — a minimal JRE is bundled, so no system Java is required. It installs to
/opt/geode/ with the launcher at /opt/geode/bin/geode.
sudo dpkg -i geode-1.16.0-linux-x64.deb # or: sudo rpm -i geode-1.16.0-linux-x64.rpm
To run it as a managed service, wire up the shipped systemd unit
(/opt/geode/share/geode/geode.service) — the unit file's header comment has
the copy-paste steps (create the geode user, drop your config in
/etc/geode/geode.toml, systemctl enable --now geode).
Homebrew
brew install vitorpamplona/tap/geode-relay # from the tap, once published
The formula depends on openjdk and installs the no-JRE jar bundle. Reference
formula: packaging/homebrew/geode-relay.rb.
Portable tarball (any Linux/macOS, no system Java)
Download geode-<version>-<os>-<arch>.tar.gz, unpack, and run:
tar xzf geode-1.16.0-linux-x64.tar.gz
./geode/bin/geode --config geode/share/geode/config.example.toml
The tarball bundles a jlink'd JRE plus share/geode/config.example.toml and
share/geode/geode.service.
From source
./gradlew :geode:run --args="--config /etc/geode.toml"
Configure
geode runs with zero config (binds 0.0.0.0:7447, in-memory SQLite). For
anything real, copy config.example.toml and edit it —
the sections mirror nostr-rs-relay's config.toml so existing configs port
almost verbatim. Precedence is CLI flags > TOML > built-in defaults.
geode --config /etc/geode/geode.toml
geode --help # full flag list
geode --version
Key sections: [info] (NIP-11 doc), [network] (bind + thread pools),
[database] (SQLite path/tuning), [options] (AUTH / verify / search),
[authorization] (allow/deny lists), [[mirror]] (upstream mirroring), and
[admin] (NIP-86 management). See the example file for every knob.
Verbs
geode [relay] [flags] serve the relay (default)
geode import [flags] [FILE…] bulk-load NDJSON events into the store
geode export [flags] dump the store as NDJSON to stdout
import/export are geode's strfry import / strfry export — one JSON event
per line, for seeding, migrating, or backing up a relay. Both stream, so a
multi-million-event corpus round-trips in roughly constant memory.
Release process
geode ships on the same tag-driven pipeline as the rest of Amethyst: pushing a
v* tag runs .github/workflows/create-release.yml, whose build-geode job
produces the tarball + .deb/.rpm + Homebrew jvm bundle, docker-geode
builds and pushes the GHCR image, and bump-homebrew-geode-formula.yml syncs
the reference formula. Design notes:
plans/2026-07-24-geode-release.md.