How to use

Start with one tool. Protect its full lifecycle.

Mycelium is open-source and self-hosted. Python applications use the engine directly; other languages use the same engine through its HTTP/JSON sidecar. Run one sidecar locally or coordinate multiple sidecars through shared PostgreSQL. No Mycelium cloud account or hosted endpoint is required.

Start

Install

Requires Python 3.10 or later.

pip install mycelium-runtime
pip install 'mycelium-runtime[langgraph]'   # automatic ToolRuntime IDs
pip install 'mycelium-runtime[redis]'   # optional
pip install 'mycelium-runtime[postgres]'

mycelium init              # on-ramp (transition + one ledgered tool)
mycelium init --full       # reference: all guards (fill TODOs; not default)
mycelium init --minimal    # smaller multi-guard scaffold
mycelium demo              # feature tour: unguarded vs ledgered + gates / hard-block / release
mycelium demo --redis      # optional Cloud-style 2-worker Redis proof
mycelium run --config mycelium.yaml -- python -m my_agent

TypeScript, Go, and other languages

The engine is Python, but the doorway into it is language-neutral. Run Mycelium as a self-hosted sidecar beside your application. Your application sends action details and results over HTTP/JSON; the sidecar owns identity, claims, leases, fencing, transitions, and recovery.

pip install mycelium-runtime
umask 077
python -c 'import secrets; print(secrets.token_urlsafe(32))' > /absolute/path/sidecar.token
# /absolute/path/sidecar.yaml
kind: mycelium-sidecar
protocol_version: "v1alpha1"
identity_namespace: identity-v1
tenant_id: tenant-a
application_id: app-a
bearer_token_file: /absolute/path/sidecar.token
ledger: {type: file, path: /absolute/path/sidecar-ledger.json}
outcome_storage: {type: file, path: /absolute/path/sidecar-outcomes.ndjson}
server: {host: 127.0.0.1, port: 8787}
mycelium sidecar serve --config /absolute/path/sidecar.yaml

# TypeScript / Node.js
npm install @mycelium-labs/sidecar-client@experimental

# Go
go get github.com/mycelium-labs/mycelium/clients/go@v0.1.1

For multiple sidecars, use the repository's shared PostgreSQL Docker Compose profile:

git clone https://github.com/mycelium-labs/mycelium.git
cd mycelium
export MYCELIUM_POSTGRES_PASSWORD="$(openssl rand -hex 24)"
export MYCELIUM_SIDECAR_TOKEN="$(openssl rand -hex 32)"
docker compose -f docker-compose.sidecar.yml up --build

Complete self-hosting guide ↗ · TypeScript package ↗ · Go module ↗ · HTTP/OpenAPI protocol ↗

Java, Rust, C#, Ruby, and other runtimes can call the same authenticated OpenAPI contract directly. The language clients are thin helpers; they do not duplicate Mycelium's Python state machine. The v1alpha1 development and shared PostgreSQL profiles are experimental and self-hosted, not a public multi-tenant service.

Agent-assisted setup

The repository includes a $mycelium-setup skill for coding agents. Ask the agent to use it in your project. It inventories tool entry points, proposes side-effect classifications, writes or updates mycelium.yaml, wires supported runtimes, adds focused tests, and runs Doctor and Verify.

Use $mycelium-setup to protect this project.

The skill does not invent signing keys, provider credentials, business request IDs, production namespaces, or approval policy. Review consequential tool classifications and supply those host-owned values yourself. The generated YAML remains ordinary project configuration that you can inspect and edit.

How it fits

Mycelium sits between the agent loop and your tools after the LLM returns tool_calls. At that boundary it composes input and authority checks, run controls, safe execution, outcome resolution, and evidence. Its execution ledger proves run-or-not and enforces at-most-once when retries or crashes occur.

What it does

Mycelium makes tool actions reliable before, during, and after execution. mycelium init / mycelium run begin with durable execution control for one tool; configure the other control areas that match your workflow.

Untrusted tool output

