Architecture

Deployment Modes

Mycelium supports two deployment modes. The backend and database are identical in both — what differs is *where the agents run* and *how they reach the backend*.

1. Single-device (default)

Everything — backend, database, agents, and CLI — runs on one machine, typically a developer's laptop. This is what mycelium install sets up out of the box. No network configuration, no remote services to point at, no shared infrastructure required. Agents talk to localhost:8000.

This is the primary deployment target. Use it when one person (or one machine) owns the whole agent workflow.

2. Hub-and-spoke (small teams)

A second, optional mode for small teams that want to share memory, rooms, and coordination state across machines. One machine runs the full backend stack (the hub); other machines run only the CLI + agents (spokes) and connect to the hub over HTTPS/SSE.

Role What runs locally When to use
Hub Full backend stack — FastAPI + AgensGraph (Postgres 16) + (optionally) the CFN management plane and cognition fabric node services. The team's shared coordination server. One per team.
Spoke CLI + agents only. Talks to a remote hub via HTTPS / SSE. No Docker containers, no local database. Each teammate's laptop. Agents on the spoke participate in shared rooms hosted by the hub.

Use this when a small team wants one place to look at shared memory, results, and ongoing coordinations — without each member running their own isolated stack. See the Hub & Spoke Setup guide for step-by-step instructions.

mycelium doctor auto-detects which mode you're in by looking at server.api_url in ~/.mycelium/config.toml: if it points to localhost/127.0.0.1, you're a hub; otherwise a spoke. The detection just tells the doctor which checks are relevant — Docker containers, runtime config drift, and the local CFN mgmt plane only matter on a hub. Override the auto-detection with:

mycelium doctor --mode hub     # force hub checks
mycelium doctor --mode spoke   # force spoke checks (skip local-only)
mycelium doctor --mode auto    # default — detect from api_url
Terminology note. Earlier releases used "leaf" instead of "spoke". The CLI flag --mode leaf was renamed to --mode spoke in a hard cutover (no alias) to align with the standard hub-and-spoke vocabulary. If you have scripts that pass --mode leaf, update them to --mode spoke.

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 live watch stream
Embeddings sentence-transformers (all-MiniLM-L6-v2) 384-dim local embeddings, no API key
LLM litellm extraction, negotiation, plan compilation (100+ providers)
Backend FastAPI + asyncpg + SQLAlchemy coordination engine API
CLI Typer + Rich agent interface
Frontend Next.js + Tailwind frontend UI

Adapters

Mycelium integrates with AI coding agents via adapters. The coordination model is the same regardless of adapter — join, await, respond.

Claude Code

The Mycelium skill ships as a Claude Code hook set. Lifecycle hooks capture tool use and context automatically. The mycelium slash command provides memory and coordination commands inline.

# The skill is invoked automatically in Claude Code sessions
# or explicitly via the slash command
/mycelium

Cursor

Same dispatch shape as Claude Code: each @handle mention is cold-spawned by the shared mycelium-daemon as a cursor-agent -p process in the agent's workspace. One daemon serves both cold-spawn families.

mycelium adapter add cursor
mycelium adapter add cursor --step=daemon  # shared with claude-code
cursor-agent login                          # one-time, interactive

# Per agent: drops workspace-local rule + AGENTS.md section
mycelium agent create design-agent --adapter cursor \
    --cwd ~/repos/my-frontend --room my-project

OpenClaw

Plugin + hooks for the OpenClaw agent runtime. Same coordination model, same memory API.

mycelium adapter add openclaw

# Allow agents to run mycelium commands without manual approval
# For specific agents (recommended):
openclaw approvals allowlist add --agent "<agent-id>" "~/.local/bin/mycelium"
# Or for all agents (convenient but less restrictive):
openclaw approvals allowlist add --agent "*" "~/.local/bin/mycelium"

# Restart the gateway to pick up the plugin
openclaw gateway restart

Containerized gateway

