No description
  • Go 83.2%
  • Vim Snippet 7.6%
  • Shell 5.6%
  • Dockerfile 2.1%
  • Makefile 1.5%
Find a file
Antoine 5ddd4e4546
Some checks failed
ci / go (push) Failing after 42s
design: lock Star/Planet/North Star architecture (ADR-0008..0014)
- Polish autopilot pass: DB-backed LiteLLM sync via admin API (no restarts),
  orchestrator container off UID 0, last_sync_error surfaced everywhere,
  SyncModels unit tests, CI workflow, runbook, Makefile.
- Architectural redesign locked in via grill-with-docs:
  - Worker -> Instance -> Planet rename
  - Orchestrator split into Orchestrator (UI) + North Star (workload-agnostic
    deployer / plug executor)
  - Borealis-derived service.yaml format with Northstar extensions
  - Adopt PocketID + Headscale as canonical platform services
- ADRs 0008..0014 + plan-0001 capture the design state for the migration.
2026-05-28 12:13:20 +00:00
.github/workflows design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
cmd design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
docs design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
internal design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
quadlet Initial commit: unsloth-orchestrator 2026-05-16 23:22:47 +00:00
scripts Initial commit: unsloth-orchestrator 2026-05-16 23:22:47 +00:00
upstream-issues Initial commit: unsloth-orchestrator 2026-05-16 23:22:47 +00:00
.gitignore Initial commit: unsloth-orchestrator 2026-05-16 23:22:47 +00:00
Containerfile design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
CONTEXT.md design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
go.mod design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
go.sum design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
Makefile design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00
README.md design: lock Star/Planet/North Star architecture (ADR-0008..0014) 2026-05-28 12:13:20 +00:00

unsloth-orchestrator

Thin control plane for a 2-machine Unsloth Studio fleet on Fedora CoreOS.

Most of what this repo does is configure off-the-shelf parts (Unsloth Studio, LiteLLM, Caddy, oauth2-proxy, PocketID) into a coherent shape. The Orchestrator binary is small: an operator landing page, a unix-socket admin CLI, and a reconciler that keeps LiteLLM's config in sync with the operator's intent.

Read first: CONTEXT.md for vocabulary, docs/architecture.md for the picture, and docs/adr/ for the decisions.

Topology in one sentence

Clients hit LiteLLM with an sk-litellm-… key → LiteLLM proxies to one of the two Workers using an sk-unsloth-… key the operator pasted earlier → the Worker is a single off-the-shelf unsloth/unsloth container with its full UI accessible at worker-<n>.<domain> (via Caddy + PocketID).

Repo layout

CONTEXT.md                 — vocabulary
docs/
  architecture.md          — diagram + request flows + state map
  adr/                     — design decisions (read 0001 first)
  quadlet-patterns.md      — Fedora CoreOS / Quadlet conventions
quadlet/
  orchestrator.container   — Orchestrator daemon (control plane)
  orchestrator-data.volume — its SQLite
  unsloth-studio.container — runs on each Worker
  unsloth-studio-home.volume
  huggingface-cache.volume
  litellm.container
  litellm-postgres.container
  litellm-postgres-data.volume
  litellm/config.yaml      — static bootstrap (general_settings only)
  oauth2-proxy.container   — template (skip if you already have one)
  caddy/orchestrator.caddyfile.snippet
cmd/
  orchestrator/main.go     — daemon entrypoint
  unsloth-orch/main.go     — operator CLI
internal/
  config, store, server, litellm
scripts/
  sops-bootstrap.sh        — first-install secret provisioning
Containerfile              — multi-stage build for the daemon + CLI
upstream-issues/           — tracker for unslothai/unsloth#5031

Deploy

Three Fedora CoreOS machines: one control plane (no GPU needed), two Workers (one GPU each). All three on a shared Tailscale (or other Overlay) network. Caddy + PocketID already deployed on the control plane.

1. Provision secrets

On any host with sops and age:

SOPS_AGE_RECIPIENT="age1..." ./scripts/sops-bootstrap.sh

