Hypha CLI Reference

Philosophy

Hypha: “A bio-digital extension for Agents to release and absorb Spores”

Hypha is not a “tool” — it is the biological extension through which Agents interact with the network. All commands represent life activities, not technical operations.

Lifecycle Perspective

┌─────────────────────────────────────────────────────────────────┐
│                       Consuming Flow                            │
├─────────────────────────────────────────────────────────────────┤
│  sense ──→ taste ──→ spawn ──→ bond ──→ grow ──→ absorb            │
│    ↓         ↓         ↓          ↓            ↓         ↓      │
│  View     Evaluate   Create     Fetch        Update    Merge    │
│  metadata  safety    working    refs         from      other    │
│                      copy                    source    branches  │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│                       Releasing Flow                            │
├─────────────────────────────────────────────────────────────────┤
│  hatch ──→ replicate ──→ release ──→ mycelium pulse              │
│    ↓           ↓            ↓              ↓                    │
│  Prepare    Replicate    Sign &        Notify                   │
│  metadata   ext. refs    publish       indexer                  │
└─────────────────────────────────────────────────────────────────┘

Command Concepts

CommandBiological ConceptTechnical Implementation
sensePerceive spores in environmentResolve URI, fetch metadata
tasteTest before consumingFetch to cache for agent review, record safety verdict
spawnSpore germinates, takes rootCreate working copy (taste gate)
bondForm mycorrhizal connectionsFetch all bonds to .cmn/bonds/ (taste gate)
hatch bondManage mycorrhizal connectionsAdd/remove/clear bonds in spore.core.json
hatch treeConfigure growth patternSet tree algorithm, exclude names, follow rules
growHyphae extend toward sourceSync from spawned_from source (taste gate)
absorbAbsorb nutrients from other hyphaeAI-assisted merge (taste gate)
hatchSpore forms withinCreate spore.core.json
replicateDNA replication — exact copyCopy spore to your domain (same hash, re-sign capsule)
releaseSpore released to environmentSign & publish to mycelium
lineageTrace life origins & observe evolutionary treeQuery bond graph (–direction in|out)
searchSense spores by affinitySemantic search via Synapse
synapseManage sensory connectionsConfigure Synapse node connections

Response Structure

Hypha emits a stdout JSONL event stream. The final result/error event uses this top-level JSON structure (Agent-First Data protocol):

{
  "code": "ok" | "error",
  "trace": { ... },
  "result": { ... },
  "error": "message"
}
FieldPresenceDescription
codeAlways"ok" or "error"
traceOptionalInternal resolution state — shows how far the operation got (aids debugging)
resultSuccess onlyCommand-specific result payload
errorError onlyHuman-readable error message (string). Error codes appear in trace.error_code.

The trace field is progressively filled as the operation proceeds. For visitor pipeline commands (sense/taste/spawn/grow/absorb), it contains:

{
  "uri": "cmn://domain/hash",
  "cmn": { "resolved": true, "public_key": "..." },
  "verified": true
}

When an error occurs, trace shows which stages completed successfully before the failure. For release, it contains {"status": "released"|"skipped", "site": "..."}. Commands without a resolution pipeline omit the trace field.

Design Rules

  1. Agent First: Default output is JSON for machine-readability
  2. Structured Output: Default output is valid JSONL (one JSON object per line)
  3. Error Handling: Errors return "code": "error" with a human-readable error string and trace.error_code for LLM self-correction
  4. No Panics: All errors are handled gracefully; never crashes unexpectedly

Output Modes

ModeFlagOutput stream
JSON (default)-o jsonCompact JSONL via agent_first_data::output_json
Plain-o plainlogfmt-style output via agent_first_data::output_plain
YAML-o yamlYAML via agent_first_data::output_yaml

All runtime protocol events are emitted on stdout (not stderr), including startup, progress, warnings, success, and errors. Output is event-stream style: startup (code=log event=startup) can appear before the final line (code=ok or code=error).

Global Options

hypha [OPTIONS] <COMMAND>

Options:
  -o, --output <FORMAT>              Output format: json | plain | yaml (default: json)
  -h, --help                         Print help
  -V, --version                      Print version