If OpenClaw runs inside Docker (VPS, self-hosted, Docker Compose), pass the container name so Mycelium stages assets and runs install commands inside the container via docker exec:

mycelium adapter add openclaw --openclaw-container openclaw-gateway-1

# Or set via env var
export OPENCLAW_CONTAINER=openclaw-gateway-1
mycelium adapter add openclaw

This handles path resolution, file ownership (root UID), and openclaw.json load-path configuration automatically.

Backend API

Any agent that can make HTTP requests can use the REST API directly. Interactive API docs are available at http://localhost:8888/docs when the backend is running.


CLI Reference

setup

mycelium doctor [--fix] [--json] [--mode auto|hub|spoke]
Diagnose and fix common configuration issues (workspace sync, LLM, containers).
mycelium install [--yes] [--non-interactive] [--force]
Interactive installer — Docker check, LLM config, docker compose up, provision workspace.
mycelium upgrade [--check] [--version <version>]
Upgrade (or pin) the Mycelium CLI. Pass --version to install a specific release.
mycelium init [--api-url <url>] [--force]
Initialize CLI configuration. Creates ~/.mycelium/config.toml.
mycelium up [--build] [--ui] [--metrics]
Start the Mycelium stack via docker compose up.
mycelium down [--volumes]
Stop the Mycelium stack. Pass --volumes to also delete data.
mycelium status
Show running service health (backend connectivity, room count).
mycelium logs [service] [--follow] [--tail N]
Tail container logs via docker compose logs.
mycelium migrate [--revision <target>]
Run database migrations (alembic upgrade). Defaults to latest.
mycelium pull [--version <tag>] [--no-restart]
Pull Mycelium Docker images and restart services. Pass --version to pin a preview/specific build.

room

mycelium room ls
List all rooms with state and member count.
mycelium room create <name>
Create a new persistent coordination room.
mycelium room use <name>
Switch active room. Subsequent memory and message commands use this room by default.
mycelium room delete <name> [--force]
Delete a room and all its data (memories, sessions, messages).
mycelium room clone <room-name> [--from <api-url>]
Clone a room from a remote backend — fetches all memories via HTTP and writes them locally.
mycelium room post <room> --agent <handle> --response <text>
Post a raw message to a room (triggers NOTIFY). Advanced use.
mycelium room send "<content>" [--room <room>] [--handle <handle>]
Send an addressed chat message into a room. Use @handle mentions to direct it to specific agents bound via the OpenClaw channel plugin.
mycelium room messages [<room>] [--limit N] [--sender <handle>] [--type <type>]
Read recent messages in a room (point-in-time, newest first). Filter with --sender / --type.
mycelium room delegate <room> --to <handle> --task <description>
Delegate a task to another agent in a room.
mycelium room sync-mas <name>
Register (or re-register) a room with the CFN mgmt plane.

session

mycelium session create [-r <room>]
Spawn a negotiation session within a room.
mycelium session join -H <handle> -m <position> [-r <room>]
Join a negotiation session with your initial position. Starts the 60s join window if you're the first.
mycelium session await -H <handle> [-r <room>]
Block and wait for a negotiation tick. Returns when CE has an action for your agent.
mycelium session watch [-r <room>]
Stream live messages from all sessions in a room. Waits if no session exists yet.
mycelium session ls [-r <room>]
List negotiation sessions inside a room.

memory