This generates /etc/unsloth/{orchestrator,litellm,litellm-postgres,worker}.enc.yaml. Copy worker.enc.yaml to both Workers; copy the rest to the control plane. The matching age private key goes in /etc/unsloth/secrets-age.key (mode 0400) on every machine.

2. Build and ship the orchestrator image

On a build host (or directly on the control plane):

podman build -t localhost/unsloth-orchestrator:v0.1 .

Pin by digest in quadlet/orchestrator.container after the first build.

3. Install Quadlets

On the control plane, copy the orchestrator + LiteLLM + (optionally) oauth2-proxy quadlets into /etc/containers/systemd/:

/etc/containers/systemd/orchestrator.container
/etc/containers/systemd/orchestrator-data.volume
/etc/containers/systemd/litellm.container
/etc/containers/systemd/litellm-postgres.container
/etc/containers/systemd/litellm-postgres-data.volume

Drop the static quadlet/litellm/config.yaml at /etc/litellm/config.yaml on the control plane. It carries only general_settings + litellm_settings — the model list lives in LiteLLM's Postgres and is owned by the Orchestrator via the admin API.

On each Worker, copy the Unsloth quadlets:

/etc/containers/systemd/unsloth-studio.container
/etc/containers/systemd/unsloth-studio-home.volume
/etc/containers/systemd/huggingface-cache.volume

Then systemctl daemon-reload && systemctl enable --now everything.

4. Wire Caddy

Merge the contents of quadlet/caddy/orchestrator.caddyfile.snippet into your existing Caddyfile (or import it). Substitute your real domain for unsloth.example.

Reload Caddy.

5. Register Workers + load models

ssh control-plane sudo unsloth-orch worker add worker-1 worker-1.overlay
ssh control-plane sudo unsloth-orch worker add worker-2 worker-2.overlay

Visit https://worker-1.<domain>/, log into Unsloth (the bootstrap password from step 1), pick a model from the model browser, mint a UI API key (Settings → API → Create). Copy the sk-unsloth-… token. Then:

ssh control-plane sudo unsloth-orch worker set-key worker-1 sk-unsloth-...

Repeat for worker-2. The Orchestrator's reconciler POSTs the new model entry to LiteLLM's admin API (/model/new → Postgres) within 30 seconds. No LiteLLM restart needed; the change takes effect on the next request.

6. Mint a Client key for yourself

ssh control-plane sudo unsloth-orch key create my-laptop

The CLI prints sk-litellm-… once. Point your client at https://litellm.<domain>/v1 with that token.

Operating

  • Add a model to a Worker: open the Worker's proxied UI, load it from the model browser. Nothing on the orchestrator side to change — LiteLLM's wildcard routing picks it up on the next /v1/models call.
  • Swap which model a Worker is serving: same — UI does it.
  • Rotate a Worker key: mint a new one in the Worker's UI, then unsloth-orch worker set-key <name> <new-key>. Reconciler pushes the new key to LiteLLM within 30s; no restart.
  • Revoke a Client key: unsloth-orch key revoke <name>.
  • Check sync health: the shell UI shows a red banner if the reconciler is failing, plus last_sync_at. CLI: unsloth-orch status.

For incident response (LiteLLM down, key rotation, backups, host reinstall, SOPS-age key compromise) see docs/runbook.md.

Development

The daemon supports an insecure dev mode that fakes X-Forwarded-User when oauth2-proxy isn't in the path. Never use in production.

ORCHESTRATOR_DEV_INSECURE=1 \
ORCHESTRATOR_STATE_DB=/tmp/state.db \
ORCHESTRATOR_ADMIN_SOCKET=/tmp/admin.sock \
ORCHESTRATOR_LITELLM_URL=http://127.0.0.1:4000 \
LITELLM_MASTER_KEY=dev \
go run ./cmd/orchestrator

Upstream issues tracked

  • unslothai/unsloth#5031 — option to disable Unsloth's UI auth in trusted-network deployments; would let us remove the double-login UX. See upstream-issues/unslothai-unsloth-5031-disable-auth.md.