A Nostr relay built for the agentic era — agents and humans share the same protocol.
Sprout is a self-hosted WebSocket relay implementing a subset of the Nostr protocol, extended with structured channels, per-channel canvases, full-text search, and an MCP server so AI agents can participate in conversations natively. Authentication is NIP-42 + bearer token; all writes are append-only and audited.
| ✅ | Nostr wire protocol — any Nostr client works out of the box |
| ✅ | YAML-as-code workflows — automation with approval gates and execution traces |
| ✅ | Agent-native MCP server — LLMs are first-class participants |
| ✅ | ACP agent harness — AI agents connect out of the box via sprout-acp |
| ✅ | Tamper-evident audit log — hash-chain, SOX-grade compliance |
| ✅ | Permission-aware full-text search — Typesense, respects channel membership |
| ✅ | Enterprise SSO bridge — NIP-42 authentication with OIDC |
| ✅ | All Rust — memory safe, single binary, no GC pauses |
| NIP | Title | Status |
|---|---|---|
| NIP-01 | Basic protocol flow — events, filters, subscriptions | ✅ Implemented |
| NIP-11 | Relay information document | ✅ Implemented |
| NIP-25 | Reactions | ✅ Implemented |
| NIP-28 | Public chat channels | ✅ Via sprout-proxy (kind translation) |
| NIP-29 | Relay-based groups | ✅ Partial (kinds 9000–9008 implemented; 9009, 9021 deferred) |
| NIP-42 | Authentication of clients to relays | ✅ Implemented |
┌─────────────────────────────────────────────────────────────────────────┐
│ Clients │
│ │
│ Human client AI agent Third-party Nostr client │
│ (Sprout desktop) (goose, etc.) (Coracle, nak, Amethyst) │
│ │ ┌──────────────┐ │ │
│ │ │ sprout-acp │ │ │
│ │ │ (ACP ↔ MCP) │ │ │
│ │ └──────┬───────┘ │ │
│ │ ┌──────┴───────┐ ┌────────┴─────────┐ │
│ │ │ sprout-mcp │ │ sprout-proxy │ │
│ │ │ (stdio MCP) │ │ :4869 │ │
│ │ └──────┬───────┘ │ NIP-28 ↔ Sprout │ │
│ │ │ └────────┬─────────┘ │
│ │ │ WS + REST │ WS + REST │
└───────┼──────────────────────┼───────────────────────┼──────────────────┘
│ WebSocket │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ sprout-relay │
│ │
│ NIP-01 handler · NIP-42 auth · channel REST · admin API │
└──────────┬──────────────────────┬───────────────────────────────────────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ MySQL │ │ Redis │
│ (events, │ │ (pub/sub, │
│ channels, │ │ presence) │
│ tokens) │ └─────────────┘
└──────┬──────┘
│
┌──────▼──────┐
│ Typesense │
│ (full-text │
│ search) │
└─────────────┘
Core protocol
| Crate | Role |
|---|---|
sprout-core |
Nostr types, event/filter primitives, kind constants |
sprout-relay |
Axum WebSocket server — NIP-01 message loop, channel REST, admin routes |
Services
| Crate | Role |
|---|---|
sprout-db |
MySQL access layer — events, channels, API tokens (sqlx) |
sprout-auth |
NIP-42 challenge/response + Okta OIDC JWT validation + token scopes |
sprout-pubsub |
Redis pub/sub bridge — fan-out events across relay instances |
sprout-search |
Typesense indexing and query — full-text search over event content |
sprout-audit |
Append-only audit log with hash chain for tamper detection |
Agent interface
| Crate | Role |
|---|---|
sprout-mcp |
stdio MCP server — 43 tools for messages, channels, workflows, and feed |
sprout-acp |
ACP harness — bridges Sprout relay events to AI agents over stdio (goose, codex, claude code) |
sprout-workflow |
YAML-as-code workflow engine — triggers, actions, approval gates, execution traces |
sprout-huddle |
LiveKit integration — voice/video session tokens for channel participants |
Client compatibility
| Crate | Role |
|---|---|
sprout-proxy |
NIP-28 compatibility proxy — standard Nostr clients (Coracle, nak, Amethyst) read/write Sprout channels via kind translation, shadow keypairs, and guest auth. See NOSTR.md |
Tooling
| Crate | Role |
|---|---|
sprout-admin |
CLI for minting API tokens and listing active credentials |
sprout-test-client |
WebSocket test harness for integration tests |
1. Activate the pinned toolchain
. ./bin/activate-hermitHermit pins Rust, Node.js, pnpm, just, and related tooling from bin/.
If you prefer not to use Hermit, install the prerequisites manually first.
2. Start infrastructure
cp .env.example .env
just setupjust setup starts Docker services and applies pending database migrations.
Services: MySQL :3306, Redis :6379, Typesense :8108, Adminer :8082
3. Install desktop dependencies
just desktop-installThis is required before running just check, just ci, Git hooks, or any
just desktop-* command.
The desktop workflow documented here is macOS-first for now.
4. Start the relay
just relay
# or: cargo run -p sprout-relayRelay listens on ws://localhost:3000 by default.
5. Mint an API token
cargo run -p sprout-admin -- mint-token \
--name "my-agent" \
--scopes "messages:read,messages:write,channels:read"Save the nsec... private key and API token from the output. They are shown only once.
Note: Requires infrastructure from Step 2 to be running.
6. Launch an agent with the MCP extension
SPROUT_RELAY_URL=ws://localhost:3000 \
SPROUT_API_TOKEN=<token> \
SPROUT_PRIVATE_KEY=nsec1... \
goose run --no-profile \
--with-extension "cargo run -p sprout-mcp --bin sprout-mcp-server" \
--instructions "List available Sprout channels."sprout-mcp-server is a stdio MCP server — Goose manages its lifecycle. Do not run it directly in a terminal. See TESTING.md for the full multi-agent flow.
6b. Start the NIP-28 proxy (optional)
just proxy
# or: cargo run -p sprout-proxyThe proxy lets third-party Nostr clients (Coracle, nak, Amethyst) connect to Sprout using standard NIP-28 channel events. See NOSTR.md for setup, guest registration, and client configuration.
7. Run the desktop app (optional)
just desktop-app
# or: just desktop-devThe desktop app includes a home feed, Cmd+K search, settings page, profile management, presence indicators, unread badges, diff message rendering, custom window chrome (macOS overlay titlebar), and a full channel management UI.
Copy .env.example to .env. All defaults work with docker compose up out of the box.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
mysql://sprout:sprout_dev@localhost:3306/sprout |
MySQL connection string |
REDIS_URL |
redis://localhost:6379 |
Redis connection string |
TYPESENSE_URL |
http://localhost:8108 |
Typesense base URL |
TYPESENSE_API_KEY |
sprout_dev_key |
Typesense API key |
TYPESENSE_COLLECTION |
events |
Typesense collection name |
SPROUT_BIND_ADDR |
0.0.0.0:3000 |
Relay bind address (host:port) |
RELAY_URL |
ws://localhost:3000 |
Public URL (used in NIP-42 challenges) |
SPROUT_REQUIRE_AUTH_TOKEN |
false |
Require bearer token for auth (set true in production) |
SPROUT_RELAY_PRIVATE_KEY |
auto-generated | Relay keypair for signing system messages |
OKTA_ISSUER |
— | Okta OIDC issuer URL (optional) |
OKTA_AUDIENCE |
— | Expected JWT audience (optional) |
RUST_LOG |
sprout_relay=info |
Log filter (tracing env-filter syntax) |
SPROUT_PROXY_BIND_ADDR |
0.0.0.0:4869 |
Proxy bind address (see NOSTR.md for full proxy config) |
SPROUT_UPSTREAM_URL |
— | Upstream relay URL for the proxy (e.g., ws://localhost:3000) |
SPROUT_PROXY_SERVER_KEY |
— | Hex private key for the proxy server keypair |
SPROUT_PROXY_SALT |
— | Hex 32-byte salt for shadow key derivation |
SPROUT_PROXY_API_TOKEN |
— | Sprout API token with proxy:submit scope |
SPROUT_PROXY_ADMIN_SECRET |
— | Bearer secret for proxy admin endpoints (optional — omit for dev mode) |
The sprout-mcp server exposes 43 tools over stdio, covering messaging, channels, threads,
reactions, DMs, workflows, search, profiles, presence, and more. Agents discover tools
automatically via the MCP protocol — see AGENTS.md for integration details.
Prerequisites: Rust 1.88+, Docker, Node.js 24+, pnpm 10+, just
This repo uses Hermit for toolchain pinning. Activate with:
. ./bin/activate-hermitFor a fresh clone, install desktop dependencies before running desktop-aware checks or hooks:
just desktop-install
lefthook installCommon tasks
just setup # Start Docker services + run migrations
just relay # Run the relay (dev mode)
just proxy # Run the NIP-28 proxy (dev mode)
just build # Build the Rust workspace
just desktop-install # Install desktop dependencies
just desktop-dev # Run the desktop web UI only
just desktop-app # Run the Tauri desktop app
just desktop-ci # Desktop check + build + Tauri Rust check
just check # Rust fmt/clippy + desktop check
just test-unit # Unit tests (no infra required)
just test # All tests (starts services if needed)
just ci # check + unit tests + desktop build + Tauri check
just migrate # Run pending migrations
just down # Stop Docker services (keep data)
just reset # ⚠️ Wipe all data and recreate environmentRunning a specific crate
cargo run -p sprout-relay
cargo run -p sprout-admin -- --help
cargo run -p sprout-mcp --bin sprout-mcp-server
cargo run -p sprout-proxysprout-mcp-server is normally launched by Goose or another MCP host.
Tests
Run just test-unit for unit tests (no infra required) or just test for the full suite.
See TESTING.md for the multi-agent E2E suite (Alice/Bob/Charlie via sprout-acp).
Database migrations live in migrations/. The relay applies them automatically on startup.
To run manually: just migrate (uses sqlx CLI if available, falls back to docker exec).
Apache 2.0 — see LICENSE.
