Federated Indexer

Synapse

The reference CMN indexer — ingests signed manifests, indexes spores and myceliums, serves discovery queries, and syncs across instances via Nostr.

Synapse is the federated indexer and resilience layer for CMN — the network’s “Search Engine” and “Backup Layer”. It crawls sovereign domains, aggregates metadata, and serves as content fallback when origin servers are offline.

API Contract: The Synapse API is defined by CMN strains — see strain-synapse, strain-synapse-search, and strain-synapse-nostr conventions for the full specification.

Installation

# All features (default: postgres + redb + nostr)
cargo build --release

# With semantic search + graph (requires external embedding service)
cargo build --release --features ruvector

# Without Nostr
cargo build --release --no-default-features --features postgres,redb

# Redb only, no Nostr
cargo build --release --no-default-features --features redb
cp target/release/synapse /usr/local/bin/

Quick Start

Development (Redb)

cargo run
# Server starts at http://localhost:3000

Production (PostgreSQL + HTTPS)

Create config.yml:

storage:
  type: postgres
  url: "postgresql://user:pass@localhost/synapse"

http:
  enabled: true
  port: 80

https:
  enabled: true
  port: 443
  domains:
    - synapse.cmn.dev
  self_signed_validity_days: 365
  acme:
    enabled: true
    email: admin@cmn.dev
    renewal_before_days: 30

cache:
  cmn_ttl_s: 300     # cmn.json cache TTL in seconds (default: 5 minutes)

pulse:
  max_clock_skew_s: 300  # Maximum clock skew in seconds (default: 5 minutes)

Run:

cargo run
# Connects to PostgreSQL
# Obtains TLS certificate via Let's Encrypt
# Starts HTTP (80) and HTTPS (443)

API Overview

Base URL: https://synapse.cmn.dev/v1

# Spore API (content-addressable)
GET /v1/spore/:hash                    # Get spore by hash
GET /v1/spore/:hash/lineage            # Find descendants
GET /v1/spore/:hash/rhizome            # Complete evolution network

# Mycelium API (domain-scoped fallback)
GET /v1/myceliums                      # List all cached myceliums
GET /v1/mycelium/:domain               # Get cached mycelium
GET /v1/mycelium/:domain/spore/:hash   # Get spore by domain+hash
GET /v1/mycelium/:domain/spores        # List domain's spores

# Pulse API (receive signed content)
POST /v1/pulse                         # Receive signed spore/mycelium

# Search API (requires ruvector feature + embedding service)
GET /v1/search?q=...&domain=...&limit= # Semantic spore search

# Graph API (requires ruvector feature + graph.enabled)
GET /v1/graph/search?q=...&limit=      # Semantic relationship search
GET /v1/graph/temporal?start=...&end=.. # Temporal evolution query
GET /v1/graph/stats                    # Graph statistics

# Nostr Relay (WebSocket, NIP-01)
GET /nostr                             # WebSocket relay endpoint

Example Requests

# Get spore by hash
curl https://synapse.cmn.dev/v1/spore/blake3_8ccf403b0447d5e23d54fd56f7a288bab8e65c7324e90da8e769ad28049433c4

# Find all forks/evolutions
curl https://synapse.cmn.dev/v1/spore/blake3_8ccf403b0447d5e23d54fd56f7a288bab8e65c7324e90da8e769ad28049433c4/lineage

# Get complete ancestry + descendants
curl https://synapse.cmn.dev/v1/spore/blake3_8ccf403b0447d5e23d54fd56f7a288bab8e65c7324e90da8e769ad28049433c4/rhizome?max_depth=5

# Get mycelium fallback
curl https://synapse.cmn.dev/v1/mycelium/cmn.dev

# Semantic search (requires ruvector feature)
curl "https://synapse.cmn.dev/v1/search?q=HTTP+client+library&limit=10"

# Relationship search (requires graph.enabled)
curl "https://synapse.cmn.dev/v1/graph/search?q=forked+for+security&limit=5"