All commands that place code into your working directory (spawn, grow, absorb, bond) require the target spore to have been tasted. Bond management (hatch bond set/remove/clear) and tree configuration (hatch tree set/show) modify spore.core.json and do not require tasting. toxic verdicts block, rotten warns then proceeds, all others (safe, fresh, sweet) proceed normally. (taste itself downloads to the global cache for review — the cache is not gated.)


1. Spore Lifecycle Commands

sense - View Spore Metadata

hypha sense <URI>

Action: Resolves CMN URI and displays spore metadata without downloading

Verification (reported in trace field):

Output:

{
  "code": "ok",
  "trace": {
    "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "cmn": {
      "resolved": true, "cached": false, "cached_at": null,
      "public_key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4"
    },
    "verified": { "core_signature": true, "capsule_signature": true }
  },
  "result": {
    "spore": {
      "$schema": "https://cmn.dev/schemas/v1/spore.json",
      "capsule": {
        "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
        "core": {
          "name": "CMN Protocol Specification",
          "domain": "cmn.dev",
          "synopsis": "Code Mycelial Network - A sovereign-first protocol for code distribution",
          "intent": ["spec simplification and strict domain validation"],
          "license": "CC0-1.0",
          "mutations": [
            "§05 URI: remove regex and pseudocode, use prose parsing steps",
            "§05 URI §6: domain must be lowercase RFC 1123, reject uppercase instead of normalizing"
          ],
          "bonds": [
            {
              "uri": "cmn://cmn.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
              "relation": "spawned_from"
            }
          ],
          "tree": { "algorithm": "blob_tree_blake3_nfc", "exclude_names": [".git"], "follow_rules": [".gitignore"] }
        },
        "core_signature": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4...",
        "dist": [
          {
            "type": "archive",
            "filename": "cmn-spec.tar.zst"
          }
        ]
      },
      "capsule_signature": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4..."
    }
  }
}

taste - Evaluate Before Use

# Step 1: Fetch to cache and output paths for agent review
hypha taste <URI>

# Step 2: Record verdict after agent analysis
hypha taste <URI> --verdict <sweet|fresh|safe|rotten|toxic> [--notes "..."]

# Optional: Pull others' taste reports from Synapse
hypha taste <URI> --synapse <URL>

# Optional: Share your report (requires domain with signing key)
hypha taste <URI> --verdict safe --domain <DOMAIN> --synapse <URL>

Arguments:

Options:

OptionDescription
--verdict <VERDICT>Record verdict: sweet, fresh, safe, rotten, or toxic
--notes <TEXT>Optional notes explaining the verdict
--synapse <URL>Pull others’ taste reports for reference
--domain <DOMAIN>Sign and share your report (requires domain key)

Verdicts (5-level taste scale):

VerdictMeaningEffect
sweetUsed it, it’s great — personal endorsementProceed normally
freshReviewed thoroughly, no issues foundProceed normally
safeQuick scan, nothing obviously wrongProceed normally
rottenUnusable — broken, won’t compile, fundamentally flawedProceed with warning
toxicConfirmed dangerous (malware, data theft, backdoor)Blocked
(none)Not yet tastedBlocked (NOT_TASTED)

Step 1 — Fetch and prepare for review (no --verdict flag):

Fetches the spore (and its parent, if a spawned_from reference exists) to the local cache, then outputs the paths for agent review.

{
  "code": "ok",
  "result": {
    "uri": "cmn://fork.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "cache_path": "/home/user/.cmn/hypha/cache/fork.dev/spore/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/content",
    "parent": {
      "uri": "cmn://origin.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
      "cache_path": "/home/user/.cmn/hypha/cache/origin.dev/spore/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5/content"
    },
    "taste": null,
    "others_tastes": []
  }
}

The agent reads the code at cache_path (and optionally compares with parent.cache_path), then proceeds to record a verdict.

Step 2 — Record verdict (with --verdict flag):

{
  "code": "ok",
  "result": {
    "uri": "cmn://fork.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "taste": "safe",
    "notes": "Reviewed changes: minor bug fix, no security concerns",
    "shared": false
  }
}

When --domain and --synapse are provided, the report is signed and submitted via POST /synapse/pulse, and shared is true.

Pulling others’ reports (with --synapse, no --verdict):

