02. Mycelium - Domain Manifest

The Mycelium is a Site Descriptor. It represents a developer or organization and their published spores.

1. Overview

The domain entry point (cmn.json) is documented in 01-substrate.md. This document covers the full mycelium manifest that contains the complete site metadata.

Location: Defined by the type: "mycelium" endpoint in cmn.json (e.g., https://cmn.dev/cmn/mycelium/{hash}.json) Schema: https://cmn.dev/schemas/v1/mycelium.json Size: ~1-10 KB

{
  "$schema": "https://cmn.dev/schemas/v1/mycelium.json",
  "capsule": {
    "uri": "cmn://cmn.dev/mycelium/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "core": {
      "domain": "cmn.dev",
      "key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
      "name": "cmn.dev",
      "synopsis": "",
      "updated_at_epoch_ms": 1769777183174,
      "spores": [
        {
          "id": "cmn-spec",
          "hash": "b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
          "name": "CMN Protocol Specification",
          "synopsis": "Code Mycelial Network - A sovereign-first protocol for code distribution"
        },
        {
          "id": "cmn-tools",
          "hash": "b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
          "name": "CMN Tools",
          "synopsis": "Command-line and service tooling for the CMN protocol"
        }
      ]
    },
    "core_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
  },
  "capsule_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
}

Note: Content endpoints (spore, archive, taste) are defined in the cmn.json endpoint array, not in the mycelium manifest. See 01-substrate §1.2.1.

2. Field Definitions

2.1 Mycelium Fields

FieldTypeDescription
$schemaStringSchema URL: https://cmn.dev/schemas/v1/mycelium.json
capsuleObjectThe capsule container.
capsule.uriStringMycelium URI: cmn://{domain}/mycelium/{hash}
capsule.coreObjectThe mycelium content.
capsule.core.nameStringDeveloper or organization name.
capsule.core.domainStringThe domain (e.g., cmn.dev).
capsule.core.keyStringEd25519 public key of the content author. Enables offline signature verification once the key-domain binding is already trusted, without fetching cmn.json.
capsule.core.synopsisStringBrief description of the developer/org.
capsule.core.bioString?Multiline markdown with full details about this domain.
capsule.core.nutrientsArray?Nutrient methods, ordered by preference (first = preferred). Omit if none. See §2.3.
capsule.core.updated_at_epoch_msNumberUnix timestamp in milliseconds. Used for version ordering.
capsule.core.sporesArray?List of published spores. Omit if the domain has not published any spores yet.
capsule.core.tastesArray?Published taste reports ({hash, target_uri}) for mirror discovery and re-submission. Omit if none.
capsule.core_signatureStringEd25519 signature of the core object (ed25519.<base58>, JCS canonical).
capsule_signatureStringEd25519 signature of the capsule object (ed25519.<base58>, JCS canonical).

2.2 Spore Entry

FieldTypeDescription
idStringStable identifier for the spore (e.g., cmn-tools). Used for deduplication across releases. Required.
hashStringBLAKE3 hash with prefix (e.g., b3.3yMR7vZQ9hL2x...). Required.
nameStringHuman-readable name of the spore. Required.
synopsisString?Optional short description.

Note: Spore entries use hash instead of full uri to keep the file size small. Clients can construct the full URI as cmn://{domain}/{hash}. The id field matches the id in spore.core.json and ensures that re-releasing a spore replaces the previous entry rather than appending a duplicate.

2.3 Nutrients

Optional array of nutrient methods, ordered by preference (first entry = preferred). Each entry is a typed method object with type as the only required field. All entries MAY include label for UI display.

{
  "nutrients": [
    {"type": "lightning", "address": "user@example.com"},
    {"type": "lightning", "offer": "lno1qgsq..."},
    {"type": "onchain_btc", "address": "bc1q..."},
    {"type": "evm", "chain_id": 8453, "token": "native", "recipient": "0x1a2b..."},
    {"type": "webpage", "url": "https://github.com/sponsors/alice", "label": "GitHub Sponsors"}
  ]
}

Nutrient types align with strain-payment-method-* conventions. Each type below corresponds to a strain (e.g., lightningstrain-payment-method-lightning), and field names match the strain’s payment request fields where applicable.

The base mycelium.json schema only requires type for nutrient entries. Type-specific required fields below are convention-level requirements enforced by corresponding strain-payment-method-* conventions and tooling.

Direct payment types — static addresses for voluntary donations:

TypeRequired FieldsOptional FieldsDescription
lightningaddress or offerLightning address (user@domain, compatible with Nostr zaps) or BOLT12 offer (lno1...). One entry per form.
onchain_btcaddressBitcoin L1 address.
liquidaddressasset_idLiquid sidechain address.
evmchain_id, recipienttokenEthereum or L2 (Arbitrum, Base, Optimism, etc.). token: ERC-20 contract address or "native" (default).
solanarecipienttokenSolana address. token: SPL mint address or "native" (default).
moneroaddressMonero address.

Webpage type — any nutrient page, platform profile, or checkout:

TypeRequired FieldsDescription
webpageurlHuman-facing payment page (GitHub Sponsors, Open Collective, Polar.sh, etc.).

The type field is an open string — any value is valid. New payment networks require no protocol update.

Design notes:

3. Schema Validation

Schema URL: https://cmn.dev/schemas/v1/mycelium.json

Validators SHOULD embed schemas for offline validation. No network fetch should be required.

4. Signing and Hashing

4.1 Core Signature