# Temporal evolution query
curl "https://synapse.cmn.dev/v1/graph/temporal?start=1700000000&end=1710000000"

# Graph stats
curl https://synapse.cmn.dev/v1/graph/stats

Integration with Hypha

Notify Synapse after releasing:

# Release spore
hypha release --domain cmn.dev

# Notify synapse
hypha mycelium pulse --domain cmn.dev --synapse https://synapse.cmn.dev

Query evolution via Hypha:

# Trace ancestors
hypha ancestors cmn://cmn.dev/spore/blake3_8ccf403b0447d5e23d54fd56f7a288bab8e65c7324e90da8e769ad28049433c4 --synapse https://synapse.cmn.dev

# Find descendants
hypha lineage cmn://cmn.dev/spore/blake3_8ccf403b0447d5e23d54fd56f7a288bab8e65c7324e90da8e769ad28049433c4 --synapse https://synapse.cmn.dev

# Auto-discover for absorb
hypha absorb --lineage --synapse https://synapse.cmn.dev

Nostr Integration

Synapse optionally integrates with the Nostr protocol for decentralized event distribution. When enabled, Synapse acts as both a Nostr client and a CMN-only Nostr relay.

Any Synapse instance can connect to another’s /nostr endpoint and sync all historical CMN data.

Configuration

Add to config.yml:

nostr:
  enabled: true
  relays:
    - "wss://relay.damus.io"
  key_store: "storage"        # "storage" (database, default) or "file:nostr.key"
  subscribe: true             # Listen for CMN events on external relays
  forward_pulse: false        # Forward HTTP pulses to Nostr relays

The Nostr identity key (secp256k1) is auto-generated on first run. By default it is stored in the database (key_store: "storage"). Use key_store: "file:path/to/key" to store it as a plain file instead.

Search & Graph

Synapse optionally provides semantic search over spores and an in-memory evolution graph for fast lineage queries. Both require the ruvector feature and an external embedding service (Ollama or OpenAI).

Vector similarity search over spore metadata (name, description, keywords). Embeddings are generated via an external API and stored in a ruvector-core VectorDB index.

Graph

The evolution graph uses ruvector-core’s HypergraphIndex to model spore relationships (spawned_from, absorbed_from, depends_on, follows, extends) as hyperedges. It serves as an in-memory acceleration layer — storage (Redb/Postgres) remains the source of truth.

When enabled, lineage and rhizome queries are served from the in-memory graph (O(V+E) with no I/O), falling back to storage BFS if the graph has no data for the requested hash.

Additional graph-only capabilities:

Configuration

Add to config.yml:

search:
  enabled: true
  index_path: "synapse-search"
  embedding:
    provider: "ollama"          # "ollama" or "openai"
    url: "http://localhost:11434"
    model: "bge-large"
    dimensions: 1024
  graph:
    enabled: true
    rebuild_on_startup: true    # Rebuild graph from storage on boot
    embed_relationships: false  # Embed edge descriptions (costs API calls)
    rebuild_batch_size: 100

Build with --features ruvector.

Features

FeatureDependencyDefault
postgressqlxYes
redbredbYes
nostrnostr-sdkYes
ruvectorruvector-coreNo

Default features: postgres, redb, nostr. Use --no-default-features --features <feature,...> to compile only what you need. Search is opt-in via --features ruvector.

Development

# Build (default: all features)
cargo build

# Build with redb only (faster compile, no libpq needed)
cargo build --no-default-features --features redb

# Build without Nostr (smaller binary, no nostr-sdk dependency)
cargo build --no-default-features --features redb

# Test
cargo test

# Run with debug logging
RUST_LOG=debug cargo run

# Run with plain text logs (development)
# Add to config.yml: log_format: "plain"

Documentation

DocumentDescription
Deployment GuideSelf-host a Synapse instance — configuration, services, operations
Storage InternalsDatabase schema, indexing, and storage backends

Documentation