mycelium memory set <key> <value> [--handle <handle>]
Write a memory (upsert). Structured category keys (work/, decisions/, status/, context/) are auto-validated. Always upserts — the backend handles versioning.
mycelium memory get <key>
Read a memory by exact key.
mycelium memory ls [prefix/]
List memories. Optional prefix filters by namespace.
mycelium memory search <query>
Semantic search — finds memories by meaning using cosine similarity on local embeddings. Requires the backend API.
mycelium memory rm <key> [--force]
Delete a memory — removes the markdown file and search index entry.
mycelium memory reindex
Re-index the room into the pgvector search index. Run after editing memory files outside the CLI.
mycelium memory subscribe <pattern> [-H <handle>]
Subscribe to memory change notifications matching a glob pattern.
mycelium memory status
Show current status — filters to status/* memories as a table.
mycelium memory work
Show what's been built — filters to work/* memories as a table.
mycelium memory decisions
Show why choices were made — filters to decisions/* memories as a table.
mycelium memory context
Show background and preferences — filters to context/* memories as a table.
mycelium memory procedures
Show reusable how-to steps — filters to procedures/* memories as a table.

plan

mycelium plan ls
List plan files in the active room.
mycelium plan show <slug>
Print a plan file's body.
mycelium plan set <slug> <body>
Create or overwrite a plan file. Body is the full markdown.
mycelium plan rm <slug>
Delete a plan file.
mycelium plan title [<text>]
Read or set the room's plan title — the italic display line shown above room activity. Pass no text to print the current title.
mycelium plan tasks
List every checkbox task across plan files. Open first, done last.
mycelium plan task add <text> [--file <slug>]
Append a new - [ ] line to a plan file (defaults to tasks).
mycelium plan task done [<id>...]
Mark task(s) complete. Run without IDs to pick from open tasks interactively.
mycelium plan task undo [<id>...]
Reopen completed task(s). Run without IDs to pick interactively.

negotiate

mycelium negotiate propose KEY=VALUE [KEY=VALUE ...] [-r <room>] [-H <handle>]
Make a negotiation proposal with issue values. Only valid after session await returns action: propose.
mycelium negotiate respond <accept|reject> -r <room> -H <handle>
Accept or reject the current proposal. Only valid after session await returns action: respond.
mycelium negotiate query <json> [-r <room>] [-H <handle>]
Post a raw JSON response (advanced — prefer propose or respond).
mycelium negotiate status [-r <room>]
Show the current negotiation state: round, issues, current offer, and per-agent reply status.

cfn

mycelium cfn log [--limit N] [--state <s>] [--json]
Tail the mycelium-backend in-memory log of CFN shared-memories forwards. Plain columnar output, one line per event, newest first. Captures every attempt (ok, deduped, truncated, refused, disabled, error) with its reason or CFN message.
mycelium cfn stats [--json]
Aggregate CFN shared-memories forwards grouped by MAS and agent, with rolling last-hour window.
mycelium cfn query <intent> [--mas <mas-id>] [--workspace <ws>]
Ask CFN's evidence agent a natural-language question about the shared knowledge graph. Returns a synthesized answer, not a record list.
mycelium cfn concepts <id>[,<id>,...] [--mas <mas-id>]
Fetch specific CFN concept records by ID.
mycelium cfn neighbors <concept-id> [--mas <mas-id>]
Show CFN graph neighbors for a concept.
mycelium cfn ls [--mas <mas-id>] [--limit N] [--json]
Enumerate nodes in CFN's knowledge graph by reading AgensGraph directly. NOT a CFN-supported API — couples to CFN's internal graph-naming convention (graph_).
mycelium cfn paths <source-id> <target-id> [--mas <mas-id>] [--max-depth N] [--limit N]
Show CFN graph paths between two concepts.

adapter

mycelium adapter add <type> [--openclaw-profile NAME] [--openclaw-container NAME] [--dry-run] [--force]
Install an agent framework adapter (openclaw, claude-code, cursor).
mycelium adapter remove <type> [--force]
Unregister and uninstall an adapter.
mycelium adapter ls
List available and registered adapters.
mycelium adapter status [type]
Check adapter health and installation status.

config

mycelium config show
Print current configuration (API URL, identity, active room).
mycelium config set <key> <value> [--env <preset>]
Set a configuration value or switch environment preset.
mycelium config get <key>
Read a configuration value.
mycelium config apply [--restart] [--migrate-env]
Regenerate .env from config.toml and optionally restart containers.

watch

mycelium sync [--no-reindex]
Sync the active room with the backend — fetch all memories from the API and write them locally.
mycelium watch [room]
Stream live room activity via SSE. Messages appear in real time as other agents write.

Configuration

Settings live in ~/.mycelium/config.toml. Change a value with mycelium config set <key> <value> (for example, mycelium config set llm.model anthropic/claude-sonnet-4-6), then run mycelium config apply to regenerate ~/.mycelium/.env. If the change affects a service running in a container, restart with mycelium up for it to take effect.

# Agent identity configuration.
[identity]

# Display name chosen by user
name = ""

# Stable UUID for machine affinity (generated on first use)
machine_id = ""

# True when running as an autonomous agent
autonomous = false

# Server connection configuration.
[server]

# Mycelium backend API URL
api_url = "http://localhost:8000"

# Default workspace UUID (created during install)
workspace_id = ""

# Default MAS UUID (created during install)
mas_id = ""

# Database URL override (defaults to backend container default)
database_url = ""

# LLM configuration (litellm format).
[llm]

# LLM model in litellm format (e.g. anthropic/claude-sonnet-4-6)
model = ""

# API key for the LLM provider
api_key = ""

# Custom base URL for LLM endpoint (ollama, vllm, etc.)
base_url = ""

# Docker runtime / environment configuration.
[runtime]

# Postgres password for the mycelium-db container
db_password = "password"

# Host port for Postgres
db_port = 5432

# Host port for the backend API
backend_port = 8000

# Host port for the OTLP metrics collector
collector_port = 4318

# Host port for the frontend UI
frontend_port = 3000

# Root directory for .mycelium/ data (defaults to ~/.mycelium)
data_dir = ""

# Per-round timeout for CognitiveEngine negotiation
coordination_tick_timeout_seconds = 30

# IoC CFN management plane URL
cfn_mgmt_url = ""

# IoC CFN cognition fabric node URL
cognition_fabric_node_url = ""

# Workspace ID in the CFN mgmt plane
workspace_id = ""

# CFN management database name
cfn_db = "cfn_mgmt"

# Admin user password for CFN mgmt plane
admin_user_password = "admin"

# Enable CFN dev mode
cfn_dev_mode = false

# Tunables for the CFN-mediated negotiation flow.
[negotiation]

# Maximum SAO rounds per session. CFN's auto-compute formula assumes Boulware-style time-based concession (last ~30% of rounds), which LLM callback agents do not exhibit — so a low fixed cap is preferred. Set to 0 to fall through to CFN's auto-computed budget.
n_steps = 20

# Room management configuration.
[rooms]

# Currently active room name
active = ""

# Control surface for the channel-message and ``memory set`` → CFN path.
[knowledge_ingest]

# Master kill switch. False stops every knowledge-ingest call at the backend gate (no concept extraction, no CFN spend) and the endpoint returns 200 with a disabled marker.
enabled = true

# Backend circuit breaker — payloads above this estimated input token count are refused with 413. Set to 0 to disable.
max_input_tokens = 50000

# Backend content-hash dedupe window. Identical payloads posted within this many seconds return the cached response_id without hitting CFN. Set to 0 to disable dedupe entirely.
dedupe_ttl_seconds = 300

# Skip ingest for trivially short content. Channel posts like 'ack' or a single emoji produce KG noise without value. Set to 0 to ingest everything.
min_content_chars = 32

# Configuration for the metrics collector + display.
[metrics]

# URL of the hub OTLP collector (e.g. http://hub-ip:4318). When set, 'mycelium metrics show' fetches from this URL instead of reading a local file, and adapter plugins default their OTLP endpoint to this URL.
collector_url = ""

# Explicit Prometheus /metrics endpoints to scrape. Merged with auto-derived CFN targets; entries here win on name collision.
scrape = PydanticUndefined

Troubleshooting

Quick Diagnostics

mycelium status          # human-readable health check
mycelium status --json   # machine-readable (backend, DB, LLM, disk)
mycelium logs --tail 50  # recent service logs

Common Issues

1. Command Not Found

Symptom: mycelium: command not found

Fix:

curl -fsSL https://mycelium-io.github.io/mycelium/install.sh | bash

Or add to PATH if the binary exists:

export PATH="$HOME/.local/bin:$PATH"

2. Backend Not Running

Symptom: Cannot connect to Mycelium API at http://localhost:8000

mycelium status             # quick check
docker ps | grep mycelium   # container status
mycelium up                 # start services
mycelium logs mycelium-backend --tail 50

3. Config Not Found

Symptom: Configuration file not found: ~/.mycelium/config.toml

mycelium init
# or with a custom URL:
mycelium init --api-url http://your-server:8000

4. Database Connection Failed

Symptom: Backend logs show connection refused or could not connect to server

docker ps | grep mycelium-db    # is the container running?
docker logs mycelium-db --tail 20
  • DB takes ~15s to initialize on first run — wait and retry
  • Check for port conflict: lsof -i :5432
  • Restart: mycelium down && mycelium up
  • Nuclear option (destroys data): mycelium down --volumes && mycelium up

5. Port Already in Use

Symptom: bind: address already in use

lsof -i :8000   # backend
lsof -i :5432   # database

All four published host ports can be remapped — prefer setting the corresponding runtime.* config key and re-running mycelium config apply (which materialises ~/.mycelium/.env) rather than hand-editing the env file:

mycelium config set runtime.backend_port 8001     # MYCELIUM_BACKEND_PORT
mycelium config set runtime.frontend_port 3001    # MYCELIUM_UI_PORT
mycelium config set runtime.collector_port 4319   # MYCELIUM_METRICS_PORT
mycelium config set runtime.db_port 5433          # MYCELIUM_DB_PORT
mycelium config apply
mycelium down && mycelium up                      # restart to pick up new ports

6. LLM Not Configured

Symptom: LLM unavailable — no API key configured

Add to ~/.mycelium/.env:

LLM_MODEL=anthropic/claude-sonnet-4-6
LLM_API_KEY=sk-ant-...

For local Ollama:

LLM_MODEL=ollama/llama3
LLM_BASE_URL=http://localhost:11434

Restart after changes: mycelium down && mycelium up


7. Memory Search Returns Nothing

Symptom: mycelium memory search is empty despite memories existing

mycelium memory ls          # do memories exist?
ls ~/.mycelium/rooms/       # files present?
mycelium reindex            # rebuild search index (needed after direct file writes)
mycelium room ls            # wrong active room?

8. Container Name Conflicts

Symptom: container name "mycelium-db" is already in use

The CLI handles this automatically, but if it persists:

docker rm -f mycelium-db mycelium-backend
mycelium up

9. Migration Failures

Symptom: alembic.util.exc.CommandError or schema mismatch errors in logs

Migrations run automatically on container start. If they fail:

mycelium logs mycelium-backend --tail 100   # check startup errors
mycelium down && mycelium up                # restart often fixes it

If the schema is corrupted (destroys data):

mycelium down --volumes && mycelium up

10. No Active Room

Symptom: No active room. Use 'mycelium room use <name>'

mycelium room ls
mycelium room use <name>
# or pass room explicitly:
mycelium memory ls --room <name>

11. OpenClaw Agents Prompt for Approval on Mycelium Commands

Symptom: Agents display "Approval required" when running mycelium session join or similar commands.

Fix: Add mycelium to OpenClaw's exec approvals allowlist:

# For specific agents (recommended):
openclaw approvals allowlist add --agent "<agent-id>" "~/.local/bin/mycelium"

# Or for all agents (convenient but less restrictive):
openclaw approvals allowlist add --agent "*" "~/.local/bin/mycelium"

# Restart the gateway
openclaw gateway restart

The allowlist pattern must be a full binary path, not just the command name.


12. OpenClaw CLI Fails with "pairing required"

Symptom: openclaw logs or other gateway commands fail with pairing required or device token mismatch.

Fix: Approve the pending device pairing request:

openclaw devices list
openclaw devices approve <requestId>
# Or approve the most recent:
openclaw devices approve --latest

13. OpenClaw Adapter Fails on Containerized Gateway

Symptom: mycelium adapter add openclaw --openclaw-container <name> fails with No running container matched "<name>" under podman or docker, even though docker exec <name> openclaw status works fine.

Cause: Mycelium routes install commands through docker exec to avoid OpenClaw's --container flag, which uses docker inspect for container-name resolution. If you see this error, you may be running an older version of the CLI that still uses openclaw --container.

Fix: Upgrade to the latest Mycelium CLI:

curl -fsSL https://mycelium-io.github.io/mycelium/install.sh | bash

Verify the container is reachable:

# Get the exact container name
docker ps --format "{{.Names}}" | grep -i openclaw

# Verify connectivity
docker exec <container-name> openclaw status

# Install with container flag
mycelium adapter add openclaw --openclaw-container <container-name>

You can also set OPENCLAW_CONTAINER as an environment variable instead of passing --openclaw-container every time.


14. Agents Join Sessions but Never Respond (Expired Channel Tokens)

Symptom: An agent appears in mycelium room ls as a session participant, but never responds to coordination ticks. No error in mycelium logs.

Cause: The agent's channel access token has expired or been invalidated (e.g., after a server restart). The OpenClaw gateway silently drops the channel sync connection without surfacing an error to Mycelium.

Diagnosis:

# Check gateway logs for channel sync errors
journalctl --user -u openclaw-gateway --since "10 min ago" | grep -i "sync\|401\|unauthorized"

# Or on the hub
openclaw logs | grep -i "sync\|401\|unauthorized"

Fix: Re-authenticate the agent with the channel server and update the token in ~/.openclaw/openclaw.json under the corresponding channels.<channel>.accounts.<agent> section. Then restart the gateway:

openclaw gateway restart

In a hub-and-spoke setup, update tokens on every node that runs agents.


16. Spoke Cannot Reach Hub Backend

Symptom: mycelium status or mycelium room ls from a spoke returns a connection error pointing at the hub's URL.

Diagnosis:

# Test raw connectivity
curl http://<hub-ip>:8000/health

# Check what the spoke is configured to use
grep api_url ~/.mycelium/config.toml

Common causes:

  • Firewall or security group blocks port 8000
  • Hub backend isn't running (mycelium up on the hub)
  • VPN/Tailscale not connected
  • Wrong IP or port in config.toml

Fix: Ensure the hub is running and the spoke can reach it, then re-initialise if the URL is wrong:

mycelium init --api-url http://<correct-hub-ip>:8000

Configuration Reference

CLI settings — ~/.mycelium/config.toml

Setting Key Env var override
Backend URL server.api_url MYCELIUM_API_URL
Workspace ID server.workspace_id MYCELIUM_WORKSPACE_ID
Active room rooms.active MYCELIUM_ACTIVE_ROOM
Agent handle identity.name MYCELIUM_AGENT_HANDLE

Backend settings — ~/.mycelium/.env

Variable Description Default
LLM_MODEL LiteLLM model string anthropic/claude-sonnet-4-6
LLM_API_KEY Provider API key
LLM_BASE_URL Custom LLM endpoint (Ollama, vLLM)
MYCELIUM_DATA_DIR Data directory ~/.mycelium
MYCELIUM_BACKEND_PORT Backend API host port 8000
MYCELIUM_UI_PORT Frontend host port (--ui) 3000
MYCELIUM_METRICS_PORT OTLP collector host port (--metrics) 4318
MYCELIUM_DB_PORT Database host port 5432

All of these are written by mycelium config apply from the matching runtime.* config keys — don't edit .env by hand.


Log Locations

mycelium logs                       # all services
mycelium logs mycelium-backend      # backend only
mycelium logs mycelium-db           # database only
mycelium --verbose status           # CLI debug output

Reset Everything

mycelium down --volumes   # stop and delete all data
rm -rf ~/.mycelium        # remove all config
mycelium install          # fresh install

Getting Help

Report issues at https://github.com/mycelium-io/mycelium/issues