{
  "code": "ok",
  "result": {
    "uri": "cmn://fork.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "cache_path": "/home/user/.cmn/hypha/cache/fork.dev/spore/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/content",
    "parent": { ... },
    "taste": null,
    "others_tastes": [
      { "domain": "alice.dev", "taste": "safe", "notes": "Clean fork, tests pass" },
      { "domain": "bob.dev", "taste": "rotten", "notes": "Tests fail on ARM" }
    ]
  }
}

Others’ reports are reference data — the agent’s own judgment is authoritative.

spawn - Create Working Copy

hypha spawn <URI> [DIRECTORY] [--vcs <TYPE>] [--dist <SOURCE>] [--bond]

Arguments:

Options:

OptionDescription
--vcs <TYPE>Initialize version control (e.g., --vcs git)
--dist <SOURCE>Preferred distribution: archive (default) or git
--bondAfter spawn, run bond to fetch all tasted bonds to .cmn/bonds/

Action: Creates a working copy. Default: archive source, no VCS.

Archive source workflow (default):

  1. Verify spore signature
  2. Download and extract archive
  3. If --vcs git: initialize git repo with initial commit
  4. Add spawned_from reference to spore.core.json

Git source workflow (--dist git):

  1. Verify spore signature
  2. Clone to cache bare repo (or use existing)
  3. Clone from cache to target directory
  4. If --vcs git: keep .git, set up remotes; otherwise remove .git
  5. Add spawned_from reference to spore.core.json

Examples:

hypha spawn cmn://cmn.dev/b3....                  # archive, no VCS
hypha spawn cmn://cmn.dev/b3.... --vcs git         # archive + git init
hypha spawn cmn://cmn.dev/b3.... --dist git        # git source, no VCS
hypha spawn cmn://cmn.dev/b3.... --dist git --vcs git  # git source + keep .git

Output:

{
  "code": "ok",
  "result": {
    "uri": "cmn://cmn.dev/b3....",
    "name": "CMN Protocol Specification",
    "path": "/home/user/projects/cmn-spec",
    "source_type": "archive",
    "vcs": null
  }
}

grow - Update from Source

hypha grow [--synapse <DOMAIN|URL>] [--synapse-token-secret <TOKEN>] [--dist <SOURCE>] [--bond] [--discard-local-changes]

Options:

OptionDescription
--synapse <DOMAIN|URL>Synapse to query for updates (domain or URL; default: configured default)
--synapse-token-secret <TOKEN>Auth token for synapse (overrides configured token)
--dist <SOURCE>Override distribution source: archive or git
--bondAfter grow, run bond to refresh .cmn/bonds/ (bonds may have changed)
--discard-local-changesSkip local modification check for archive grow (when no VCS is present)

Action: Pulls latest changes using Synapse lineage discovery (run in spawned directory)

Requirements:

Update discovery (8-step flow with Agent-First Data progress):

  1. RESOLVE — Read ./spore.core.json, extract spawned_from URI (domain + hash)
  2. SYNAPSE — Resolve synapse endpoint (falls back to mycelium chain-following if no synapse configured)
  3. LINEAGE — Query Synapse for newer versions on the same domain, follow chain to tip
  4. VERIFY — Fetch & verify new spore from source site (cmn.json → manifest → signatures)
  5. TASTE — Check taste verdict for new hash (blocks if toxic)
  6. RESOLVE_DIST — Determine update method (respects --dist; else: git if .git exists and manifest has git dist; else archive with delta)
  7. APPLY — Download & apply update (git: fetch + checkout; archive: download + replace files)
  8. COMPLETE — Report result with old/new hash

Output:

{
  "code": "ok",
  "result": {
    "uri": "cmn://cmn.dev/b3....",
    "old_hash": "b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "new_hash": "b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
    "method": "git",
    "path": "/home/user/projects/cmn-spec"
  }
}

absorb - Prepare for AI Merge

hypha absorb <URI>... [--discover] [-s <DOMAIN|URL>] [--max-depth <N>]

Arguments:

Options:

Action: Prepares code from spores for AI-assisted merging

Files created:

Output:

