- Shell 49.7%
- Go 43%
- Python 5.6%
- Dockerfile 1.2%
- Nix 0.3%
- Other 0.2%
| caddy | ||
| cmd | ||
| deploy | ||
| dockerfiles | ||
| docs | ||
| scripts | ||
| systemd | ||
| tls | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| BFF-API.md | ||
| bootstrap-auth.sh | ||
| Caddyfile | ||
| docker-compose.yml | ||
| go.mod | ||
| go.sum | ||
| local-registry.sh | ||
| muxcore.json | ||
| muxcore.staging.json | ||
| PORTS.md | ||
| README.md | ||
| REPO-STATUS.md | ||
| run-host-staging.sh | ||
| run-host.sh | ||
| setup.sh | ||
| smoke.sh | ||
MuxCore MVP stack
Local reference compose for the media MVP path. Sibling clones under /home/user/Projects/MuxCore are the build context.
P0 Media MVP status: met (Wave 21 stack + smoke; Wave 22 packaging freeze). Operator URLs after ./run-host.sh up: run/VIEW-ME.txt.
Core pin: published v0.5.4 (remote storage sidecar dial; Settings mesh + chunked Put; mTLS from v0.5.1). Nested: pkg/contracts @ v0.5.4; sdk/go/module / sdk/go/client still @ v0.5.3. Modules pinning without replace (GOPRIVATE=github.com/Muxcore-Media/*, gh HTTPS):
Historical wave pins (still accurate as of each wave; later patch tags supersede — see spool catalog 2.4.13):
- Waves 25–26 (core-adjacent):
auth-local,call-policy-default,publish-policy-default,secrets-file,encryption-aesgcm,api-rest,jellyfin@v0.2.1,media-root-folders@v0.1.1,health-monitor,metadata-tmdb@v0.1.1,database-sqlite,secrets-vault - Wave 27 (native media stack):
contracts-media-admin@v0.1.0,contracts-notification@v0.1.1,media-movies@v0.1.1,media-tvshows@v0.1.1,media-scanner@v0.1.1,media-automation@v0.1.0,request-media@v0.2.2,notification-default@v0.1.0,admin-ui@v0.1.3 - Wave 28 (leaves + smoke helpers):
media-rename@v0.2.2,media-ffprobe@v0.1.2,media-subtitles@v0.4.2,media-custom-formats@v0.1.2. Hostgo.modsmoke helpers pin published module tags (sibling replaces removed); localreplace => ../core*kept for host convenience. - Wave 29 (non-host sibling pins):
media-list-sync@v0.1.1,notification-apprise@v0.1.1,workflow-tapestry@v0.1.0(not started by defaultrun-host.sh). Polluted orgmedia-uidump archived; usemedia-ui-app.
Consumer SPA: Muxcore-Media/media-ui-app (private; host uses sibling ../media-ui-app/dist-app).
Authoritative docs: ../core.wiki/Getting-Started.md, ../core.wiki/Deployment.md.
Spool presets mirrored: ../spool/tags/minimal.json, ../spool/tags/media.json.
Operator references in this repo: PORTS.md (default gRPC/HTTP ports), BFF-API.md (mediauiprox JSON contracts), tls/ (mTLS staging + secret rotation).
Prerequisites
- Docker Compose v2 or host Go toolchain (
run-host.sh) - Org repos cloned as siblings (same layout as this workspace)
- Dev default:
MUXCORE_INSECURE_DISABLE_TLS=truevia./run-host.sh. Staging mTLS:./run-host-staging.sh(seetls/MTLS-STAGING.md).
GHCR images (optional)
Default compose builds from sibling trees. To pull prebuilt images instead, use docker-compose.ghcr.yml once muxcored (and peers) are published.
Publish muxcored from a host with rootless podman (e.g. gringotts):
./scripts/publish-muxcored-ghcr.sh v0.5.4
Requires gh token scopes repo + write:packages. Image build is verified locally as localhost/muxcored:v0.5.0 (rebuild for v0.5.1 before publish); GHCR push is blocked until the token has packages write.
Kubernetes (Phase 3 scaffold)
Kustomize overlays + Helm chart for the minimal platform slice live under deploy/:
kubectl apply -k deploy/kustomize/overlays/dev
# or
helm upgrade --install muxcore deploy/helm/muxcore -n muxcore --create-namespace
Images default to ghcr.io/muxcore-media/* (same GHCR P0 dependency). Host ./run-host.sh remains the verified operator path.
Quick start
Guided host setup (recommended):
cd mvp # or _mvp in older layouts
./setup.sh
Prompts for TMDB (live key or offline fixtures), admin credentials, library paths, and optional Jellyfin; writes .env, starts ./run-host.sh up, bootstraps auth, and can run ./smoke.sh.
Manual path:
cd mvp
cp .env.example .env
# edit TMDB_API_KEY=… (or TMDB_FIXTURE=1) and MVP_ADMIN_* as needed
Docker Compose (preferred for containers)
docker compose up --build -d
./bootstrap-auth.sh
./smoke.sh
Host binaries (no Docker)
(cd ../core && go build -o ../_mvp/bin/muxcored ./cmd/muxcored)
(cd ../api-rest && go build -o ../_mvp/bin/api-rest ./cmd/module)
(cd ../media-tvshows && go build -o ../_mvp/bin/media-tvshows ./cmd/module)
(cd ../admin-ui && npx --yes @tailwindcss/cli@4.1.6 -i ./input.css -o ./assets/dist/styles.css --minify && go build -o ../_mvp/bin/admin-ui .)
(cd ../auth-local && go build -o ../_mvp/bin/auth-local ./cmd/module)
(cd ../jellyfin && go build -o ../_mvp/bin/jellyfin ./cmd/module)
(cd ../media-scanner && go build -o ../_mvp/bin/media-scanner ./cmd/module)
# Or rebuild many peers to spool catalog tags: ./scripts/rebuild-catalog-peers.sh media-scanner api-rest
(cd ../media-automation && go build -o ../_mvp/bin/media-automation ./cmd/module)
./run-host.sh up
# Single-module ops (core stays up; clears stale mesh registration on stop/restart):
# ./run-host.sh stop-one media-scanner
# ./run-host.sh restart admin-ui
# ./run-host.sh unregister media-scanner
./bootstrap-auth.sh
./smoke.sh
./run-host.sh stop
Admin UI: http://localhost:8082. Jellyfin bridge HTTP: http://127.0.0.1:8475/healthz (optional JELLYFIN_BASE_URL + JELLYFIN_API_KEY for a live server).
Scanner watches _mvp/data/downloads and imports into _mvp/data/library (SCANNER_IMPORT_MODE=copy).
Automation: soft queue APIs (AddToQueue / GetQueue / Search). Host stack sets MUXCORE_MESH_DIAL_LOCAL=true and absolute PUBLISH_POLICY_FILE / CALL_POLICY_FILE.
Smoke checks
- Core
/health200 - Discovery resolve (incl.
media-tvshows,jellyfin,media-scanner,media-automation) - Bearer
/api/v1/modules - AddMovie / AddTVShow
- Admin UI login via auth-local +
/modules+/dashboard/monitor+/automation+/jellyfin - Jellyfin
/healthz+ gRPCStatus(soft OK when unconfigured) - Jellyfin soft
UpsertItemLink/ListItemLinks/SyncLibraryskip + fixturePOST /webhookPlaybackStart - Scanner
ImportPathfixture → organized library file underdata/library/Movies/... - Automation queue soft (
AddToQueue/GetQueue) - Health-monitor
ReportHealth+ HTTP/status+ mesh fan-out ofmodule.degraded(visible on admin-ui/events?filter=health) - Media-ui SPA (
:5173) auth + shell +/api/movies/ stream //api/tvvia mediauiprox BFF (skip if not running) - Media-ui → request-media: search +
POST /api/request(TMDB_FIXTURE=1offline Fight Club hit, or liveTMDB_API_KEY) - Soft
/api/jellyfin/play(200 linked / 404 unlinked or unconfigured) - Optional live Jellyfin (
SMOKE_LIVE_JELLYFIN=1, or auto whenJELLYFIN_BASE_URL+JELLYFIN_API_KEYare set): Status configured + RefreshLibrary + SyncLibrary + sample PlayURL viacmd/jellyfinlive
Consumer SPA source/build: ../media-ui-app/ → org Muxcore-Media/media-ui-app (dist-app). Build with (cd ../media-ui-app && npm ci && npm run build).
Profiles
| Profile | Extra services |
|---|---|
| (default) | platform + media path + admin-ui + jellyfin + scanner + automation + request-media + media-ui (host) |
observability |
compose-only: metrics-prometheus (:9901 scrape) + tracing-otlp (slog fallback unless OTEL_EXPORTER_OTLP_ENDPOINT set) |
media-ui |
compose-only: consumer SPA + BFF on :5173 |
Polluted media-ui/ dump is quarantined — shippable SPA is media-ui-app/. Operator admin remains admin-ui.
Endpoints
| Service | Host port (default) |
|---|---|
| core HTTP | 8080 |
| admin-ui | 8082 |
| api-rest HTTP | 18080 |
| auth-local gRPC / HTTP | 9403 / 9401 |
| media-movies gRPC | 9420 |
| media-tvshows gRPC / HTTP | 9440 / 9450 |
| media-automation gRPC | 9460 |
| downloader gRPC | 9461 |
| media-scanner gRPC | 9470 |
| jellyfin gRPC / HTTP | 9475 / 8475 |
| health-monitor gRPC / HTTP | 9202 / 9203 |
| media-ui (consumer SPA) | 5173 |
| request-media HTTP / gRPC | 9380 / 9481 |
| media-root-folders gRPC | 9540 |