The core_signature signs the core object:

  1. Serialize core using JCS (RFC 8785)
  2. Sign the canonical bytes with Ed25519 private key
  3. Format as ed25519.<base58>

Purpose:

4.2 Content Hash Calculation

The hash in capsule.uri is calculated from core + core_signature:

  1. Construct hash input: {"core": <core>, "core_signature": "<signature>"}
  2. Serialize hash input using JCS
  3. Hash with BLAKE3 → b3.<base58>
  4. The mycelium URI is cmn://{domain}/mycelium/{hash} (the hash is also stored in cmn.json as an element of the hashes array on the type: "mycelium" endpoint for change detection)

Key Properties:

4.3 Capsule Signature

The capsule_signature signs the entire capsule object (including uri):

  1. Build capsule: {"uri": <uri>, "core": <core>, "core_signature": "<signature>"}
  2. Serialize using JCS
  3. Sign with Ed25519 private key → ed25519.<base58>

Purpose:

4.4 Canonical JSON (JCS)

All signatures and hashes use JCS (see 01-substrate §1.3).

5. Publishing Workflow

Publishing implementations MUST:

  1. Build the core object
  2. Sign core → core_signature
  3. Compute hash from core + core_signature
  4. Construct uri with hash: cmn://{domain}/mycelium/{hash}
  5. Build capsule with uri, core, core_signature
  6. Sign capsule → capsule_signature
  7. Save full mycelium to /cmn/mycelium/{hash}.json
  8. Generate cmn.json capsule entry with endpoints (including type: "mycelium" with hashes array)
  9. Sign cmn.json capsules array → capsule_signature
  10. Save to cmn.json

6. File Organization

site_root/
├── .well-known/
│   └── cmn.json                                          # Domain entry point (~150 bytes)
└── cmn/
    └── mycelium/
        └── b3.3yMR7vZQ9hL2x...pTa2.json                  # Current version

Benefits:

7. Content Resolution

7.1 Hash Lookup and Sharding

The mycelium endpoint in cmn.json carries a hashes array. Each hash points to a mycelium shard. Most domains use a single shard.

Shard rules:

7.2 Mycelium Resolution

When fetching the full mycelium content:

Find the type: "mycelium" endpoint in capsules[0].endpoints:

If endpoints are missing, return an error - there are no default fallback URLs.

7.3 Spore Resolution

When a client needs to fetch a specific spore:

Find the type: "spore" endpoint in capsules[0].endpoints:

Resolution flow: cmn.json → find type: "spore" endpoint → fetch spore.

If endpoints are missing, return an error. Synapse is only a fallback when the domain is unreachable, not a default endpoint.

Static Deployment: This design allows static file hosting without any server-side logic.

8. Pulse (Publishing Updates)

When mycelium is updated, publishing tools MUST regenerate both the capsule and full mycelium files.

Optional notification:

Publishing implementations MAY send a Pulse notification to one or more Synapse nodes (see 05-strain §5.2).

Synapse Validation:

  1. Schema Validation: Validate against embedded schema
  2. Signature Verification: Verify core_signature and capsule_signature against the domain’s public key
  3. Version Check: Compare updated_at_epoch_ms with cached version
    • new > cached → Accept (newer version)
    • new == cached, same hash → Ignore (duplicate)
    • new == cached, different hash → Reject (conflict — publisher MUST increment timestamp to correct)
    • new < cachedReject (older version)

Content Correction: If a publisher needs to fix a mistake (e.g., typo in synopsis, wrong spore entry), they MUST increment updated_at_epoch_ms before re-signing and re-publishing. This produces a new hash and a newer timestamp, which a Synapse node can accept as an ordinary update. The monotonic timestamp requirement ensures that corrections are unambiguous and prevents conflicting edits.

Protection Against:

9. Example

Entry Point (cmn.json):

{
  "$schema": "https://cmn.dev/schemas/v1/cmn.json",
  "capsules": [
    {
      "uri": "cmn://cmn.dev",
      "key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
      "endpoints": [
        {"type": "mycelium", "url": "https://cmn.dev/cmn/mycelium/{hash}.json", "hashes": ["b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"]},
        {"type": "spore",    "url": "https://cmn.dev/cmn/spore/{hash}.json"},
        {"type": "archive",  "url": "https://cmn.dev/cmn/archive/{hash}.tar.zst", "format": "tar+zstd"},
        {"type": "taste",    "url": "https://cmn.dev/cmn/taste/{hash}.json"}
      ]
    }
  ],
  "capsule_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
}

Client resolution: Find the type: "mycelium" endpoint, iterate its hashes array, replace {hash} in the url template for each → fetch each mycelium shard.

Full (/cmn/mycelium/b3.3yMR7vZQ9hL2x...pTa2.json):

{
  "$schema": "https://cmn.dev/schemas/v1/mycelium.json",
  "capsule": {
    "uri": "cmn://cmn.dev/mycelium/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "core": {
      "domain": "cmn.dev",
      "key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
      "name": "cmn.dev",
      "synopsis": "",
      "updated_at_epoch_ms": 1769777183174,
      "spores": [
        {
          "id": "cmn-spec",
          "hash": "b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
          "name": "CMN Protocol Specification",
          "synopsis": "Code Mycelial Network - A sovereign-first protocol for code distribution"
        },
        {
          "id": "cmn-tools",
          "hash": "b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
          "name": "CMN Tools",
          "synopsis": "Command-line and service tooling for the CMN protocol"
        }
      ]
    },
    "core_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
  },
  "capsule_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
}