Skip to content

Spool and Marketplace

TheMinecraftGuyGuru edited this page Jun 8, 2026 · 2 revisions

Spool and Marketplace

Spools are how MuxCore discovers modules. The marketplace is how it imports them. This page explains how modules are discovered, imported, and how contract reconciliation enables third-party modules to use their own contract repos.


How Spools Work (Plain Language)

Think of a spool like an app store catalog. It's a list of available modules and curated tag presets. When you run:

muxcored --tag default

Core fetches the default tag from the official spool (github.com/Muxcore-Media/spool) and discovers which modules to load.

Official vs Third-Party Spools

Type Example Trust Level
Official github.com/Muxcore-Media/spool Maintained by the MuxCore team
Third-party github.com/some-user/custom-spool Untrusted — audit before use

Anyone can create a spool. See Spool Security for the trust model.

Tag Format

Tags are JSON files in tags/<name>.json. They list modules with version pins:

{
  "name": "default",
  "description": "The official MuxCore starter setup",
  "version": "1.0.0",
  "modules": [
    {
      "repo": "https://github.com/Muxcore-Media/admin-ui",
      "version": "v1.0.0",
      "required": true
    }
  ]
}

Module Import and Contracts

Every module implements one or more contract interfaces. For official modules, these contracts come from github.com/Muxcore-Media/contracts-* repos. But third-party module authors may define their contracts in their own repos.

The Problem: Go's Nominal Type System

In Go, two interfaces with identical method sets but different package paths are different types:

// Module A imports the canonical contract
import "github.com/Muxcore-Media/contracts-media"
var lib media.MediaLibrary

// Module B implements an identical interface from a different repo
import "github.com/some-dev/contracts-media"
// Module B's MediaLibrary is a DIFFERENT type than Module A's
// Type assertion lib = moduleB.(media.MediaLibrary) FAILS

This is Go's nominal type system — type identity is package_path + name, not structure.

The Solution: Contract Reconciliation

When core imports a module (via --tag), the module manager runs the contract reconciliation engine (github.com/Muxcore-Media/contracts-reconciler) after cloning the repo and before building:

  1. Extract. Parses the Go interface from the third-party contract repo using AST
  2. Compare. Checks structural compatibility against the canonical Muxcore-Media equivalent (method names, parameter types, return types)
  3. Normalize. If structurally identical, generates a go.mod replace directive
  4. Reject. If methods differ, the import fails with a detailed mismatch report
Third-party: github.com/some-dev/contracts-media v1.2.0
Canonical:   github.com/Muxcore-Media/contracts-media v1.0.0

Interface "MediaLibrary":
  - Both have: Add, Remove, Get, List, Search
  - Method signatures match structurally ✓

→ go mod edit -replace github.com/some-dev/contracts-media=github.com/Muxcore-Media/contracts-media@v1.0.0

After reconciliation, go.mod replace directives normalize all contract imports to canonical paths. Compile-time type safety is preserved — every module agrees on the same MediaLibrary type.

Declaring Contracts in muxcore.json

Third-party modules declare their contracts in muxcore.json:

{
  "name": "My Custom Downloader",
  "kind": "downloader",
  "capabilities": ["downloader.custom"],
  "contracts": [
    {
      "repo": "github.com/my-org/contracts-downloader",
      "version": "v2.0.0",
      "interface": "Downloader"
    }
  ]
}

Official modules don't need this — they already use canonical contract repos.

The Simplest Approach: Type Aliases

If you control the third-party contract repo, use Go type aliases to avoid reconciliation entirely:

package downloader

import "github.com/Muxcore-Media/contracts-downloader"

// Type alias — this IS the canonical type. No reconciliation needed.
type Downloader = contracts_downloader.Downloader

Modules importing from this repo get the canonical type directly. The Go compiler treats them as identical.


Canonical Contract Registry

The reconciler maintains a registry mapping interface names to canonical repos. Interface names are checked in Go source via Canonical("MediaLibrary").

Interface Canonical Repo
MediaLibrary github.com/Muxcore-Media/contracts-media
Downloader github.com/Muxcore-Media/contracts-downloader
Indexer github.com/Muxcore-Media/contracts-indexer
MetadataProvider github.com/Muxcore-Media/contracts-metadata
Transcoder github.com/Muxcore-Media/contracts-transcoder
Playback github.com/Muxcore-Media/contracts-playback
... ...

The full registry is maintained in the contracts-reconciler repo's canonical.go.


Philosophy

MuxCore contracts are patterns, not org-bound dependencies. Two modules implementing the same interface pattern should be interchangeable regardless of which GitHub org published the .go file.

The reconciler is the weaver — it aligns patterns across independent contract repos. Core never enters the conversation. The loom doesn't care which thread made the pattern.


Next Steps

Clone this wiki locally