Skip to content

Repository files navigation

🍄 Mycelium MVP

A federated AI agent orchestration system built on AT Protocol primitives — agents with self-sovereign identity, capability discovery, decentralised task coordination, and portable reputation.

Status: MVP plus the first Protocol 0.1 contract — 539 tests covering legacy behavior, facts, permissions, snapshot/live ingestion, and AppView projections · persistent identities · AT Protocol PDS bridge · Jetstream federation · knowledge + tool providers · composable multi-attestor trust · proof-chain dashboard


What It Does

Mycelium is a protocol layer that fills the gap between centralised agent platforms (which lock in your data) and local-first runtimes (which offer no coordination). Agents own their identity and work history; orchestrators coordinate without controlling.

The MVP demonstrates the full lifecycle:

Bootstrap agents → Declare capabilities → Post tasks to Wanted Board →
Agents discover & claim tasks via Firehose → Execute (real or simulated) →
Mayor recommends, assigns, verifies completions → Reputation stamps link to evidence →
WorkTrace explains who did what, why it counted, and what changes next

How It Differs

Most agent frameworks (LangGraph, CrewAI, AutoGen) are single-process orchestrators — agents share a central database, coordination dies with the process, and reputation doesn't travel between platforms.

Mycelium follows AT Protocol's social architecture instead:

Centralised (LangGraph / CrewAI) Mycelium
Identity Assigned by framework did:key / did:plc — cryptographic, self-sovereign, portable
Data Central database Agent-owned repos with signed commits
Coordination Single process AT Protocol relay — agents on different machines see each other
Reputation Vendor-locked Signed stamps, verifiable by any observer
Portability Tied to the platform Records live on any AT Protocol PDS

Quick Start

Requirements: Node.js ≥ 22.13 for Protocol 0.1 work

npm install

# Level 0 — Pure simulation (zero config, ~50 seconds)
npm run demo

# Web dashboard (http://localhost:3000)
npm run dashboard

# Inspect the DuckDB database directly
npm run query "SELECT * FROM agent_identities"
npm run query "SELECT collection, COUNT(*) FROM firehose_events GROUP BY 1 ORDER BY 2 DESC"

# Clear all data for a fresh start
npm run reset

# Run tests
npm test

# Validate and regenerate Protocol 0.1 Lexicons
npm run lexicon:check
npm run lexicon:generate
npm run typecheck

DevEx Ladder

Each level builds on the previous. Level 0 works out of the box.

Level Command What you need
0 — Simulation npm run demo Nothing — pure simulation
1 — Real LLM MYCELIUM_ENABLE_INFERENCE=true GITHUB_TOKEN=ghp_... npm run demo Free GitHub token
1b — Local LLM MYCELIUM_ENABLE_INFERENCE=true LOCAL_ONLY_MODEL=qwen2.5:7b npm run demo Ollama installed
2 — Persistent npm run demo (after first run) Nothing extra — DIDs persist via DuckDB
3 — Docker docker compose up Docker

Copy .env.example to .env and uncomment variables as needed.

Level 0 — Demo Output

npm run demo bootstraps a 6-agent team and runs an 8-task project end-to-end:

🍄  MYCELIUM MVP — Federated Agent Orchestration Demo

🤖 atlas    ← Frontend specialist (claude-sonnet-4 via GitHub Models)
🤖 beacon   ← Backend architect   (claude-sonnet-4 via GitHub Models)
🤖 cipher   ← Security analyst    (gpt-4 via GitHub Models)
🤖 delta    ← DevOps engineer     (claude-haiku-4 via GitHub Models)
🤖 echo     ← QA specialist       (claude-sonnet-4 via GitHub Models)
🤖 forge    ← Generalist          (llama-3-70b via Ollama)

📋 PROJECT: Build the Mycelium Dashboard
   8 tasks · dependency-gated posting · competing claims · reputation stamps

[████████] 8/8 accepted ✅

Agent   Tasks  Score  Trust           Rejected  Model
atlas     3      85   🔵 established       0    claude-sonnet-4
beacon    1      86   ⬜ newcomer           0    claude-sonnet-4
cipher    1      83   ⬜ newcomer           0    gpt-4
...

Level 1 — Real LLM Inference

All 6 agents use a local Ollama model (no API token required):

# Install Ollama: https://ollama.ai
ollama pull qwen2.5:7b

