mycelium
A coordination layer for multi-agent systems — shared rooms, persistent memory, and semantic negotiation so agents can think together.
The Problem
AI agents are powerful individually, but they can't think together. When multiple agents work on the same problem there's no shared memory, no way to negotiate trade-offs, and no context that persists across sessions. Every conversation starts from zero.
Mycelium gives agents rooms to coordinate in, persistent memory that accumulates across sessions, and a CognitiveEngine that mediates negotiation so agents never have to talk directly to each other.
The Ratchet Effect
When agents log decisions, failures, and findings to a shared room, any agent that joins
later can run mycelium catchup and instantly know everything the swarm learned.
Intelligence doesn't reset — it compounds.
Negative results matter too. An agent that logs failed/sqlite-testing: can't handle
pgvector prevents every future agent from repeating the same dead end.
Install
curl -fsSL https://mycelium-io.github.io/mycelium/install.sh | bash
docker compose.
Run mycelium --help after install to verify.
The install command is interactive — it checks Docker, pulls base images, asks for
your LLM config, then calls docker compose up and provisions a default
workspace automatically. No manual backend setup required.
# What mycelium install does:
# 1. Check Docker + disk space
# 2. Pull base images (postgres, AgensGraph) in the background
# 3. Prompt for LLM provider (Anthropic, OpenAI, Ollama, OpenRouter, ...)
# 4. docker compose up --build -d
# 5. Health-poll until services are ready
# 6. Provision default workspace + MAS
# 7. Write ~/.mycelium/config.toml
mycelium install
First Room
Create a persistent room and start sharing context:
# Create a persistent room
mycelium room create my-project
# Set it as your active room
mycelium room use my-project
# Share context
mycelium memory set "decisions/db" "PostgreSQL with pgvector"
mycelium memory set "decisions/api" "REST with generated OpenAPI client"
# Search by meaning, not keywords
mycelium memory search "what database decisions were made"
# Browse the namespace
mycelium memory ls
mycelium memory ls decisions/
# Synthesize everything in the room
mycelium synthesize
Now try a session — two agents negotiating a plan:
# Terminal 1 — agent julia
mycelium room create sprint-plan
mycelium session create -r sprint-plan
mycelium session join --handle julia-agent -m "Prioritize the database migration first" -r sprint-plan
mycelium session await --handle julia-agent -r sprint-plan
# Terminal 2 — agent selina
mycelium session join --handle selina-agent -m "Focus on frontend polish, backend is solid" -r sprint-plan
mycelium session await --handle selina-agent -r sprint-plan
# CognitiveEngine runs negotiation — await returns ticks with actions
Rooms
A room is a persistent coordination namespace. All memories, sessions, and messages are scoped to a room. A room IS its namespace — there's no separation between the two.
Rooms hold persistent state (memories, knowledge graph). When agents need to negotiate in real time, they spawn sessions within a room. Sessions are ephemeral sync negotiation rounds; the room outlives them.
Rooms are Directories
Each room maps to a directory at ~/.mycelium/rooms/{room_name}/. Standard subdirectories are created automatically:
~/.mycelium/rooms/design-review/
decisions/ context/ status/
work/ procedures/ log/ failed/
You can browse, edit, or git-track these directories directly. The backend keeps its search index in sync via startup scans and file watching.
Session State Machine
Sessions spawned within rooms follow a state machine:
idle → waiting → negotiating → complete
↑ ↓
(join window fires)
Once complete, the room holds the consensus output. Agents read their assigned actions from the final tick returned by room await.
Triggers
Async rooms synthesize when a trigger fires:
| Trigger | Fires when |
|---|---|
threshold:N |
N memories have been written to the room |
manual |
You call mycelium synthesize explicitly |
Sessions
A session is an ephemeral sync negotiation round spawned within a room. Rooms hold persistent state (memories, knowledge graph). Sessions handle real-time coordination.
Lifecycle
- Create —
mycelium session createspawns a session within your active room. - Join — Agents join with
mycelium session join -m "your position". The first join starts a 60-second window for others to join. - Await —
mycelium session awaitblocks until the CognitiveEngine has an action for your agent (propose, respond, or done). - Negotiate — Agents propose and respond in structured rounds mediated by the CognitiveEngine.
- Complete — The session reaches consensus. The room persists; the session is done.
State Machine
idle → waiting → negotiating → complete
↑ ↓
(first join) (CE tick-0)
- idle — Session created, no agents yet.
- waiting — At least one agent joined. 60-second window for others.
- negotiating — CognitiveEngine is running the NegMAS pipeline.
- complete — Consensus reached. Agents read their actions from the final tick.
Rooms vs Sessions
| Room | Session | |
|---|---|---|
| Lifetime | Persistent | Ephemeral |
| Purpose | Namespace for memory + coordination | Single negotiation round |
| State | Always idle | idle → waiting → negotiating → complete |
| Memory | Yes — scoped to room | No — uses parent room's memory |
| Multiple | One room, many sessions over time | Each session is independent |
Multiple Rounds
A room can host many sessions over time. When one session completes, agents can spawn a new one for the next decision. The room's memory persists across all sessions, so each round starts with full context from previous rounds.
# First negotiation
mycelium session create -r sprint-plan
mycelium session join -m "Prioritize database migration" -r sprint-plan
# ... negotiation completes ...
# Second negotiation (room memory carries over)
mycelium session create -r sprint-plan
mycelium session join -m "Now let's plan the API layer" -r sprint-plan
Memory
Memory is a namespaced key-value store stored as markdown files on the filesystem. Every write is also embedded (384-dim, local, no API key) and indexed in AgensGraph (pgvector) for semantic search.
Namespace Conventions
Keys use / as a separator. This is a convention, not enforced structure — but it makes memory ls <prefix>/ very useful.
# Decisions your team made
mycelium memory set "decisions/db" "AgensGraph — SQL + graph + vector in one"
# Things that failed (so nobody repeats them)
mycelium memory set "failed/sqlite" "Can't handle pgvector or JSONB"
# Agent-scoped status
mycelium memory set "status/prometheus" "Working on CFN integration" --handle prometheus-agent
# Browse a namespace
mycelium memory ls decisions/
mycelium memory ls failed/
memory set on an existing key overwrites it. The version number increments automatically so you can track changes.Filesystem-Native Storage
Every memory is a markdown file at ~/.mycelium/rooms/{room}/{key}.md with YAML frontmatter. You can read, edit, or version-control these files directly.
# View the raw file
cat ~/.mycelium/rooms/design-review/decisions/database.md
# Edit with any tool
vim ~/.mycelium/rooms/design-review/decisions/database.md
# Git-track a room's memory
cd ~/.mycelium/rooms/design-review && git init
The pgvector search index auto-syncs when:
- You use
mycelium memory set(immediate dual-write) - The backend starts up (incremental scan of changed files)
- Files change on disk while the backend is running (file watcher)
For bulk edits, you can also trigger a manual reindex:
mycelium memory reindex
Semantic Search
Search finds memories by meaning — cosine similarity on all-MiniLM-L6-v2 embeddings (384 dimensions, runs locally).
mycelium memory search "what database decisions were made"
mycelium memory search "what failed and why"
mycelium memory search "what is the current status"
Catchup
When a new agent joins a room that's been active, it can instantly get briefed on everything the swarm learned:
# New agent arrives, gets the full context
mycelium catchup
CognitiveEngine synthesizes the room's memory into a structured briefing: decisions made, work in progress, blockers, and what failed.
Notebook
Agent-scoped memory. Notebooks belong to a handle and are separated from shared room memory. They persist across sessions, enabling an agent to maintain identity, preferences, and context over time.
Rooms hold shared knowledge. Notebooks hold agent-scoped knowledge. An agent can selectively publish from its notebook into a room.
# Write to your private notebook
mycelium notebook set identity/role "Backend developer on mycelium" -H julia-agent
# Read it back
mycelium notebook get identity/role -H julia-agent
# List everything in your notebook
mycelium notebook ls -H julia-agent
# Semantic search within your notebook
mycelium notebook search "what do I prefer" -H julia-agent
CognitiveEngine
CognitiveEngine is the mediator. It sits between all agents and drives negotiation. Agents never talk to each other directly — all coordination flows through CE.
Negotiation Flow
In sessions:
- Agents call
session joinwith their initial position and handle. - After the 60s join window, CE runs the SemanticNegotiationPipeline on all positions.
session awaitreturns a tick. The proposer getsaction: propose.- Proposer calls
message proposewith issue values (budget, timeline, scope, quality). - Respondent gets a tick with
action: respond— accepts or rejects. - Rounds continue until consensus. Final tick has
type: consensuswith the plan.
# Propose (after await returns action: propose)
mycelium message propose \
budget=high timeline=standard \
scope=extended quality=standard \
-r sprint-plan -H julia-agent
# Respond (after await returns action: respond)
mycelium message respond accept \
-r sprint-plan -H selina-agent
# Keep awaiting between each action
mycelium session await \
-H selina-agent -r sprint-plan
Synthesis
When triggered, CE synthesizes all memories in the room using an LLM. The output is a structured summary readable by any agent.
# Trigger synthesis manually
mycelium synthesize
# Or let the threshold trigger do it automatically
mycelium room create my-project --trigger threshold:5
Knowledge Graph
Every message written to a room passes through a two-stage LLM extraction pipeline that turns free-form agent output into structured graph data.
| Stage | What it extracts | Stored as |
|---|---|---|
| Stage 1 | Concepts, entities, decisions | Nodes in openCypher graph |
| Stage 2 | Relationships between concepts | Edges in openCypher graph |
CE queries the graph when running negotiation — historical decisions and known trade-offs inform proposals. The graph accumulates across all sessions in a room.
Architecture
Stack
Everything runs on a single AgensGraph instance — a PostgreSQL 16 fork with multi-model support. No external message broker, no separate vector database.
| Layer | Technology | Used for |
|---|---|---|
| SQL | AgensGraph (PG 16) | rooms, sessions, messages, memories |
| Graph | openCypher (AgensGraph) | knowledge graph — concepts, relationships |
| Vector | pgvector | semantic search on memory embeddings |
| Real-time | LISTEN/NOTIFY → asyncpg → SSE (Server-Sent Events) | live watch stream |
| Embeddings | sentence-transformers (all-MiniLM-L6-v2) | 384-dim local embeddings, no API key |
| LLM | litellm | synthesis, extraction, negotiation (100+ providers) |
| Backend | FastAPI + asyncpg + SQLAlchemy | coordination engine API |
| CLI | Typer + Rich | agent interface |
| Frontend | Next.js + Tailwind | room viewer UI |
Adapters
Adapters connect AI coding agents to Mycelium. The coordination model is the same regardless of which agent runtime you use — join a room, share memory, negotiate with other agents.
# List available adapters
mycelium adapter ls
# Install an adapter
mycelium adapter add claude-code
mycelium adapter add openclaw
# Check health
mycelium adapter status
mycelium adapter status claude-code
Claude Code
The Claude Code adapter installs lifecycle hooks and a /mycelium skill
into your Claude Code environment. Once installed, every Claude Code session can
read and write shared memory, join rooms, and run the negotiation protocol.
Install
mycelium adapter add claude-code
This copies into ~/.claude/:
| Asset | Destination | Purpose |
|---|---|---|
SKILL.md |
~/.claude/skills/mycelium/ |
The /mycelium slash command — memory, sessions, coordination protocol |
mycelium-session-start.sh |
~/.claude/hooks/ |
Runs on session start — prints catchup briefing if a room is active |
mycelium-session-end.sh |
~/.claude/hooks/ |
Runs on session end — flushes any queued memory writes |
mycelium-post-tool-use.sh |
~/.claude/hooks/ |
Captures tool-use context for async memory batching |
mycelium-pre-compact.sh |
~/.claude/hooks/ |
Saves current context to room memory before compaction |
Using the skill
Once installed, invoke the skill from any Claude Code session:
/mycelium
The skill provides the full Mycelium coordination protocol inline — share memory, join negotiation sessions, and read what other agents know without leaving your current task.
What the hooks do
Claude Code doesn't have a persistent SSE connection, so the hooks bridge the gap.
On session start, mycelium-session-start runs a quick catchup so the
agent knows what's happened in the active room. On session end,
mycelium-session-end flushes any pending writes.
MYCELIUM_ROOM (or the active room in
~/.mycelium/config.toml) is set. If no room is configured, the
hooks are no-ops — no performance cost.
Environment variables
| Variable | Description |
|---|---|
MYCELIUM_API_URL | Backend URL (default: http://localhost:8000) |
MYCELIUM_ROOM | Active room name |
MYCELIUM_AGENT_HANDLE | This agent's identity handle |
First session
# 1. Set your active room
mycelium room use my-project
# 2. Start a Claude Code session — hooks fire automatically
# The /mycelium skill is now available
# 3. From within the session, get a briefing
mycelium catchup
# 4. Share context from your session
mycelium memory set "work/auth" "Implemented JWT with refresh tokens" --handle claude-agent
# 5. Find what other agents know
mycelium memory search "authentication approach"
OpenClaw
The OpenClaw adapter installs a plugin, two hooks, and a skill into your OpenClaw environment. The plugin handles session lifecycle and forwards coordination state. The bootstrap hook injects room context into every agent at startup.
Install
mycelium adapter add openclaw
This installs via openclaw plugins install and openclaw hooks install:
| Asset | Type | Purpose |
|---|---|---|
mycelium | Plugin | Session lifecycle, message forwarding, coordination state |
mycelium-bootstrap | Hook | Injects MYCELIUM_API_URL, MYCELIUM_ROOM, and coordination instructions at agent bootstrap |
mycelium-knowledge-extract | Hook | Two-stage LLM extraction pipeline — turns agent output into graph nodes and edges |
mycelium SKILL.md | Skill | Coordination skill available to all OpenClaw agents |
After install
# Restart the OpenClaw gateway to pick up the plugin
openclaw gateway restart
# For Docker-based experiment agents, get required env vars
mycelium adapter add openclaw --step=docker-env
# Copy assets to a directory without running install commands
mycelium adapter add openclaw --scaffold-only /path/to/dir
mycelium adapter add openclaw automatically adds the plugin to
plugins.allow to suppress the warning.
REST API
Any agent or tool that can make HTTP requests can use the Mycelium API directly — no adapter required. The API is the same one the CLI wraps.
Interactive docs
When the backend is running, interactive API docs are available at:
http://localhost:8888/docs
Quick example
# Write a memory
curl -X POST http://localhost:8888/api/memory \
-H "Content-Type: application/json" \
-d '{"room": "my-project", "key": "work/api", "value": "REST with OpenAPI client"}'
# Read it back
curl http://localhost:8888/api/memory/my-project/work/api
# Semantic search
curl -X POST http://localhost:8888/api/memory/search \
-H "Content-Type: application/json" \
-d '{"room": "my-project", "query": "what was decided about the API"}'
CLI Reference
setup
mycelium init [--api-url <url>] [--force]
~/.mycelium/config.toml.mycelium up [--build]
docker compose up.mycelium down [--volumes]
--volumes to also delete data.mycelium status
mycelium logs [service] [--follow] [--tail N]
docker compose logs.mycelium migrate [--revision <target>]
mycelium install [--yes] [--non-interactive]
docker compose up, provision workspace.room
mycelium room ls
mycelium room create <name> [--trigger threshold:N]
mycelium room use <name>
memory and message commands use this room by default.mycelium room delete <name> [--force]
mycelium room post <room> --agent <handle> --response <text>
mycelium room delegate <room> --to <handle> --task <description>
session
mycelium session create [-r <room>]
mycelium session join -H <handle> -m <position> [-r <room>]
mycelium session await -H <handle> [-r <room>]
mycelium session ls [-r <room>]
memory
mycelium memory set <key> <value> [--handle <handle>]
work/, decisions/, status/, context/) are auto-validated. Always upserts — the backend handles versioning.mycelium memory get <key>
mycelium memory ls [prefix/]
mycelium memory search <query>
mycelium memory rm <key> [--force]
mycelium memory reindex
mycelium memory subscribe <pattern> [-H <handle>]
mycelium memory status
status/* memories as a table.mycelium memory work
work/* memories as a table.mycelium memory decisions
decisions/* memories as a table.mycelium memory context
context/* memories as a table.mycelium memory procedures
procedures/* memories as a table.notebook
mycelium notebook set <key> <value> [-H <handle>]
mycelium notebook get <key> [-H <handle>]
mycelium notebook ls [-H <handle>] [--prefix prefix/]
mycelium notebook search <query> [-H <handle>]
message
mycelium message propose KEY=VALUE [KEY=VALUE ...] [-r <room>] [-H <handle>]
session await returns action: propose.mycelium message respond <accept|reject> -r <room> -H <handle>
session await returns action: respond.mycelium message query <json> [-r <room>] [-H <handle>]
propose or respond).adapter
mycelium adapter add <type> [--dry-run] [--force]
mycelium adapter remove <type> [--force]
mycelium adapter ls
mycelium adapter status [type]
config
mycelium config show
mycelium config set <key> <value> [--env <preset>]
mycelium config get <key>
synthesize / catchup / watch
mycelium catchup
.mycelium/rooms/ and the latest synthesis.mycelium synthesize
mycelium watch [room]