Tool and retrieval output is data, even when it contains imperative language. Mark external content as untrusted_data so it cannot be promoted into operator-release authorization claims.

from mycelium import mark_untrusted_tool_output

search_result = mark_untrusted_tool_output(
    tool_result,
    source="tool:search",
)

This is a narrow prompt-injection defense at the authorization boundary. It blocks one path from injected tool content to release authority; it does not replace context isolation or broader prompt-injection evaluation.

Execution & recovery

Action execution

Transition ledger for safe execution: the default mycelium init / mycelium run path. Each ledgered tool gets a side_effect_class and transition_key. Repeated dispatches resolve through gates, not blind re-execution. Read the prevention page →

from mycelium import load_config

config = load_config("mycelium.yaml")

@config.apply
def send_payment(amount: float, recipient: str) -> dict:
    return gateway.charge(amount, recipient)

# payment: duplicate resolves existing transition; won't charge twice
send_payment(amount=100.0, recipient="acct_123", tool_call_id="call_pay")

See Resolution for gate semantics and the SDK README for the full reference.

Durable composite recovery

Python applications can wrap an unchanged bounded function whose consequential child calls are already protected by Mycelium. The opt-in @composite decorator pins the child-call manifest, returns stored child results during replay, and runs only children that have not already completed. Every retry must provide the same stable, host-owned operation ID.

@composite(storage)
def publish_batch(operation_id: str):
    for index in range(3):
        result = publish_one(idempotency_key=f"{operation_id}:{index}", index=index)
    return result

Here publish_one must already be a ledgered consequential tool. The loop count is a literal from 1 to 32; each iteration has its own child identity and should use its own provider idempotency key. The decorator also supports straight-line steps and one boolean branch chosen from an invocation argument or the immediately preceding ledgered child's result. Branches and loops cannot be combined in one composite.

This Python feature supports file, SQLite, Redis, and PostgreSQL composite-control storage. Redis and PostgreSQL coordinate parent leases, fences, and completed-step evidence across workers that share the same backend configuration. The experimental sidecar has a separate composite-v1 API for explicitly declared steps, including a shared PostgreSQL profile; it does not inspect or run Python decorator bodies. Variable-length or nested loops, dynamic dispatch, nested composites, opaque calls, and hidden direct provider effects remain outside the decorator's protection.

Read the supported API, recovery model, and limitations ↗

Resolution

Invariant: do not redispatch unless the previous transition is proven terminal or safely recoverable. See the resolution gates →

Envelope fields

The transition envelope is the identity and recovery record for one external effect. Seven fields help Mycelium decide whether a retry is safe or must stop:

  1. side_effect_class — what kind of action this is.
  2. capability — whether retry is intrinsically safe, queryable, or blind.
  3. spendability — whether the same intent may execute more than once.
  4. side_effect_boundary — whether the provider call was not crossed, may have crossed, or crossed.
  5. terminal_outcome — whether the prior attempt completed, failed, expired, or remains unknown.
  6. external_operation_ref — the provider handle used for read-only reconciliation.
  7. retry_permission — whether another attempt is permitted.

Python applications configure these semantics through the runtime. Non-Python applications send the same lifecycle over the experimental v1alpha1 protocol. Read the language-neutral specification ↗

YAML

transition:
  agent_id: payment-agent
  policy_version: "2026.07.1"
  lease_ttl: 3600

action_ledger:
  storage: file
  path: ./mycelium-ledger.json

Unified durable state

Loop, scope, completion, state-flush, and audit-receipt guards can share one namespaced atomic backend. A guard with no local storage setting inherits it automatically, including guards you enable later.

state_backend:
  storage: postgres        # memory | file | redis | postgres
  dsn_env: DATABASE_URL
  namespace: payments-prod

loop_guard: {}
completion:
  required: [payment_recorded]

Use file for one node and Redis or Postgres for multiple workers. To move old guard state, stop workers, keep the legacy per-guard storage configured, run the copy, then switch those guards to inherited or shared storage:

