Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 64 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,30 @@ 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 |
| ✅ | **YAML-as-code workflows** — automation with execution traces (approval gates: planned) |
| ✅ | **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 |
| ✅ | **Pure Rust backend** — memory safe, no GC pauses |

## Supported NIPs

| NIP | Title | Status |
|-----|-------|--------|
| [NIP-01](https://github.com/nostr-protocol/nips/blob/master/01.md) | Basic protocol flow — events, filters, subscriptions | ✅ Implemented |
| [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) | Mapping Nostr keys to DNS-based internet identifiers | ✅ Implemented |
| [NIP-09](https://github.com/nostr-protocol/nips/blob/master/09.md) | Event deletion | ✅ Implemented |
| [NIP-10](https://github.com/nostr-protocol/nips/blob/master/10.md) | Conventions for clients' use of `e` and `p` tags in text events | ✅ Implemented |
| [NIP-11](https://github.com/nostr-protocol/nips/blob/master/11.md) | Relay information document | ✅ Implemented |
| [NIP-17](https://github.com/nostr-protocol/nips/blob/master/17.md) | Private Direct Messages | ✅ Implemented |
| [NIP-25](https://github.com/nostr-protocol/nips/blob/master/25.md) | Reactions | ✅ Implemented |
| [NIP-28](https://github.com/nostr-protocol/nips/blob/master/28.md) | Public chat channels | ✅ Via `sprout-proxy` (kind translation) |
| [NIP-29](https://github.com/nostr-protocol/nips/blob/master/29.md) | Relay-based groups | ✅ Partial (kinds 9000–9008 implemented; 9009, 9021 deferred) |
| [NIP-29](https://github.com/nostr-protocol/nips/blob/master/29.md) | Relay-based groups | ✅ Partial (kinds 9000–9002, 9005, 9007–9008, 9021–9022 implemented; 9009 stubbed) |
| [NIP-42](https://github.com/nostr-protocol/nips/blob/master/42.md) | Authentication of clients to relays | ✅ Implemented |
| [NIP-50](https://github.com/nostr-protocol/nips/blob/master/50.md) | Search capability | ✅ Implemented |
| [NIP-98](https://github.com/nostr-protocol/nips/blob/master/98.md) | HTTP Auth | ✅ Partial (`POST /api/tokens` bootstrap only) |

## Architecture

Expand All @@ -59,58 +65,61 @@ append-only and audited.
┌─────────────────────────────────────────────────────────────────────────┐
│ sprout-relay │
│ │
│ NIP-01 handler · NIP-42 auth · channel REST · admin API │
└──────────┬──────────────────────┬───────────────────────────────────────┘
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ Postgres │ │ Redis │
│ (events, │ │ (pub/sub, │
│ channels, │ │ presence) │
│ tokens) │ └─────────────┘
└──────┬──────┘
┌──────▼──────┐
│ Typesense │
│ (full-text │
│ search) │
└─────────────┘
│ NIP-01 handler · NIP-42 auth · channel/DM/media/workflow REST │
└───┬──────────────────┬──────────────────┬──────────────────┬────────────┘
│ │ │ │
┌──▼───────┐ ┌──────▼──────┐ ┌──────▼──────┐ ┌─────▼─────┐
│ Postgres │ │ Redis │ │ Typesense │ │ S3/MinIO │
│ (events, │ │ (pub/sub, │ │ (full-text │ │ (media │
│ channels,│ │ presence, │ │ search) │ │ uploads) │
│ users, │ │ typing) │ └─────────────┘ └───────────┘
│ workflows│ └─────────────┘
│ …) │
└──────────┘
```

## Crate Map

**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 |
| `sprout-core` | Zero-I/O foundation types — `StoredEvent`, NIP-01 filter matching, Schnorr verification, kind constants, channel/presence types |
| `sprout-relay` | Axum WebSocket server — NIP-01 message loop, channel/DM/media/workflow REST, Blossom media upload |

**Services**
| Crate | Role |
|-------|------|
| `sprout-db` | Postgres 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-db` | Postgres access layer — events, channels, users, DMs, threads, reactions, workflows, tokens, feed (sqlx) |
| `sprout-auth` | NIP-42 challenge/response + Okta OIDC JWT validation + NIP-98 HTTP Auth + token scopes + rate limiting |
| `sprout-pubsub` | Redis pub/sub fan-out, presence tracking, typing indicators, and rate limiting |
| `sprout-search` | Typesense indexing and query — full-text search over event content |
| `sprout-audit` | Append-only audit log with hash chain for tamper detection |
| `sprout-audit` | Append-only audit log with SHA-256 hash chain for tamper detection |

**Agent interface**
| Crate | Role |
|-------|------|
| `sprout-mcp` | stdio MCP server — 43 tools for messages, channels, workflows, and feed |
| `sprout-mcp` | stdio MCP server — tools for messaging, channels, DMs, canvas, workflows, forums, search, profiles, and presence |
| `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 |
| `sprout-workflow` | YAML-as-code workflow engine — message/reaction/diff/schedule/webhook triggers, action dispatch, execution traces |
| `sprout-huddle` | LiveKit integration — voice/video session tokens, webhook verification, in-memory session tracking |

**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](NOSTR.md) |

**Shared libraries**
| Crate | Role |
|-------|------|
| `sprout-sdk` | Typed Nostr event builders — used by sprout-mcp, sprout-acp, and sprout-cli |
| `sprout-media` | Blossom/S3 media storage, validation, and thumbnail generation |

**Tooling**
| Crate | Role |
|-------|------|
| `sprout-cli` | Agent-first CLI for interacting with the relay |
| `sprout-admin` | CLI for minting API tokens and listing active credentials |
| `sprout-test-client` | WebSocket test harness for integration tests |
| `sprout-test-client` | Integration test client and E2E test suite — relay, REST API, tokens, MCP, media, media extended, Nostr interop, and workflows |

## Quick Start

Expand All @@ -136,7 +145,7 @@ just build

`just setup` does the heavy lifting:
- Starts Docker services (Postgres, Redis, Typesense, Adminer, Keycloak, MinIO, Prometheus)
- Waits for all services to be healthy
- Waits for core services (Postgres, Redis, Typesense) to be healthy
- Runs database migrations
- Installs desktop dependencies (`pnpm install`)

Expand Down Expand Up @@ -227,11 +236,32 @@ Copy `.env.example` to `.env` and adjust as needed. All defaults work out of the
| `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) |
| `SPROUT_CORS_ORIGINS` | — | Comma-separated allowed CORS origins (unset = permissive) |
| `SPROUT_HEALTH_PORT` | `8080` | Port for health check endpoint (separate from main bind) |
| `SPROUT_MAX_CONCURRENT_HANDLERS` | `1024` | Max concurrent EVENT/REQ handlers |
| `SPROUT_MAX_CONNECTIONS` | `10000` | Max simultaneous WebSocket connections |
| `SPROUT_MAX_GIF_BYTES` | `10485760` | Max GIF upload size in bytes (10 MB) |
| `SPROUT_MAX_IMAGE_BYTES` | `52428800` | Max image upload size in bytes (50 MB) |
| `SPROUT_MEDIA_BASE_URL` | `http://localhost:3000/media` | Public base URL for media files |
| `SPROUT_MEDIA_SERVER_DOMAIN` | auto-derived from `RELAY_URL` | Media server domain as `host[:port]` |
| `SPROUT_S3_ENDPOINT` | `http://localhost:9000` | S3-compatible endpoint URL (MinIO in dev) |
| `SPROUT_S3_ACCESS_KEY` | `sprout_dev` | S3 access key |
| `SPROUT_S3_SECRET_KEY` | `sprout_dev_secret` | S3 secret key |
| `SPROUT_S3_BUCKET` | `sprout-media` | S3 bucket name for media uploads |
| `SPROUT_METRICS_PORT` | `9102` | Port for Prometheus metrics endpoint |
| `SPROUT_PUBKEY_ALLOWLIST` | `false` | Restrict NIP-42 pubkey-only auth to allowlisted keys (`true`/`1`); API token and Okta JWT auth bypass |
| `SPROUT_SEND_BUFFER` | `1000` | WebSocket send buffer size |
| `SPROUT_UDS_PATH` | — | Unix domain socket path (alternative to TCP) |
| `OKTA_JWKS_URI` | — | Okta JWKS endpoint URI for JWT verification |
| `SPROUT_TOOLSETS` | `default` | MCP toolsets to enable (comma-separated: `default`, `channel_admin`, `dms`, `canvas`, `workflow_admin`, `identity`, `forums`, `all`, `none`; append `:ro` for read-only) |
| `SPROUT_MINT_RATE_LIMIT` | `50` | Max API token mints per pubkey per hour |
| `SPROUT_RELAY_PUBKEY` | — | Relay's hex pubkey — required by `sprout-proxy`; also used as fallback auth by `sprout-workflow` when no API token is set |

## MCP Tools

The `sprout-mcp` server exposes 43 tools over stdio, covering messaging, channels, threads,
reactions, DMs, workflows, search, profiles, presence, and more. Agents discover tools
The `sprout-mcp` server exposes tools over stdio, organized into toolsets: `default` (25 tools
active out of the box), `channel_admin`, `dms`, `canvas`, `workflow_admin`, `identity`, and
`forums`. Set `SPROUT_TOOLSETS=all` to enable every tool. Agents discover available tools
automatically via the MCP protocol — see [AGENTS.md](AGENTS.md) for integration details.

## Development
Expand Down Expand Up @@ -269,6 +299,7 @@ just reset # ⚠️ Wipe all data and recreate environment

```bash
cargo run -p sprout-relay
cargo run -p sprout-cli -- --help
cargo run -p sprout-admin -- --help
cargo run -p sprout-mcp --bin sprout-mcp-server
cargo run -p sprout-proxy
Expand All @@ -281,8 +312,8 @@ cargo run -p sprout-proxy
Run `just test-unit` for unit tests (no infra required) or `just test` for the full suite.
See [TESTING.md](TESTING.md) for the multi-agent E2E suite (Alice/Bob/Charlie via `sprout-acp`).

**Database schema** lives in `schema/schema.sql`. The relay applies it automatically on startup.
To run manually: `just migrate`.
**Database schema** lives in `schema/schema.sql`. Apply it with `just migrate`; `just setup`
runs migrations automatically as part of environment setup.

## License

Expand Down
Loading