Synapse: Discovery Without a Registry
A federated indexer for the Code Mycelial Network — pulse ingestion, Nostr relay sync, lineage traversal, and semantic search. No central registry. No trust required.
Package registries are chokepoints. npm, PyPI, crates.io — each one is a single database that every consumer must query and every publisher must trust. When the registry goes down, the ecosystem stops. When the registry is compromised, every downstream consumer inherits the damage. When the registry changes its policies, you comply or leave.
The Code Mycelial Network (CMN) eliminates the registry. Every domain is its own publisher. Every spore is signed by its author and verifiable by anyone. But without a central index, how do you find anything? How do you search across thousands of domains? How does a new participant discover what’s out there?
Synapse is the answer — a federated indexer that any operator can run. It crawls domains, indexes spores, serves queries, and synchronizes with other instances through the Nostr relay network. No single Synapse owns the index. No trust is placed in any instance. Every piece of data is independently verified against the publisher’s public key before it enters the index.
The trust model: verify everything, trust nothing
Synapse is not a cache sitting in front of a trusted source. There is no trusted source. Every manifest that enters the index — spore, mycelium, taste report — arrives as a signed capsule. Synapse verifies both layers:
- Core signature — the author’s Ed25519 key signs
capsule.core - Capsule signature — the host domain’s key signs the full
capsule
The host’s public key is fetched from https://{domain}/.well-known/cmn.json and cached with a TTL. If signature verification fails, the data is rejected. If the domain’s key rotates, the cache expires and the new key is fetched on the next pulse.
This means you can run a Synapse instance, subscribe to public Nostr relays, ingest thousands of events from domains you’ve never heard of, and every single one is cryptographically verified before it touches your index. A compromised relay cannot inject false data. A malicious Synapse instance cannot poison your index. The signatures are end-to-end.
Four data channels
Data enters a Synapse instance through four independent channels:
| Source | Mechanism |
|---|---|
| HTTP Pulse | Domains push signed manifests via POST /synapse/pulse |
| Nostr Subscription | Your instance pulls historical + real-time CMN events from external relays |
| Nostr Relay | Other instances or clients push events to your /synapse/nostr WebSocket endpoint |
| Crawler | Background retry loop re-fetches cmn.json → mycelium → spores from known domains |
No seed list. No manual domain configuration. Domains become known through pulses and Nostr events. Once known, the crawler handles the rest — fetching the full domain manifest, indexing every spore, and retrying on failure with exponential backoff.
A publisher pushes a pulse after releasing:
hypha mycelium pulse --synapse https://synapse.example.com
The pulse carries a signed capsule. Synapse verifies it, indexes it, and — if Nostr forwarding is enabled — broadcasts it to the relay network for other instances to pick up.
Cross-instance sync via Nostr
This is the mechanism that makes Synapse federated rather than just distributed. Every instance can act as both a Nostr relay and a Nostr client:
Instance A Public Relays Instance B
│ │ │
│ forward_pulse ────────→ │ │
│ │ ────────→ subscribe │
│ │ │
│ subscribe ←──────── │ │
│ │ ←──────── forward_pulse │
Public Nostr relays (relay.damus.io, nos.lol, etc.) act as the shared transport. CMN events are NIP-78 application events (kind 30078) with structured tags for URI, domain, hash, and content type. Any Nostr relay stores them. Any Synapse instance can subscribe and ingest them.
Bootstrapping a new instance is one config change:
nostr:
enabled: true
relays:
- "wss://relay.damus.io"
- "wss://nos.lol"
subscribe: true
forward_pulse: true
On startup, the subscription sends a REQ to each relay for all historical CMN events, receives the backlog, then streams new events in real-time. Every event is verified through the same CMN signature pipeline as HTTP pulses. Within minutes, a fresh instance has the full network index — rebuilt from cryptographically verified data, without trusting any single source.
Lineage traversal: the bond graph
Synapse doesn’t just store spores — it indexes the relationships between them. Every bond declared in spore.core.json is stored as a graph edge. The API exposes traversal in both directions:
# Who forked from this spore? (inbound bonds)
curl 'https://synapse.example.com/synapse/spore/b3.<hash>/bonds?direction=inbound&max_depth=3'
# What does this spore depend on? (outbound bonds)
curl 'https://synapse.example.com/synapse/spore/b3.<hash>/bonds?direction=outbound'
The response includes the full lineage with relationship types — spawned_from, absorbed_from, depends_on, follows — and spore metadata for each node. Traversal depth is configurable per-request and capped by the server to prevent expensive unbounded walks.
The PostgreSQL backend uses recursive CTEs for lineage queries — one round-trip regardless of depth. The embedded redb backend uses BFS with the same interface. Both batch-fetch spore summaries to avoid N+1 queries.
Semantic search
With an embedding service (Ollama or OpenAI), Synapse indexes spore names, synopses, and intents as vectors. Search queries are embedded and matched against the index:
curl 'https://synapse.example.com/synapse/search?q=http+service&license=MIT'
Results are ranked by relevance with optional filters for domain, license, strain, bonds, and time range. Each result includes aggregated taste verdicts from the network — the signal that community evaluators have reviewed the code.
The search index includes a bond graph overlay for fast lineage lookups without hitting the database. On startup, the graph is rebuilt from indexed data.
Taste aggregation
Every spore and domain has a reputation surface built from taste reports. The network’s evaluators submit signed verdicts — sweet, fresh, safe, rotten, toxic — and Synapse aggregates them:
# Taste verdicts for a specific spore
curl 'https://synapse.example.com/synapse/spore/b3.<hash>/tastes'
# Aggregated reputation for an entire domain
curl 'https://synapse.example.com/synapse/cmn/example.com/tastes'
Synapse does not adjudicate. It aggregates and serves. Each visitor decides which taster domains to trust and how to weigh their reports. The verdicts are advisory — a trust signal, not an authority.
Two storage backends
| Backend | Use Case |
|---|---|
| redb | Development, single-node, zero config — one file, embedded |
| PostgreSQL | Production, high traffic, concurrent queries |
Both compiled in by default. Switch with one config line. The storage trait is the same — lineage traversal, taste aggregation, batch queries, Nostr event persistence — so behavior is identical regardless of backend.
Deploy in five minutes
# Build
git clone https://github.com/cmnspore/cmn-synapse.git
cd cmn-synapse && cargo build --release
# Minimal config
cat > config.yml <<YAML
debug: true
storage:
backend: "redb"
redb_path: "synapse.db"
http:
enabled: true
address: "0.0.0.0:3000"
YAML
# Run
./target/release/synapse
Built-in ACME for automatic TLS certificates. Built-in Nostr relay. Built-in semantic search. One binary, one config file. For production, point a reverse proxy at it or enable the ACME provider for standalone TLS.
Agent-first output
Like all CMN tools, Synapse emits Agent-First Data structured logs. Every request, every pulse, every crawl event is a JSON event with stable fields. Pipe to ELK, Loki, CloudWatch, or any log aggregator. Secrets (database URLs, API keys) are auto-redacted via the _secret suffix convention.
{"$afdata":"request","method":"POST","path":"/synapse/pulse","status_code":200,"result":"indexed","trace":{"duration_ms":42}}Install
brew install cmnspore/tap/synapse # macOS/Linux
scoop bucket add cmnspore https://github.com/cmnspore/scoop-bucket && scoop install synapse # Windows
cargo install cmn-synapse # any platformThe network has no center
Any operator can run a Synapse instance. Any instance can sync with any other through public Nostr relays. No instance is authoritative. No instance is required. If every Synapse goes offline, the data still lives on the Nostr relay network, waiting for the next instance to subscribe and rebuild.
This is the discovery layer that CMN needs — one that matches the sovereignty model of the protocol itself. Your domain is your registry. Your Synapse is your index. The network is the union of all of them.
Docs: cmn.dev/tools/synapse Source: github.com/cmnspore/cmn-synapse License: MIT