{
  "code": "ok",
  "result": {
    "sources": [
      { "uri": "cmn://...", "hash": "b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "path": ".cmn/absorb/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/" }
    ],
    "prompt_path": ".cmn/absorb/ABSORB.md"
  }
}

bond - Fetch Bonds

hypha bond [--clean] [--status]

Options:

OptionDescription
--cleanRemove orphaned bonds not in spore.core.json
--statusShow bond status without fetching

Action: Reads spore.core.json bonds and fetches tasted bonded spores to .cmn/bonds/. Excludes spawned_from (handled by grow) and absorbed_from (historical — merge already done). toxic spores are blocked, rotten spores warn then proceed, untasted spores are blocked.

Requirements:

When to use:

Directory structure created:

.cmn/
└── bonds/
    ├── bonds.json               ← index of all bonds
    ├── b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/           ← depends_on
    │   ├── spore.json
    │   └── content/
    └── b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5/           ← follows
        ├── spore.json
        └── content/

The bonds.json index maps hashes to URIs, relations, and names:

{
  "bonds": [
    { "hash": "b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "uri": "cmn://pub.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "relation": "depends_on", "name": "Spore B" }
  ]
}

For depends_on bonds, the publisher configures build system paths using the hash directory:

Output:

{
  "code": "ok",
  "result": {
    "bonded": [
      { "uri": "cmn://pub.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "relation": "depends_on", "status": "bonded" }
    ]
  }
}

Status output (--status):

{
  "code": "ok",
  "result": {
    "bonds": [
      { "uri": "cmn://origin.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "relation": "spawned_from", "bonded": "excluded" },
      { "uri": "cmn://pub.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2", "relation": "depends_on", "taste": "safe", "bonded": true },
      { "uri": "cmn://cmn.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5", "relation": "implements", "taste": "safe", "bonded": true },
      { "uri": "cmn://xyz.com/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5", "relation": "inspired_by", "taste": null, "bonded": false }
    ]
  }
}

hatch - Prepare Spore Metadata

hypha hatch [OPTIONS]

Options:

OptionDescription
--id <ID>URL-safe identifier (for paths)
--name <NAME>Display name
--domain <DOMAIN>Publisher domain
--synopsis <TEXT>Short description
--intent <TEXT>Why this release (repeatable, required for release)
--mutations <TEXT>What changed (repeatable)
--license <SPDX>License identifier (default: MIT)

Action: Creates a new spore.core.json or updates existing one. Use hypha hatch bond set/remove/clear to manage bonds and hypha hatch tree set/show to manage tree configuration.

Output:

{
  "code": "ok",
  "result": {
    "protocol": "cmn/1",
    "spore": {
      "id": "my-tool",
      "name": "My Tool",
      "synopsis": "A useful tool",
      "intent": ["v1.0"],
      "mutations": [],
      "license": "MIT",
      "tree": { "algorithm": "blob_tree_blake3_nfc", "exclude_names": [".git"], "follow_rules": [".gitignore"] }
    }
  }
}

hatch bond - Manage Bonds

hypha hatch bond set --uri <URI> --relation <RELATION> [--id ID] [--reason REASON] [--with KEY=VALUE]...
hypha hatch bond remove [--uri URI] [--relation RELATION]
hypha hatch bond clear

Subcommands:

SubcommandDescription
setAdd or update a bond (upsert by URI). --uri required. --relation required for new bonds, optional for updates. Only explicitly passed fields are overwritten. --with KEY=VALUE is repeatable and merges into existing with object. VALUE is parsed as JSON, falls back to string.
removeRemove bonds matching --uri and/or --relation. At least one filter required. When both are given, only bonds matching both are removed.
clearRemove all bonds

Examples:

# New bond (--relation required)
hypha hatch bond set --uri cmn://cmn.dev/b3.abc --relation follows --id my-lib --reason "Core library"

# Update only reason (relation/id/with preserved)
hypha hatch bond set --uri cmn://cmn.dev/b3.abc --reason "Updated reason"

# Add with parameters (merges into existing with)
hypha hatch bond set --uri cmn://cmn.dev/b3.abc --with 'mints=["https://mint.example.com"]' --with unit=sat

# Remove
hypha hatch bond remove --relation follows
hypha hatch bond remove --uri cmn://cmn.dev/b3.abc
hypha hatch bond remove --uri cmn://cmn.dev/b3.abc --relation follows
hypha hatch bond clear

hatch tree - Manage Tree Configuration

hypha hatch tree set [--algorithm <ALG>] [--exclude-names <NAME>...] [--follow-rules <FILE>...]
hypha hatch tree show

Subcommands:

SubcommandDescription
setSet tree configuration fields. Only provided fields are overwritten.
showShow current tree configuration.

Examples:

# Set exclude names
hypha hatch tree set --exclude-names .git node_modules

# Set follow rules
hypha hatch tree set --follow-rules .gitignore .npmignore

# Set algorithm
hypha hatch tree set --algorithm blob_tree_blake3_nfc

# Show current tree config
hypha hatch tree show

release - Sign and Publish

hypha release --domain <DOMAIN> [OPTIONS]

Required:

Options:

OptionDescription
--source <PATH>Spore source directory (default: current)
--site-path <PATH>Custom site directory
--dist-git <URL>External git repository URL
--dist-ref <REF>Git ref: tag/branch/commit
--archive <FORMAT>Archive format for release generation (currently only zstd)
--dry-runPre-compute URI without writing any files

Action:

  1. Validates spore.core.json structure
  2. Computes content hash (BLAKE3)
  3. Verifies private key permissions (must be 0600)
  4. Signs manifest with private key
  5. Copies files to site’s public/ directory
  6. Updates cmn.json and mycelium.json

Output:

{
  "code": "ok",
  "result": {
    "protocol": "cmn/1",
    "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "spore": { ... },
    "signature": "ed25519...."
  }
}

replicate - Copy Spore to Your Domain

hypha replicate <URI> --domain <DOMAIN> [--bonds]

Arguments:

Required:

Options:

OptionDescription
--bondsReplicate all non-self bonds from spore.core.json and update URIs

Action: Creates an exact copy of a spore on your domain (same hash, same core, same core_signature). Only the dist and capsule_signature change — the capsule is re-signed with your domain’s key.

This is a publisher command — requires a mycelium site (hypha mycelium root).

Steps:

  1. Fetch original spore.json (preserve core + core_signature)
  2. Download content (archive)
  3. Copy archive to your site’s public/ directory
  4. Create new dist entry pointing to your domain
  5. Re-sign capsule with your key → new capsule_signature
  6. Add spore to your mycelium.json

Single spore:

hypha replicate cmn://other.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2 --domain mydomain.com

All non-self bonds (--bonds):

# In a project directory with spore.core.json
hypha replicate --bonds --domain mydomain.com

Reads spore.core.json, finds all bonds pointing to other domains, replicates each one to mydomain.com, and updates bond URIs:

Before: depends_on → cmn://other.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2
After:  depends_on → cmn://mydomain.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2  (same hash)

Output:

{
  "code": "ok",
  "result": {
    "replicated": [
      {
        "original": "cmn://other.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
        "replicate": "cmn://mydomain.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
        "core_domain": "other.com"
      }
    ]
  }
}

Verification by visitors:


2. Discovery Commands

lineage - Trace Spore Lineage

hypha lineage <URI> [--direction in|out] [-s <DOMAIN|URL>] [--max-depth <N>]

Action: Traces spore lineage via Synapse. --direction in (default) finds descendants (forks/evolutions). --direction out traces ancestors (spawn chain).

The -s/--synapse flag accepts a configured domain or a URL. If omitted, uses the default from hypha synapse use.

Output:

{
  "code": "ok",
  "result": {
    "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "synapse": "https://synapse.cmn.network",
    "direction": "inbound",
    "count": 5,
    "bonds": [
      { "uri": "cmn://fork1.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5", "relation": "spawned_from" }
    ]
  }
}

search - Find Spores by Keyword

hypha search <QUERY> [-s <DOMAIN|URL>] [--domain <DOMAIN>] [--license <SPDX>] [--bonds <RELATION:URI>] [--limit <N>]

Arguments:

Options:

OptionDescription
--synapse <NAME|URL>Synapse server — domain or URL (default: configured default)
--domain <DOMAIN>Filter results by domain
--license <SPDX>Filter results by license (SPDX identifier)
--bonds <RELATION:URI>Filter by bond relationship. Format: relation:uri. Comma-separated for AND logic (e.g. spawned_from:cmn://a.dev/hash,follows:cmn://b.dev/hash).
--limit <N>Maximum results (default: 20)

Action: Performs semantic search over indexed spore metadata via Synapse’s /synapse/search endpoint

Examples:

hypha search "HTTP client library" --synapse https://synapse.cmn.dev
hypha search "database" --synapse https://synapse.cmn.dev --domain cmn.dev --limit 5
hypha search "crypto" --synapse https://synapse.cmn.dev --license MIT
hypha search "http client" --bonds spawned_from:cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2

Output:

{
  "code": "ok",
  "result": {
    "query": "HTTP client library",
    "synapse": "https://synapse.cmn.dev",
    "domain": null,
    "license": null,
    "bonds": null,
    "count": 3,
    "results": [
      {
        "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
        "domain": "cmn.dev",
        "name": "reqwest-lite",
        "synopsis": "Lightweight HTTP client for Rust",
        "license": "MIT",
        "intent": ["initial release"],
        "score": 0.92
      },
      {
        "uri": "cmn://tools.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
        "domain": "tools.dev",
        "name": "curl-wrapper",
        "synopsis": "Ergonomic curl wrapper",
        "license": "Apache-2.0",
        "intent": ["v2 rewrite"],
        "score": 0.85
      }
    ]
  }
}

Error when search is not configured:

{
  "code": "error",
  "error": "Search engine not configured on this synapse instance",
  "trace": {
    "error_code": "SYNAPSE_ERR"
  }
}

3. Mycelium Infrastructure

mycelium root - Establish Site

hypha mycelium root <DOMAIN> [--site-path <PATH>] [--endpoints-base <URL>]

Action: Establishes a new site with Ed25519 keypair (or updates existing)

Creates:

Output:

{
  "code": "ok",
  "result": {
    "domain": "example.com",
    "public_key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
    "site_path": "/home/user/.cmn/mycelium/example.com"
  }
}

Key Management

By default, mycelium root creates a new keypair for each domain. This provides security isolation between domains.

However, a single keypair can be used for multiple domains. This is an operational choice, not a protocol requirement. To share keys:

# Initialize first domain (creates new keypair)
hypha mycelium root example.com

# Initialize second domain with shared keypair
hypha mycelium root other.com
cp ~/.cmn/mycelium/example.com/keys/private.pem ~/.cmn/mycelium/other.com/keys/
cp ~/.cmn/mycelium/example.com/keys/public.pem ~/.cmn/mycelium/other.com/keys/

# cmn.json for other.com will use the same public key

When to share keys:

When to use separate keys:

mycelium status - View Site Status

hypha mycelium status [DOMAIN] [--site-path <PATH>]

Action:

Output:

{
  "code": "ok",
  "result": {
    "domain": "example.com",
    "public_key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
    "site_path": "/home/user/.cmn/mycelium/example.com",
    "spore_count": 5
  }
}

mycelium serve - Local Server

hypha mycelium serve [DOMAIN] [--site-path <PATH>] [--port <PORT>]

Action: Starts a local HTTP server to serve the site (for debugging)

Options:

mycelium pulse - Notify Synapse

hypha mycelium pulse [-s <DOMAIN|URL>] --file <PATH>

Action: Sends a signed pulse to a Synapse indexer (POST /synapse/pulse)

Security:

Output:

{
  "code": "ok",
  "result": {
    "synapse": "https://synapse.cmn.network",
    "response": {
      "code": "ok",
      "message": "Indexed successfully"
    }
  }
}

4. Cache Management

cache list

hypha cache list

Lists all cached spores.

cache clean

hypha cache clean [--all]

Options:

cache path

hypha cache path <URI>

Shows local filesystem path for a cached spore.


5. Synapse Management

synapse add - Register a Node

hypha synapse add <URL>

Action: Registers a Synapse node. The domain is extracted from the URL and used as the identifier. Creates $CMN_HOME/hypha/synapse/<domain>/config.toml. If this is the first node, it becomes the default automatically.

Example: hypha synapse add https://synapse.cmn.dev → registers as synapse.cmn.dev

Output:

{
  "code": "ok",
  "result": {
    "domain": "synapse.cmn.dev",
    "url": "https://synapse.cmn.dev",
    "default": true
  }
}

synapse list - Show Configured Nodes

hypha synapse list

Action: Lists all configured Synapse nodes with default marker and token status.

Output:

{
  "code": "ok",
  "result": {
    "count": 2,
    "default": "synapse.cmn.dev",
    "nodes": [
      { "domain": "synapse.cmn.dev", "url": "https://synapse.cmn.dev", "has_token": false, "default": true },
      { "domain": "localhost", "url": "http://localhost:8080", "has_token": true, "default": false }
    ]
  }
}

synapse use - Set Default Node

hypha synapse use <DOMAIN>

Action: Sets the default Synapse node. All commands with -s/--synapse will use this node when no argument is given.

Example: hypha synapse use synapse.cmn.dev

synapse remove - Unregister a Node

hypha synapse remove <DOMAIN>

Action: Removes a Synapse node directory. Clears default if the removed node was the default.

synapse info - Query Instance Info

hypha synapse info [DOMAIN|URL]

Action: Calls GET /synapse/info on the Synapse instance and displays the self-description. Caches the response to $CMN_HOME/hypha/synapse/<domain>/info.json. Uses default node if no argument given.

Output:

{
  "code": "ok",
  "result": {
    "synapse": "https://synapse.cmn.dev",
    "info": {
      "name": "CMN Synapse",
      "indexed_spores": 12450,
      "features": ["search", "lineage", "rhizome", "pulse"],
      "payment": "free"
    }
  }
}

synapse config - Configure a Synapse Node

hypha synapse config <DOMAIN> [--token-secret <TOKEN>]

Action: Configures a Synapse node. Currently supports setting the auth token. When set, Hypha automatically includes Authorization: Bearer <token> in all requests to that node. Stored in $CMN_HOME/hypha/synapse/<domain>/config.toml (0600 permissions).

synapse discover - Find Other Instances

hypha synapse discover [-s <DOMAIN|URL>]

Action: Searches for other Synapse instances via GET /synapse/search?ref=follows:strain-synapse. Uses default node if no argument given.


6. Configuration Commands

config list - Show Current Configuration

hypha config list

Action: Shows the effective configuration (defaults merged with $CMN_HOME/hypha/config.toml). Reports the config file path and whether it exists.

{
  "code": "ok",
  "result": {
    "path": "/home/user/.cmn/hypha/config.toml",
    "exists": true,
    "config": {
      "defaults": { "synapse": "synapse.cmn.dev" },
      "cache": { "cmn_ttl_s": 300 }
    }
  }
}

config set - Set a Configuration Value

hypha config set <KEY> <VALUE>

Action: Sets a configuration value using dotted key notation. Creates config.toml if it doesn’t exist.

KeyTypeDescription
defaults.synapsestringDefault synapse domain
cache.pathstringCustom cache directory
cache.cmn_ttl_sintegercmn.json cache TTL in seconds (default: 300)
cache.key_trust_ttl_sintegerKey trust cache TTL in seconds (default: 604800)
cache.key_trust_refresh_modeenumKey trust refresh mode: expired, always, offline
cache.key_trust_synapse_witness_modeenumDomain-offline fallback: allow (use Synapse witness) or require_domain (no Synapse witness)
hypha config set defaults.synapse synapse.cmn.dev
hypha config set cache.cmn_ttl_s 600
hypha config set cache.key_trust_ttl_s 604800
hypha config set cache.key_trust_refresh_mode expired
hypha config set cache.key_trust_synapse_witness_mode require_domain
hypha config set cache.path /tmp/hypha-cache

7. System Commands

version

hypha -V

Shows version information.

help

hypha help [COMMAND]

Shows help information. Equivalent to --help.


8. Error Handling

Errors are emitted as structured JSON events in the stdout JSONL stream (Agent-First Data protocol):

{
  "code": "error",
  "error": "Site not found at /path/to/site",
  "trace": {
    "error_code": "NO_SITE"
  }
}

Pipeline Error Codes

These standardized codes correspond to stages in the visitor resolution pipeline (sense/taste/spawn/grow/absorb):

CodeStageDescription
INVALID_URIURI parseInvalid or malformed CMN URI
KEY_FETCH_FAILEDKey fetchcmn.json fetch or public key extraction failed
CMN_FAILEDcmn.jsoncmn.json endpoint extraction failed
MANIFEST_FAILEDManifestManifest fetch (mycelium or spore) failed
SIG_FAILEDVerificationSignature verification failed
HASH_MISMATCHHash checkContent hash doesn’t match URI
SPORE_NOT_FOUNDCatalogSpore not found in mycelium catalog
FETCH_FAILEDDownloadContent download (HTTPS/git) failed

Command-Specific Error Codes

CodeDescription
INIT_ERRFailed to initialize site
NO_SITESite not found
NO_SPOREspore.core.json not found
VALIDATION_ERRValidation failed
SIGN_ERRFailed to sign (publisher)
PARSE_ERRFailed to parse JSON
WRITE_ERRFailed to write file
DIR_EXISTSTarget directory exists
DIR_ERRDirectory creation failed
SPAWN_ERRSpawn operation failed (git/archive)
GROW_ERRGrow operation failed (local git/archive)
GIT_URL_CHANGEDGit repository URL changed since spawn
REPO_IDENTITY_ERRRepository root commit mismatch
ABSORB_ERRAbsorb operation failed (local)
BOND_ERRBond operation failed (fetch/extract bonds)
NOT_TASTEDSpore has not been tasted — run hypha taste first
ROTTEN_WARNSpore tasted as rotten — proceeding with warning
TOXICSpore tasted as toxic — blocked
SYNAPSE_ERRSynapse query failed
GIT_ERRGit operation failed (publisher)
LOCAL_MODIFIEDLocal files modified since spawn — archive grow blocked (use --discard-local-changes or git init)

Exit Codes


9. Configuration

Environment Variables

VariableDescriptionDefault
CMN_HOMEBase directory for all CMN data (keys, sites, config)~/.cmn
SYNAPSE_TOKEN_SECRETAuth token for Synapse requests. Overrides per-node config, overridden by --synapse-token-secret.unset

Configuration Files

FileDescription
$CMN_HOME/hypha/config.tomlHypha config (defaults, cache TTLs)
$CMN_HOME/hypha/synapse/<domain>/config.tomlPer-node synapse config (url, token_secret). Mode 0600.
$CMN_HOME/hypha/synapse/<domain>/info.jsonCached /synapse/info response

hypha/config.toml format:

[defaults]
synapse = "synapse.cmn.dev"

[cache]
# path = "/custom/cache/path"   # optional, default: $CMN_HOME/hypha/cache/
cmn_ttl_s = 300

synapse/<domain>/config.toml format:

url = "https://synapse.cmn.dev"
token_secret = "sk-abc123"   # optional

10. Directory Structure

Hypha Configuration

$CMN_HOME/hypha/
├── config.toml                  # Defaults and cache TTLs
└── synapse/
    ├── synapse.cmn.dev/
    │   ├── config.toml          # url, token_secret (mode 0600)
    │   └── info.json            # Cached /v1/info response
    └── localhost/
        └── config.toml

Mycelium Site

$CMN_HOME/mycelium/<domain>/
├── keys/
│   ├── private.pem       # Ed25519 private key (mode 0600)
│   └── public.pem        # Ed25519 public key
└── public/               # Deployable static files
    ├── .well-known/
    │   └── cmn.json      # Domain entry point (includes public key)
    └── cmn/
        ├── mycelium/
        ├── spore/
        └── archive/

Project Working Directory

my-project/
├── src/
├── spore.core.json          ← committed to git
├── .gitignore               ← includes .cmn/
└── .cmn/                    ← gitignored, fully regenerable
    ├── bonds/               ← bond: all bonded spores
    │   ├── bonds.json       ← index (hash, uri, relation, name)
    │   ├── b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/   ← organized by hash
    │   │   ├── spore.json
    │   │   └── content/
    │   └── b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5/
    │       ├── spore.json
    │       └── content/
    └── absorb/              ← absorb: temporary staging
        ├── ABSORB.md
        └── b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/
            ├── spore.json
            └── content/

The .cmn/ directory is derived from spore.core.json and the global cache. Delete it anytime — hypha bond rebuilds bonds/, and hypha absorb rebuilds absorb/.

Local Cache

Default: $CMN_HOME/hypha/cache/. Override with [cache] path in config.toml.

$CMN_HOME/hypha/cache/
└── <domain>/
    ├── mycelium/
    │   ├── cmn.json
    │   └── mycelium.json
    ├── spore/
    │   └── b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2/
    │       ├── spore.json
    │       └── content/
    └── repos/
        └── {root_commit}.git  # Bare repo cache

11. Security

Key Format

Keys are stored in standard PEM format:

Private Key Protection

Public Key Discovery

The domain’s public key is fetched from cmn.json over HTTPS:

https://cmn.dev/.well-known/cmn.json
→ { "capsule": { "public_key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4", ... }, ... }

TLS provides the authenticated channel that binds the public key to the domain. No DNS TXT records are required.