MYCELIUM_ENABLE_INFERENCE=true LOCAL_ONLY_MODEL=qwen2.5:7b DEMO_TIMEOUT_MS=600000 npm run demo

Or use GitHub Models (free token at github.com/settings/tokens):

MYCELIUM_ENABLE_INFERENCE=true GITHUB_TOKEN=ghp_... npm run demo

Level 2 — Persistent Identities

Agent DIDs persist in data/mycelium.duckdb across runs. Run the demo twice — reputation accumulates, the same agents return, their work history grows.

npm run demo    # first run: generates identities
npm run demo    # second run: reuses same DIDs, adds more stamps
npm run query "SELECT handle, did FROM agent_identities"
npm run reset   # clear everything for a fresh start

Level 3 — Docker (real AT Protocol PDS)

No Node.js required — run the entire simulation in a container:

docker compose up
# open http://localhost:3000

To also spin up a local AT Protocol PDS (agents mirror records to real XRPC repos, browseable via any AT Proto tool):

npm run pds-init                        # generates .env.docker with PDS secrets (run once)
docker compose --profile pds up         # mycelium dashboard + local AT Proto PDS
# Dashboard: http://localhost:3000
# PDS:       http://localhost:2583

To add Jetstream federation (multiple Mycelium nodes see each other's agent activity):

docker compose --profile pds --profile jetstream up

After running with --profile pds, you can inspect agent records directly:

# List records for an agent
curl "http://localhost:2583/xrpc/com.atproto.repo.listRecords?repo=<did>&collection=network.mycelium.task.posting"

Architecture

The Seven Layers (all present in MVP)

Layer Component MVP Implementation
L0 Agent Identity did:key (Ed25519) — unique, cryptographically verifiable, persisted
L1 Data Ownership Per-agent in-memory stores (DuckDB-persisted) — agents own their records
L2 Schemas Zod-validated Lexicon-like records (19 types)
L3 Federation In-memory Firehose + AT Protocol PDS bridge (real XRPC) + Jetstream federation
L3 Coordination Wanted Board — task state machine (open→claimed→assigned→in_progress→completed→accepted/rejected→open)
L4 Orchestration Mayor — decomposes projects, ranks claims, quality-gates completions
L5 Governance Reputation — signed stamps, multi-dimensional scores, trust levels
L6 Explanation WorkTrace — derived proof chain for task lifecycle, evidence, and consequences

Protocol 0.1 boundary

The me.lqdev.mycelium.* namespace is the portable protocol contract. It is deliberately separate from the older network.mycelium.* simulation records:

  • Principals: requesters, workers, verifiers, and coordinators are repository authors. A model, prompt, tool, document, artifact, or run is an addressable resource and does not receive a permanent DID by default.
  • Authorship: requester attestations are authored by the requester; recommendations and coordinator certifications are separate facts authored by the coordinator. The AppView never rewrites one principal's record as another.
  • Coordination: competing claims are first-class. Requester-selected, delegated-coordinator, committee, deterministic-bounty, and self-service governance are represented as task data rather than a mandatory Mayor role.
  • Projection: ProtocolAppView is rebuildable from a PDS snapshot plus ordered events. It validates authorship, deduplicates global firehose sequences, quarantines invalid records, and exposes deterministic projection hashes.
  • Permissions: role permission sets resolve to narrow repo:<collection>?action=create scopes; expired or invalid resolution fails closed.

Validate the checked-in Lexicons and the focused Protocol 0.1 type boundary with:

npm run lexicon:check
npm run typecheck
npm test -- --reporter=dot src/protocol

src/protocol/ingestion.ts provides the snapshot/live handoff and cursor-store contract. AtprotoRepoSnapshotAdapter in src/atproto/repo-snapshot.ts now uses the official com.atproto.sync.getRepo HTTP endpoint and the official AT Protocol repository/MST implementation to decode a real CAR export. It preserves the repository DID, collection, record key, record CID, and signed commit revision as repoRev before handing validated ProtocolRecordEnvelope values to ProtocolAppView. A getRepo revision is per-repository metadata, not a firehose cursor; ordinary snapshots cannot carry a streamSeq field. Unsupported collections, malformed records, and authorship failures are reported in the snapshot quarantine instead of being silently accepted.

AtprotoSubscribeReposSource in src/atproto/subscribe-repos.ts consumes the official com.atproto.sync.subscribeRepos WebSocket format: each frame is two concatenated CBOR objects (the { op, t } header and payload), and commit blocks are decoded as an official CAR. It handles create, update, and delete operations while preserving the global seq, commit CID, repository rev, since, record path, and operation CID. Identity/account/handle/info and unknown frames become observable ingestion diagnostics. ProtocolIngestor persists one numeric streamSeq per subscription, buffers during snapshot load, deduplicates replay, and requires a fresh snapshot with an authoritative stream boundary after a gap or tooBig commit. The injected AuthoritativeRecoveryProvider must return a repository snapshot plus an authoritative boundary containing repoDid, the signed snapshot repoRev, the global streamSeq, and an opaque provider proof. Its verifier must confirm that the proof covers that exact snapshot and global position; the ingestor rejects malformed, unverified, or non-monotonic boundaries before replacing AppView state or advancing the durable cursor. It replays buffered events in sequence order, skips only equal-or-older tooBig markers already covered by the boundary, replays ordinary events at the boundary or later, and fails closed if repeated recovery makes no boundary progress. A plain getRepo snapshot never supplies that boundary, and lastObservedStreamSeq is never used to infer one. Without an injected provider, recovery stops with an explicit error rather than guessing. Jetstream remains an optional legacy integration and is not a substitute for this direct cursor handoff.

The current repository deliberately does not claim a production provider: AT Protocol getRepo and subscribeRepos do not expose an atomic snapshot-plus-global-sequence endpoint. A deployment must operate or trust a provider that can make that consistency guarantee (for example, a relay/PDS companion checkpoint service) and implement AuthoritativeRecoveryProvider with proof verification. Until that service exists, initial getRepo loading and live ingestion are supported, but gap/tooBig recovery is intentionally unavailable.

Commit signature verification against resolved DID keys is deliberately deferred to a separate follow-up. This slice therefore does not claim public federation readiness.

Intelligence Providers

The legacy simulation displays models as named provider resources:

GitHub Models (cloud)        Ollama (local)
├── claude-sonnet-4          ├── llama-3-70b
├── claude-haiku-4           └── codellama
├── gpt-4
└── phi-4

Source Layout

src/
  identity/       Ed25519 key generation, DID:key, signing/verification
  repository/     In-memory record store (one store per agent)
  storage/        DuckDB connection factory + async persistence layer
  firehose/       In-memory pub/sub event bus
  atproto/        AT Protocol bridge (PDS XRPC mirror + Jetstream federation consumer)
  audit/          WorkTrace builder that derives human-readable proof chains from firehose events
  schemas/        Zod schemas for all 19 record types
  intelligence/   Provider/model bootstrap (GitHub Models + Ollama)
  knowledge/      Knowledge provider bootstrap, seed documents, query with graceful degradation
  tools/          Tool provider bootstrap, definition records, invocation with graceful degradation
  agents/         Engine (bootstrap + createAgentRunner) + 6-agent roster
  orchestrator/   Mayor + Wanted Board (recommendation, assignment, verification, quality gate)
  reputation/     Stamp creation, aggregation, trust levels, rankClaims
  constants.ts    All magic numbers centralised
  demo/
    run.ts        Full E2E CLI demo (DuckDB-backed, persistent identities)
    dashboard/    Fastify SSE/REST server + HTML/CSS/JS dashboard
scripts/
  reset.ts        Clears data/ for a fresh start
  query.ts        DuckDB SQL inspector (npm run query "<SQL>")

Key Concepts

Agent Sovereignty — Each agent has its own data store, persisted to DuckDB. The Mayor coordinates but never owns agent data. Agent identities (DIDs + keypairs) persist across runs.

Wanted Board — Tasks posted as task.posting records in the Mayor's repo. Agents subscribe to the Firehose, evaluate tasks via shouldClaim() (domain + proficiency + tag matching), file task.claim records in their own repos. The Mayor Bundle ranks competing claims by capability fit, reputation, and load, writes a match.recommendation record, then writes a task.assignment record for the selected worker. The matcher and coordinator roles are bundled in this demo, but their typed records make the boundary explicit.

Quality Gate — The Mayor Bundle evaluates completions against quality thresholds (pass rate, coverage, summary depth), writes a verification.result, and then stamps accepted or rejected work. Poor-quality work is rejected: the task reopens, the agent earns a negative stamp linked to the verification evidence, and another agent can claim it. After 3 attempts, the task is force-accepted.

Reputation — After verification, an attestor issues a reputation.stamp (multi-dimensional: code quality, reliability, communication, creativity, efficiency). Stamps are typed by attestorType (mayor, requester, peer, verifier) and weighted during aggregation — Mayor stamps carry 40%, requester feedback 35%, peer review 20%. Stamps live in the attestor's repo, signed and attributable, and can carry evidenceUris pointing to verification records. Any observer can aggregate them into a trust level (newcomer → established → trusted → expert). A stamp is evidence, not a global score.

Network Participants — The dashboard shows all entity types in a unified "Network Participants" view: 👤 human task requesters (with their own DID and AT Protocol identity), 🏛️ the Mayor Bundle (matcher, coordinator, verifier, and attestor roles bundled in this demo), 🤖 worker agents, 🔧 tool providers, and 📚 knowledge providers. Customer task.posting and task.review events are labeled by handle in the firehose.

Proof Chain / WorkTrace — Open a completed task in the dashboard to see a role-by-role proof chain: requester posted work, agents claimed it, matcher recommended a worker, coordinator assigned it, worker completed it, verifier checked it, and attestor issued a stamp. GET /api/tasks/:id/trace returns the same derived trace as JSON, including missing evidence for pending tasks and consequences for future routing.

Intelligence Attribution — Every task completion records intelligenceUsed: { modelDid, providerDid }. Reputation stamps carry intelligenceDid. The full provenance chain (agent + model + provider) is verifiable.

Knowledge Attribution — Before each LLM call, agents query registered knowledge providers. Every consultation writes a knowledge.query record (providerDid, queryHash, verificationLevel). contextCids reference specific knowledge.document records — CID-addressable when published to a PDS. Reputation stamps carry knowledgeRefs.

Tool Attribution — After the LLM generates a response, agents invoke matching tool providers. Every invocation writes a tool.invocation record referencing the AT URI of the specific tool.definition (not just a name — the definition has its own DID and CID). Reputation stamps carry toolRefs.

Set KB_ENDPOINT and TOOL_ENDPOINT env vars to connect live providers; without them, a built-in mock provider with seed documents and tools runs automatically.


Inspection

DuckDB SQL Explorer

# Who are the agents?
npm run query "SELECT handle, did, created_at FROM agent_identities"

# What happened in the last run?
npm run query "SELECT seq, collection, rkey, operation FROM firehose_events ORDER BY seq DESC LIMIT 20"

# Who earned the most stamps?
npm run query "SELECT did, COUNT(*) AS stamps FROM firehose_events WHERE collection = 'network.mycelium.reputation.stamp' GROUP BY did ORDER BY 2 DESC"

# What proof-chain records were produced?
npm run query "SELECT collection, COUNT(*) FROM firehose_events WHERE collection IN ('network.mycelium.match.recommendation', 'network.mycelium.task.assignment', 'network.mycelium.verification.result') GROUP BY 1 ORDER BY 1"

# Which tasks got rejected?
npm run query "SELECT rkey, content FROM records WHERE collection = 'network.mycelium.task.posting'"

DuckDB CLI (if installed)

duckdb data/mycelium.duckdb

Dashboard

npm run dashboard   # → http://localhost:3000

The dashboard shows live SSE events, network participants, agent profiles, task timelines, proof chains, and evidence-linked reputation stamps.

After a task is posted, inspect its proof chain:

curl "http://localhost:3000/api/tasks/task-001/trace"

Testing

npm test            # run all 543 tests once
npm run test:watch  # watch mode

Test coverage: schemas, identity, firehose, repository, wanted-board, orchestrator, reputation, audit/WorkTrace, agents, intelligence, knowledge, tools, storage, atproto.


Documentation

Full design rationale, schemas, and implementation notes in docs/PRD/:


What's Next

  • Commit authenticity — Verify commit signatures against resolved DID keys before making a public federation-readiness claim.
  • Hosted demo — Run the official PDS and TypeScript AppView on one small VM, persist PDS data and cursor state, and verify a disposable AppView rebuild before publishing the demo URL. Keep the private PLC endpoint configurable; do not claim public federation until its deployment is pinned and tested.
  • Upstream generic seams — Propose OAuth permission-set resolution and PDS-side permission enforcement as generic changes in the forked .NET repositories, without moving Mycelium-specific lexicons into those projects.

About

Mycelium MVP — Federated agent orchestration on decentralized social protocols (AT Protocol, ActivityPub, Matrix)

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages