03. Spore - Package Format

The Spore is a Logic Capsule. It relies on its URI for identity and carries the logic DNA.

Location: Defined by capsules[].endpoints.spore in cmn.json (e.g., https://cmn.dev/cmn/spore/{hash}.json) Schema: https://cmn.dev/schemas/v1/spore.json

1. The spore.json Manifest

{
  "$schema": "https://cmn.dev/schemas/v1/spore.json",
  "capsule": {
    "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "core": {
      "id": "cmn-spec",
      "name": "CMN Protocol Specification",
      "domain": "cmn.dev",
      "key": "ed25519.5XmkQ9vZP8nL3xJdFtR7wNcA6sY2bKgU1eH9pXb4",
      "synopsis": "Code Mycelial Network - A sovereign-first protocol for code distribution",
      "intent": ["add intent and changes array fields to spore core"],
      "license": "CC0-1.0",
      "mutations": [
        "§2.2 Core Fields: intent type String → Array",
        "§2.2 Core Fields: add mutations field (Array)",
        "§2.4 Bond Types: add optional reason field",
        "§1, §4.1, §6 example JSON updated"
      ],
      "bonds": [],
      "tree": {
        "algorithm": "blob_tree_blake3_nfc",
        "exclude_names": [".git"],
        "follow_rules": [".gitignore"]
      },
      "updated_at_epoch_ms": 1700000000000
    },
    "core_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "dist": [
      {
        "type": "archive",
        "filename": "cmn-spec.tar.zst"
      }
    ]
  },
  "capsule_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2"
}

2. Field Definitions

2.1 Common Fields

FieldTypeDescription
$schemaStringSchema URL: https://cmn.dev/schemas/v1/spore.json
capsuleObjectThe capsule container.
capsule.uriStringFull URI: cmn://{domain}/{hash}
capsule_signatureStringEd25519 signature of entire capsule object (ed25519.<base58>, JCS canonical).

2.2 Core Fields (Immutable)

FieldTypeDescription
capsule.coreObjectImmutable metadata (part of spore identity).
capsule.core.nameStringHuman-readable display name (e.g., CMN Protocol Specification).
capsule.core.domainStringThe domain of the publisher (e.g., cmn.dev).
capsule.core.keyStringAuthor’s Ed25519 public key (ed25519.<base58>). Embedded at release time — enables offline signature verification without fetching cmn.json. See 01-substrate §1.2.4 for trust model.
capsule.core.synopsisStringOne-line summary — a visitor reads this alone and understands what the spore does.
capsule.core.intentArrayMulti-paragraph description of this spore’s functionality and purpose — what it does, how it works, why it exists. Each array item is a paragraph. Permanent — not cleared on release.
capsule.core.mutationsArrayWhat changed relative to the spawned_from parent — describes the mutations applied to derive this spore from its ancestor.
capsule.core.licenseStringSPDX License Identifier.
capsule.core.bondsArrayList of {uri, relation, id?, reason?} (See §2.4 Bond Types).
capsule.core.treeObjectTree hash configuration.
capsule.core.tree.algorithmStringTree hash algorithm (e.g., blob_tree_blake3_nfc).
capsule.core.tree.exclude_namesArrayFiles/patterns to skip (e.g., [".git"]).
capsule.core.tree.follow_rulesArrayIgnore systems to honor (e.g., [".gitignore"]).
capsule.core.updated_at_epoch_msNumberContent update timestamp (milliseconds since Unix epoch). Publishers SHOULD derive it from the latest Git commit time for the source tree when available, with max file mtime as fallback.
capsule.core_signatureStringEd25519 signature of capsule.core (ed25519.<base58>, JCS canonical).

2.2.1 Common Extensions

The following fields are optional and not required by the protocol. When present in core, they participate in the hash like any other core field.

FieldTypeDescription
capsule.core.idStringURL-safe path identifier (e.g., cmn-spec). Used by publishers for directory names, mycelium deduplication, and default export paths.
capsule.core.versionStringHuman-readable version (e.g., 1.0.0). Meaningful to the publisher; visitors address by hash.

id vs name:

2.3 Distribution Fields (Mutable)

FieldTypeDescription
capsule.distArrayPhysical source locations (e.g., git, ipfs). Replicate-friendly. MUST contain at least one entry.

Each dist entry MUST be one of:

The first three are built-in v1 entries. archive uses endpoint indirection: filename is resolved through cmn.json endpoints.archive[].url. For future protocols, use the extension form with a type field (for example, { "type": "s3", "url": "..." }). Consumers that do not understand an extension type MAY skip that entry and continue trying other dist entries.

Incremental delivery note:

2.4 Bond Types

Bonds declare relationships to other spores:

{
  "bonds": [
    {
      "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
      "relation": "spawned_from"
    },
    {
      "uri": "cmn://lib.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
      "relation": "depends_on",
      "id": "signing-lib",
      "reason": "Provides Ed25519 signature verification for spore manifests and domain key validation"
    },
    {
      "uri": "cmn://cmn.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
      "relation": "follows",
      "id": "agent-first-data",
      "reason": "Implements agent-first-data naming conventions for all field names"
    },
    {
      "uri": "cmn://other.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
      "relation": "absorbed_from",
      "reason": "Merged authentication module with OAuth and domain verification support"
    }
  ]
}

Bond fields:

FieldTypeRequiredDescription
uriStringYesCMN URI of the bonded spore (e.g., cmn://{domain}/{hash})
relationStringYesRelationship type (see predefined types below)
idStringNoHuman-readable identifier for this bond. Bond-fetch uses it as the directory name under .cmn/bonds/ (e.g. .cmn/bonds/agent-first-data/) instead of the hash.
reasonStringNoWhy this bond exists and what role it plays in this spore
withObjectNoBond-specific parameters defined by the bonded spore’s convention

Predefined relation types:

Note: Custom relation types are allowed. The predefined types provide semantic meaning for tooling, but any string value is valid. Naming guidance (non-enforced): Use namespaced relation names for custom values to avoid collisions (e.g., example.com/deploys_to or org.example.deploys_to). Predefined names above are reserved by the protocol.

The reason field:

The optional reason field explains why this bond exists from the bonding spore’s perspective. It is most useful for:

Note: spawned_from typically does NOT need reason because the mutations field already documents what was modified in this spawn.

Visitors can read the reason field to understand the purpose and context of each bond without needing to fetch the bonded spore’s metadata.

The with field:

The optional with field carries bond-specific parameters whose schema is defined by the bonded spore’s convention. It allows a spore to declare details about how it uses the bonded spore:

{
  "uri": "cmn://cmn.dev/b3.xxx",
  "relation": "follows",
  "id": "strain-payment-method-evm",
  "reason": "Accepts EVM payments",
  "with": {
    "chains": [8453, 42161],
    "tokens": ["native", "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"]
  }
}

The with value is an opaque object to the CMN protocol — its structure is defined entirely by the bonded spore. For example, strain-payment-method-evm defines that with may contain chains and tokens; strain-payment-method-cashu defines that with may contain mints.

2.5 Dependency Model

Taste gate: All operations that place code into a visitor’s working directory — spawning, growing, absorbing, and bonding — require the target spore to have been tasted. See 04-taste for verdict definitions, processing rules, and the taste capsule format.

Replicate convention: When releasing a spore, publishers SHOULD replicate all bonds that point to other domains (see §6.1 Replicate). A replicate hosts the same spore (identical hash, identical core and core_signature) under the publisher’s own domain, re-signed with the publisher’s capsule key. The bond URI then points to the publisher’s replicate:

{
  "bonds": [
    {
      "uri": "cmn://mydomain.com/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
      "relation": "depends_on",
      "reason": "Parsing library"
    },
    {
      "uri": "cmn://mydomain.com/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
      "relation": "implements",
      "reason": "Agent-first-data naming conventions"
    }
  ]
}

The hash is identical to the original — core.domain still identifies the original author. Visitors can reach all bonded spores from a single domain, and verify authorship via core_signature against the original domain’s key. This ensures:

Working directory (.cmn/): A visitor’s spawned project uses a .cmn/ directory for CMN operational data. This directory is project-local, gitignored, and fully regenerable from spore.core.json:

my-project/
├── src/
├── spore.core.json
└── .cmn/                       ← gitignored, regenerable
    ├── bonds/                  ← bonded spores (from bond)
    │   ├── bonds.json          ← index of all bonds
    │   └── {id-or-hash}/       ← id when present, hash otherwise
    │       ├── spore.json      ← spore manifest
    │       └── content/
    └── absorb/                 ← absorb staging (temporary)
        ├── ABSORB.md
        └── {hash}/
            └── content/

The bond operation reads spore.core.json bonds and fetches tasted-safe bonded spores to .cmn/bonds/. It excludes spawned_from (handled by grow) and absorbed_from (historical — the merge is already done). Each bond is stored under its id when present (e.g. .cmn/bonds/agent-first-data/), otherwise under its hash. A bonds.json index maps dir names to hashes, URIs, relations, and names for quick lookup by build systems and tools.

3. Schema Validation

3.1 Schema URL

TypeSchema URL
Sporehttps://cmn.dev/schemas/v1/spore.json

3.2 Embedded Schemas

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

4. Signing and Hashing

4.1 Two-Layer Signature

The spore uses a two-layer signature scheme:

┌─────────────────────────────────────────────────────┐
│ capsule                                             │
│  ┌───────────────────────────────────────────────┐  │
│  │ core (immutable)                              │  │
│  │  name, domain, key, synopsis, intent,         │  │
│  │  mutations, license, bonds, tree,             │  │
│  │  updated_at_epoch_ms, id?, version?           │  │
│  └───────────────────────────────────────────────┘  │
│  core_signature ← signs core                        │
│  uri ← contains hash (computed from code+core+sig) │
│  dist (mutable by replicators)                      │
└─────────────────────────────────────────────────────┘
capsule_signature ← signs entire capsule

4.2 Core Signature

The capsule.core_signature signs the immutable metadata:

  1. Serialize core using JCS (RFC 8785)
  2. Sign with domain’s Ed25519 private key → ed25519.<base58>

Purpose:

4.3 URI Hash Calculation

The hash in capsule.uri is calculated from code (Merkle Tree) + core + core_signature:

  1. Compute code Merkle Tree hash (see §4.6)
  2. Construct hash input: {"code": "<code_hash>", "core": <core>, "core_signature": "<signature>"}
  3. Serialize hash input using JCS
  4. Hash with BLAKE3 → b3.<base58>
  5. Construct URI: cmn://{domain}/b3.<base58>

Key Properties:

4.4 Capsule Signature

The capsule_signature signs the entire capsule object (including uri, core, core_signature, dist):

  1. Serialize capsule using JCS
  2. Sign with domain’s (or replicate host’s) Ed25519 private key → ed25519.<base58>

Purpose:

4.5 Canonical JSON (JCS)

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

4.6 Code Hash (Merkle Tree)

The code hash uses a Git-like Merkle Tree approach for content-addressing.

4.6.1 Hashing Configuration

The capsule.core.tree field controls the tree hash algorithm and which files are included:

algorithm (String):

exclude_names (Name List):

follow_rules (Engine List):

4.6.2 Merkle Tree Construction (Git-compatible)

CMN uses Git-like Merkle Tree format with two differences:

  1. BLAKE3 (32 bytes) instead of SHA-1 (20 bytes)
  2. NFC normalization for filenames (cross-platform consistency)

Blobs (Files):

Concatenate header and file content, then BLAKE3 hash the result:

blob <content_length>\0<file_content>

Example: A file containing hello (5 bytes) → blob 5\0hello → BLAKE3 → 32-byte hash.

Trees (Directories):

Build sorted entries, prepend header, then BLAKE3 hash:

tree <entries_length>\0<entry_1><entry_2>...

Each entry:

<mode> <name>\0<32-byte-binary-hash>

Processing rules:

Entry Format:

4.6.3 Unicode NFC Normalization

See also: §4.6.4 below for a complete step-by-step worked example.

To prevent hash mismatches between operating systems (macOS NFD vs. Linux NFC):

4.6.4 Worked Example

A directory with two files:

my-project/
├── README.md    (13 bytes: "Hello, CMN!\n")
└── src/
    └── main.rs  (14 bytes: "fn main() {}\n")

Step 1 — Hash blobs (files):

Each file is prefixed with blob <length>\0:

README.md:
  Input bytes: "blob 13\0Hello, CMN!\n"   (5 + 2 + 1 + 13 = 21 bytes)
  BLAKE3 → readme_hash (32 bytes binary)

src/main.rs:
  Input bytes: "blob 14\0fn main() {}\n"  (5 + 2 + 1 + 14 = 22 bytes)
  BLAKE3 → main_hash (32 bytes binary)

Step 2 — Build the src/ tree:

One entry for main.rs, sorted alphabetically (only one entry here):

Entry: "100644 main.rs\0" + main_hash (32 bytes binary)

Concatenate all entries to get src_entries. Prepend header:

Input bytes: "tree <len(src_entries)>\0" + src_entries
BLAKE3 → src_tree_hash (32 bytes binary)

Step 3 — Build the root tree:

Two entries sorted alphabetically: README.md (file), src (directory):

Entry 1: "100644 README.md\0" + readme_hash (32 bytes binary)
Entry 2: "40000 src\0" + src_tree_hash (32 bytes binary)

Concatenate entries to get root_entries. Prepend header:

Input bytes: "tree <len(root_entries)>\0" + root_entries
BLAKE3 → root_hash (32 bytes binary)

Step 4 — Format root hash:

Convert root_hash to base58 → b3.<~44 base58 chars>

This root hash is the code hash used in §4.3 (URI hash calculation).

Key details:

5. Content Verification

5.1 Integrity (MUST)

After obtaining spore content through any distribution channel (archive, git, IPFS, or any other dist source), the client MUST compute the Merkle Tree hash (§4.6) and verify it matches the hash in the spore URI. Content with mismatched hashes MUST be rejected.

5.2 Review (SHOULD)

Hash verification only proves “content has not been tampered with” — it does not prove “content is safe.” Clients SHOULD review spore content before use. The taste system provides a framework for recording and sharing review results.

5.3 Key Trust Verification

Spores with capsule.core.key support offline signature verification. The embedded key allows clients to verify core_signature locally, then establish trust in the key through the tiered model described in 01-substrate §1.2.4.

For replicates (where core.domain differs from the URI domain), core.key is the original author’s key — core_signature verifies against it. The capsule_signature still verifies against the hosting domain’s key from cmn.json.

6. Replicating and Spawning

6.1 Replicate (Same Hash)

A replicate hosts the same spore with different dist URLs:

{
  "$schema": "https://cmn.dev/schemas/v1/spore.json",
  "capsule": {
    "uri": "cmn://replicate.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "core": {
      "name": "CMN Protocol Specification",
      "domain": "cmn.dev"
    },
    "core_signature": "ed25519.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa23yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
    "dist": [
      { "type": "archive", "filename": "cmn-spec.tar.zst" }
    ]
  },
  "capsule_signature": "ed25519...."
}

Verification:

  1. If core.key is present, verify core_signature against core.key locally; otherwise fetch cmn.dev public key from cmn.json
  2. Establish key trust via domain confirmation or Synapse witness (see 01-substrate §1.2.4)
  3. URI hash matches (b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2)
  4. domain ≠ URI domain → This is a replicate hosted by replicate.dev
  5. capsule_signature verifies against replicate.dev public key

6.2 Spawn (Different Hash)

A spawn creates a new spore derived from an existing one (new domain, modified metadata):

{
  "$schema": "https://cmn.dev/schemas/v1/spore.json",
  "capsule": {
    "uri": "cmn://fork.dev/b3.8cQnH4xPmZ2vLkJdRt7wNbA9sF3eYgU1hK6pXq5",
    "core": {
      "name": "CMN Spec Spawn",
      "domain": "fork.dev",
      "bonds": [
        {
          "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
          "relation": "spawned_from"
        }
      ]
    },
    "core_signature": "ed25519....",
    "dist": [...]
  },
  "capsule_signature": "ed25519...."
}

Properties:

7. spore.core.json

Each spore source directory includes a spore.core.json file containing the capsule.core fields (§2.2). It does not contain dist or signatures — those are added during release.

Schema: https://cmn.dev/schemas/v1/spore-core.json

7.1 Field Reference

Required fields:

FieldTypeDescription
nameStringHuman-readable display name.
domainStringPublisher domain (e.g., cmn.dev).
synopsisStringOne-line summary — a visitor reads this alone and understands what the spore does.
intentArrayMulti-paragraph description of this spore’s functionality and purpose — what it does, how it works, why it exists. Each array item is a paragraph. Permanent — not cleared on release. Required for release.
licenseStringSPDX License Identifier.
treeObjectTree hash configuration. Required for deterministic content hashing.

Optional fields:

FieldTypeDescription
idStringURL-safe path identifier (e.g., cmn-spec). Used for directory names and mycelium deduplication.
versionStringHuman-readable version (e.g., 1.0.0). Informational only; visitors address by hash.
mutationsArrayWhat changed relative to the spawned_from parent — describes the mutations applied to derive this spore from its ancestor.
bondsArrayList of {uri, relation, id?, reason?} objects (see §2.4).

tree sub-fields:

FieldTypeDescription
algorithmStringTree hash algorithm (e.g., blob_tree_blake3_nfc).
exclude_namesArrayDirectories or files to skip during hashing (e.g., [".git"]).
follow_rulesArrayStandard ignore file formats to honor (e.g., [".gitignore"]).

7.2 Complete Example

{
  "$schema": "https://cmn.dev/schemas/v1/spore-core.json",
  "id": "cmn-spec",
  "version": "1.2.0",
  "name": "CMN Protocol Specification",
  "domain": "cmn.dev",
  "synopsis": "Code Mycelial Network - A sovereign-first protocol for code distribution",
  "intent": ["add intent and changes array fields to spore core"],
  "mutations": [
    "§2.2 Core Fields: intent type String → Array",
    "§2.2 Core Fields: add mutations field (Array)",
    "§1, §4.1, §6 example JSON updated"
  ],
  "license": "CC0-1.0",
  "bonds": [
    {
      "uri": "cmn://cmn.dev/b3.3yMR7vZQ9hL2xKJdFtN8wPcB6sY1mXgU4eH5pTa2",
      "relation": "spawned_from"
    }
  ],
  "tree": {
    "algorithm": "blob_tree_blake3_nfc",
    "exclude_names": [".git"],
    "follow_rules": [".gitignore"]
  }
}

7.3 Lifecycle

spore.core.json (local draft, committed to git)

     │  hypha hatch  ← create or update


hypha release

     ├── Read spore.core.json
     ├── Compute Merkle Tree root hash (§4.6)
     ├── Sign core → core_signature
     ├── Compute URI hash (§4.3)
     ├── Add dist endpoints
     ├── Sign capsule → capsule_signature


spore.json (signed, published, immutable)

The spore.core.json file is the only file a developer edits directly. The release command reads it, adds computed fields (dist, signatures, URI), and produces the final spore.json.