A local-first knowledge graph for nostr, implementing the tapestry protocol for decentralized curation of simple lists (DCoSL) and personalized web of trust metrics using the GrapeRank algorithm.
This is a fork of the Brainstorm prototype, now being rebuilt by the team at NosFabrica. Development is focused on the concept graph — a structured knowledge graph built from nostr events (DLists), stored in Neo4j, and browsable through a React UI.
Tapestry runs locally in a Docker container. You own your data. It's designed to be operated by humans through the browser UI, or by AI agents through the CLI and API.
- Docker Desktop (or Docker Engine + Compose) — install
- Git
- A nostr key and a NIP-07 browser extension (e.g., nos2x, Alby, or Nostr Connect)
git clone https://github.com/nous-clawds4/tapestry.git
cd tapestry
git checkout concept-graphCopy the example environment file and fill in your values:
cp .env.example .envEdit .env:
# Your nostr public key (hex format, not npub)
OWNER_PUBKEY=your_hex_pubkey_here
# Choose a strong password for Neo4j
NEO4J_PASSWORD=change_me_to_something_secure
# set admin pubkey for the local relay (probably use same as above)
ADMIN_PUBKEYS=your_hex_pubkey_hereHow to find your hex pubkey: If you only have your
npub, you can convert it at njump.me or using thenakCLI:nak key decode npub1...
Note: If any of the ports in the docker-compose.yml file are non-negotiably unusable on your system, create a docker-compose.override.yml and set the ports there, shadowing the same yml structure as what you're overriding. See docker-compose.override-example.yml.
docker compose up -dThe first build takes 10–15 minutes (compiling strfry, installing Neo4j, etc.). Subsequent starts are fast.
docker compose logs -fWait until you see the brainstorm service start. Then open:
- Control Panel: http://localhost:8080
- Knowledge Graph UI: http://localhost:8080/kg/
- Neo4j Browser: http://localhost:8080/browser/preview/
- Protocol:
neo4j:// - Connection URL:
localhost:8687 - user:
neo4j - password: what you set above in
.env
- Protocol:
- Nostr Relay:
ws://localhost:8080/relay
- Open the Knowledge Graph UI at http://localhost:8080/kg/
- Click "Sign in with Nostr" in the top right
- Your NIP-07 extension will prompt you to approve
- You should see your name and an Owner badge
Your Tapestry instance starts with an empty database. To import existing DList data from the DCoSL network:
# Sync DList events from the DCoSL relay into your local strfry
docker compose exec tapestry strfry sync wss://dcosl.brainstorm.world \
--filter '{"kinds":[9998,9999,39998,39999]}' \
--dir downNote: A more streamlined import workflow is coming soon. For now, you can also use the tapestry-cli tool to sync and normalize data into Neo4j.
If you hit limits, try doing each kind separately and/or adding a limit:
docker compose exec tapestry strfry sync wss://dcosl.brainstorm.world \
--filter '{"kinds":[9999], "limit": 750000}' \
--dir downAt this point, if you visit the /kg dashboard, you'll see:
Neo4j Constraints & Indexes Missing 5 of 5 required constraints/indexes are not installed. Missing constraints: NostrEvent.id, NostrEvent.uuid, NostrEventTag.uuid, NostrUser.pubkey. Missing indexes: NostrEvent.kind.
Either click the button there or use cURL:
curl -X POST http://localhost:8080/api/neo4j-setup-constraints-and-indexesNow, when you visit the Neo4j browser you should see these under "Database information".
- On the dashboard, click "install firmware ->" to visit http://localhost:5173/kg/settings/firmware
- Click the "Install Firmware" button
- This will take a little while, but will live update when it's complete
Once finished, you may see some subtle warnings on the dashboard:
168 of 2045 nodes need a tapestryKey 259 of 259 JSON tags still inline in Neo4j
These are harmless and expected for now; Click the blue buttons on each line.
For active development, use the dev compose override which bind-mounts your local code:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -dAfter editing server-side code, restart the brainstorm service:
docker compose exec tapestry supervisorctl restart brainstormThe React frontend lives in ui/ and uses Vite:
cd ui
npm install
npx vite --hostThis starts a dev server at http://localhost:5173/kg/ with hot module replacement. API requests are proxied to the Docker container on port 8080.
Tapestry runs as a single Docker container with several services managed by supervisord:
| Service | Purpose |
|---|---|
| Express (brainstorm) | API server, serves the control panel and Knowledge Graph UI |
| strfry | Local nostr relay — stores all events (DLists, profiles, etc.) |
| Neo4j | Graph database — concept graph, relationships, trust scores |
| nginx | Reverse proxy — all services accessed via port 8080 |
- DLists (Decentralized Lists): Nostr events (kinds 9998/39998 for headers, 9999/39999 for items) that define structured data — lists of things curated by your web of trust
- Concept Graph: DList headers that follow the tapestry protocol form a knowledge graph in Neo4j with node types, relationship types, properties, and JSON schemas
- Two-layer settings: Shipped defaults (
src/concept-graph/parameters/defaults.json) merged with user overrides (/var/lib/brainstorm/settings.json), configurable via the Settings page
External relays (DCoSL, purplepag.es, etc.)
↓ sync
Local strfry (ws://localhost:8080/relay)
↓ import + normalize
Neo4j concept graph
↓ query
React UI (port 8080/kg/)
| Page | Description |
|---|---|
| 📋 Simple Lists | Browse all DList headers with item counts, author profiles, Neo4j sync status |
| 🧩 Concepts | Concept graph — node types, properties, schemas, DAG structure |
| 📡 Events | Browse nostr events by type |
| 🔵 Nodes | All Neo4j nodes with labels and relationships |
| 👤 Nostr Users | User directory with profiles fetched from external relays |
| 🔗 Relationships | Neo4j relationship browser |
| 🛡️ Trusted Lists | (Coming soon) WoT-curated list views |
| ⚙️ Settings | Owner-only — configure relays, concept UUIDs, system parameters |
| Variable | Required | Description |
|---|---|---|
OWNER_PUBKEY |
✅ | Your nostr hex pubkey — determines who is the "Owner" in the UI |
NEO4J_PASSWORD |
✅ | Password for Neo4j (used by the API server) |
DOMAIN_NAME |
Optional | Domain name for the instance (default: localhost) |
Tapestry uses a two-layer configuration:
- Defaults (
src/concept-graph/parameters/defaults.json) — shipped with the code, includes relay lists and canonical concept UUIDs - User overrides (
/var/lib/brainstorm/settings.json) — persistent Docker volume, written by the Settings page
Changes to relay lists take effect immediately. Changes to concept UUIDs or system parameters require a restart.
Tapestry can be operated by AI agents (e.g., under OpenClaw). In addition to the Docker stack, agents need:
- tapestry-cli — command-line tool for querying, syncing, and managing the instance
- Tapestry skill — teaches the agent the API, schema, and workflows
See Agent Setup in the Quickstart guide for installation instructions.
| Port | Service | Notes |
|---|---|---|
| 8080 | Express API + UI | Main entry point — all services proxied through here |
| 5173 | Vite dev server | Only during development (npx vite) |
All services are accessed through the nginx proxy on port 8080:
| Path | Service | Notes |
|---|---|---|
/kg/ |
Knowledge Graph UI | React app |
/browser/preview/ |
Neo4j Browser | Database access (user: neo4j) |
/relay |
strfry relay | Local nostr relay (WebSocket: ws://localhost:8080/relay) |
/api/ |
Express API | REST endpoints |
GNU Affero General Public License v3.0
Contributions are welcome! Please feel free to submit comments, bug reports and issues. If you would like to submit a pull request, please create a new issue first and describe the changes you would like to make.