Skip to content

Writing Modules

TheMinecraftGuyGuru edited this page Jun 8, 2026 · 5 revisions

Writing Modules

This guide covers everything you need to build a MuxCore module from scratch.

Quick Start

A module is a Go package that:

  1. Implements contracts.Module (lifecycle)
  2. Calls contracts.Register() in init() (auto-discovery)
  3. Implements one or more capability contracts (the actual functionality)
  4. Has a muxcore.json at its repo root (marketplace metadata)
my-module/
  go.mod           <- depends on github.com/Muxcore-Media/core
  module.go        <- your implementation
  muxcore.json     <- marketplace metadata

Minimal Module

package mymodule

import (
    "context"
    "github.com/Muxcore-Media/core/pkg/contracts"
)

func init() {
    contracts.Register(func(deps contracts.ModuleDeps) contracts.Module {
        return NewModule(deps.EventBus)
    })
}

type Module struct {
    bus contracts.EventBus
}

func NewModule(bus contracts.EventBus) *Module {
    return &Module{bus: bus}
}

func (m *Module) Info() contracts.ModuleInfo {
    return contracts.ModuleInfo{
        ID:      "my-module",
        Name:    "My Module",
        Version: "1.0.0",
        Kinds:   []contracts.ModuleKind{contracts.ModuleKindProvider},
    }
}

func (m *Module) Init(ctx context.Context) error  { return nil }
func (m *Module) Start(ctx context.Context) error { return nil }
func (m *Module) Stop(ctx context.Context) error  { return nil }
func (m *Module) Health(ctx context.Context) error { return nil }

ModuleDeps - What Core Gives You

Every module receives a contracts.ModuleDeps struct with seven services:

Field Interface Use
EventBus contracts.EventBus Publish and subscribe to events
Registry contracts.ServiceRegistry Discover other modules at runtime
Routes contracts.RouteRegistrar Register HTTP handlers
Cluster contracts.Cluster Cluster membership (nil if standalone)
Storage contracts.StorageOrchestrator Object storage via IDs, not paths
WorkerPool contracts.WorkerPool Distributed task scheduling
Audit contracts.AuditLogger System-wide audit logging

How to Implement Each Module Kind

Downloader

Implement contracts.Downloader. Discovered via FindByKind(ModuleKindDownloader). Example: downloader-qbittorrent

Indexer

Implement contracts.Indexer. Discovered via FindByKind(ModuleKindIndexer). Example: indexer-jackett

Auth Provider

Implement contracts.AuthProvider. Core wires the first auth module into the API middleware automatically. Example: auth-local

Playback

Implement contracts.Playback. Discovered via FindByKind(ModuleKindPlayback). Example: jellyfin

Media Manager

Implement contracts.MediaLibrary + MediaTypeSchemaProvider. Discovered via FindByKind(ModuleKindMediaManager). Example: media-manager-movies

Workflow Engine

Implement contracts.WorkflowEngine. Discovered via FindByKind(ModuleKindWorkflow). Example: workflow-engine

Storage Provider

Implement contracts.StorageProvider. Optionally implement Streamable, Seekable, Watchable, AtomicMovable, Hardlinkable — the orchestrator detects these at runtime.

Scheduler

Implement contracts.Scheduler. Discovered via FindByKind(ModuleKindScheduler). Example: scheduler-cron

UI Module

Register HTTP handlers via RouteRegistrar. Uses ModuleKindUI. Example: admin-ui

API Module

Register API routes via RouteRegistrar. Uses ModuleKindAPI. Example: api-rest

Rate Limiter

Implement contracts.RateLimiterProvider. Core discovers and wires into API middleware. Example: ratelimit-tokenbucket

Cache

Implement contracts.CacheLayer. Storage orchestrator discovers automatically. Example: cache-memory

Health Monitor

Implement contracts.HealthMonitor. Core discovers and starts automatically. Example: health-monitor

Provider Modules

For modules without a specific kind interface, use ModuleKindProvider and advertise capabilities:

  • Supplementary Content: SupplementaryContentProvider, cap content.subtitle
  • Notification: NotificationProvider, cap notification.discord
  • Import Lists: ImportListProvider, cap importlist.trakt
  • Media Info: MediaInfoProvider, cap mediainfo.ffprobe
  • File Watcher: FileWatcher, cap filewatcher.inotify
  • Audit Logger: AuditLogger, cap audit.log
  • Worker Pool: WorkerPool, cap worker.distributed

Module Communication

Discovering Other Modules

// Broad: find all downloaders
entries := deps.Registry.FindByKind(contracts.ModuleKindDownloader)

// Fine-grained: find by capability
entries := deps.Registry.FindByCapability("playback.jellyfin")

// Direct: resolve by ID
entry, err := deps.Registry.Resolve("downloader-qbittorrent")

// Type-assert to the interface
for _, entry := range entries {
    if dl, ok := entry.Module.(contracts.Downloader); ok {
        dl.Add(ctx, task)
    }
}

Publishing Events

deps.EventBus.Publish(ctx, contracts.Event{
    Type:    contracts.EventDownloadCompleted,
    Source:  "module:my-downloader",
    Payload: payload,
})

Subscribing to Events

deps.EventBus.Subscribe(ctx, contracts.EventMediaRequested,
    func(ctx context.Context, event contracts.Event) error {
        var payload contracts.MediaRequestedPayload
        json.Unmarshal(event.Payload, &payload)
        return nil
    })

Module Metadata (muxcore.json)

{
  "name": "My Module",
  "description": "What it does",
  "version": "1.0.0",
  "kind": "downloader",
  "capabilities": ["downloader.torrent"],
  "dependencies": [],
  "homepage": "https://github.com/you/my-module"
}
Field Required Notes
name Yes Display name
description Yes Short description
version Yes Semantic version
kind Yes One of: auth, provider, downloader, indexer, media_manager, processor, playback, workflow, storage, ui, api, eventbus, scheduler
capabilities Yes Array of capability strings
dependencies No Module IDs this depends on
homepage No URL to repo

Publishing

  1. Push module to a public GitHub repo
  2. Add repo URL to a marketplace catalog.json
  3. For the official marketplace, submit a PR to github.com/Muxcore-Media/marketplace-catalog

Checklist

  • go.mod depends on github.com/Muxcore-Media/core
  • contracts.Register() called in init()
  • Implements contracts.Module (Info, Init, Start, Stop, Health)
  • Implements the capability contract for your module kind
  • muxcore.json at repo root
  • Module kind matches the contract interface
  • Builds with core: go build -tags default ./cmd/muxcored

Clone this wiki locally