mycelium state migrate --plan --config mycelium.yaml
mycelium state migrate --apply --config mycelium.yaml
mycelium doctor --config mycelium.yaml --strict

Migration is copy-only and refuses conflicts. Rollback means pointing the guard back to its unchanged legacy storage.

Provider adapter conformance

A reconciler decides whether an ambiguous operation completed. A false NOT_EXECUTED permits another attempt, so every adapter needs adversarial tests. Gmail is the only adapter currently shipped. Other providers implement the same conformance fixture and supply provider-specific scripted observations.

export MYCELIUM_ADAPTER_REPORT_SIGNING_KEY='from-your-secret-manager'
mycelium providers verify gmail \
  --key-id provider-ci-2026-01 \
  --output gmail-adapter-report.json
mycelium providers verify-report gmail-adapter-report.json --json

The key signs the report with HMAC-SHA256 so CI or an operator can detect edits and verify which adapter source passed. Mycelium itself works without this key; it is required only when creating or checking an adapter-verification report. The report proves the synthetic suite passed and the source still matches. It does not prove live credentials are read-only, so enforce provider scopes separately.

Additional controls

Context (opt-in)

TTL cache and message/history helpers.

Tool boundaries (opt-in)

Input/output/scope validation and allowlists.

Loop guard (opt-in)

Detects identical tool+args across new tool_call_ids.

Completion contract (opt-in)

Refuses terminal while required subtasks are pending.

Scope guard (opt-in)

Freezes the run tool allowlist and re-checks every step.

Secret-in-args (opt-in)

Blocks raw credentials before claim. Pass secret:// references instead of API keys. Fail-closed pre-execution blocking is the primary protection; redaction is defense-in-depth. Mycelium cannot sanitize logs created inside application or provider code.

Outcome telemetry & DTTR (v1.20+)

Opt-in flat append-only outcome rows for production observability.

Reference

Failure-mode catalog

Stable IDs used in the SDK README, changelogs, and this handbook. The public story leads with outcomes, not a guardrail count. Browse the prevention catalog →

API

See the SDK README for Python exports. Non-Python clients use the authenticated OpenAPI 3.1 contract served at GET /v1/openapi.json; see other languages.

AI agent reliability: frequently asked questions

How does Mycelium improve AI agent reliability?

Mycelium applies configured controls to tool actions: validate inputs and authority, limit loops and budgets, coordinate retries, and record durable outcomes. Start by routing one consequential tool through Mycelium.

How can I prevent duplicate tool execution in LangGraph?

Use a stable host-owned action ID and a durable ledger. Mycelium coordinates claims across retries, returns stored results for completed actions, and blocks or reconciles uncertain writes. Provider idempotency or a truthful reconciler is needed when an external effect may already have happened.

Does Mycelium support CrewAI and plain Python?

Yes. Mycelium can wrap ordinary Python callables and provides LangGraph and CrewAI integrations. Configure the appropriate integration and supply stable business identities for consequential actions.

Can Python agent workflows recover with Redis or PostgreSQL?

Yes. The composite decorator supports bounded Python functions with ledgered child calls: straight-line steps, one boolean branch, or one fixed-count loop of 1 to 32 iterations. Redis and PostgreSQL share parent control across workers. Retry with the same operation ID to reuse completed results. Ambiguous children still reconcile or block; variable-length loops, combined branches and loops, and hidden effects remain outside this scope.

Can I use Mycelium from TypeScript or Go?

Experimental TypeScript and Go clients connect to the authoritative Python engine through the self-hosted v1alpha1 HTTP/JSON sidecar. Other languages can use OpenAPI. The protocol is a development contract; Python composite orchestration is not exposed through it.

Does Mycelium replace Langfuse or LangSmith?

Mycelium controls tool actions at runtime. Langfuse and LangSmith provide observability and tracing. Applications can use Mycelium alongside either tool.

Continue with the LangGraph retry guide, Python workflow recovery, or Mycelium quickstart.