-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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 defaultCore fetches the default tag from the official spool (github.com/Muxcore-Media/spool) and discovers which modules to load.
| 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.
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
}
]
}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.
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) FAILSThis is Go's nominal type system — type identity is package_path + name, not structure.
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:
- Extract. Parses the Go interface from the third-party contract repo using AST
- Compare. Checks structural compatibility against the canonical Muxcore-Media equivalent (method names, parameter types, return types)
-
Normalize. If structurally identical, generates a
go.mod replacedirective - 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.
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.
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.DownloaderModules importing from this repo get the canonical type directly. The Go compiler treats them as identical.
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.
Core exposes the SpoolService gRPC service for runtime management of spools and tag deployments. Admin tools use this to inspect available spools, list tags, and trigger deployments without restarting:
| RPC | Purpose |
|---|---|
ListSpools |
Returns all configured spool URLs (active spool from --spool, plus any configured runtime spools) |
ListTags |
Lists all tag names available on a given spool, with descriptions and module counts |
FetchTag |
Fetches a tag definition without deploying — inspect what modules would be loaded |
DeployTag |
Fetches a tag, resolves modules, verifies checksums, and spawns new ones. Idempotent — already-running modules are skipped |
# Using muxcorectl (or any gRPC client):
# Call DeployTag to load the "media-stack" tag without restarting corespoolClient := spoolv1.NewSpoolServiceClient(conn)
resp, err := spoolClient.DeployTag(ctx, &spoolv1.DeployTagRequest{
SpoolUrl: "https://github.com/Muxcore-Media/spool",
TagName: "media-stack",
})
// resp.Spawned → number of modules newly spawned
// resp.Skipped → modules already running
// resp.Failed → modules that failed to startThe DeployTag response reports per-module results:
{
"tag_name": "media-stack",
"results": [
{"module_id": "downloader-qbittorrent", "spawned": true, "already_running": false},
{"module_id": "media-movies", "spawned": false, "already_running": true}
],
"spawned": 1,
"skipped": 1,
"failed": 0
}See Admin API for the full gRPC reference.
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.
- Module System — how modules discover each other
- Contracts Reference — every interface in detail
- Spool Security — trust model for third-party spools