Themelio compatibility reference. This page describes the retained Themelio implementation or its historical design. Check the parallel-operation guide before applying it to the current platform.
ADR-0021: Themelio Command-Line Interface
Status: Draft
Date: 2026-07-06
Deciders: TBD
Relates to: ADR-0011 (Human Web UI and Agent Client Access) — the CLI is a new programmatic client alongside the web UI; ADR-0012 (Job and Deployment Management System) and ADR-0013 (actions.yaml Automation System) — the CLI drives and observes the jobs/deployments and actions those ADRs introduced.
Context
Themelio today is reachable only through its Next.js web UI. Machine-learning practitioners, CI pipelines, and agent clients increasingly expect a terminal-driven, scriptable client — the way Hugging Face users reach the Hub through the hf CLI. We want a first-class themelio command-line tool that covers the resource lifecycle the platform already exposes (auth, repositories for models/datasets/spaces, running actions, and observing the resulting jobs and deployments) without inventing new backend architecture.
Current State
- The web service (
services/web) exposes an HTTP API under/api/**for models, datasets, spaces, repos, jobs, deployments, and settings. It backs onto GitLab (GraphQL/REST) and proxies jobs/deployments tok8s-root-actor. - Authentication is a single
PRIVATE-TOKENheader. In the browser flow, NextAuth (OIDC/Keycloak) mints a GitLab impersonation token stored in Valkey keyed by an opaque,httpOnlysession cookie; middleware injects that token asPRIVATE-TOKEN. Users can also mint a personal access token in Settings → Access Tokens viaPOST /api/settings/tokens, fulfilled bygitlab-root-actoragainst GitLab's admin endpoint. - Content (repository files, including large files) lives in GitLab and is transferred over git-HTTPS + LFS. The API's
POST …/commitfile-write endpoints are stubs (they return fabricated commits and persist nothing). - Compute is never created directly: running an
actions.yamlaction (ADR-0013) yields a job (slurm-job) or a deployment (k8s-deployment/k8s-inferenceservice), persisted per ADR-0012. The server validates action parameter values at execution time but performs no structural validation ofactions.yaml, and resolving aref:requires the shipped references that live ink8s-root-actor.
Current Problems
- No terminal/scriptable client. Every operation requires the browser UI; there is no way to script repository, action, or job/deployment workflows, or to drive Themelio from CI or an agent.
- No documented headless authentication path. The browser cookie flow is unusable outside a browser, and no client-facing token model is written down for programmatic use.
- No content-transfer story for a client. With commit endpoints stubbed, a client has no API to push or pull repository bytes.
- No way to validate
actions.yamlbefore running it. Authors only discover structural mistakes when an action fails at execution time.
Requirements
- Authenticate non-interactively (CI) and interactively, using a credential that works for both the web API and git content transfer.
- Cover the existing resource lifecycle: create/fork/list/inspect repositories; run actions; observe and destroy jobs and deployments.
- Be scriptable: machine-readable output and stable exit codes.
- Add the minimum viable backend surface; reuse existing services and semantics.
Decision Drivers
- Familiarity — behave like
hfwhere it fits, so ML users are immediately productive. - Thin client — keep logic and validation on the server; the CLI orchestrates and formats.
- Reuse over rebuild — lean on the existing web API,
actions.yaml, and jobs/deployments rather than new architecture. - One credential — a single token for both API calls and git.
- Scriptability — first-class
--jsonand predictable exit codes.
Considered Options
Option A: A Python themelio CLI over the web API, with git hand-off for content
A standalone Python 3.11+ CLI (themelio, distributed via pipx/uv, built on Typer + httpx) that is a thin client of the web API. Its design rests on five sub-decisions.
-
Authentication — paste an
api-scoped GitLab PAT. The user creates a personal access token in Settings → Access Tokens with the "Full API Access" (api) scope and pastes it intothemelio auth login(or suppliesTHEMELIO_TOKEN/--tokenfor CI). Oneapi-scoped token covers everything, because GitLab'sapiscope also authorizes git push/pull over HTTPS. To enable this, the Settings token UI was extended to offer theapiscope (previously git read/write only). The CLI stores the token in the OS keyring by default (falling back to~/.themelio/config, mode600) and verifies it viaGET /api/whoami-v2. The host defaults tohttps://dev.themelio.pharos.grnet.grand is confirmed at login.Two alternatives were weighed and rejected: reusing the browser
sessioncookie (it is opaque,httpOnly, browser-tethered, revoked on browser sign-out, and meaningless to GitLab, so it cannot authenticate git); and a browser OIDC device-login flow (nicer UX but requires new backend endpoints — deferred as a future enhancement, not v1). -
Content transfer — hand off to the user's
git. Because the commit endpoints are stubs and content lives in GitLab, the CLI moves no bytes itself.themelio git-setupprints (or, with--apply, writes) a git credential-helper configuration sogit clone/git pushover HTTPS transparently use the stored token via a hiddenthemelio git-credentialsubcommand.<type> <ns/repo> downloadanduploadprint the exactgit/git-lfscommands for a repo rather than executing them, keeping the CLI thin and free of a git runtime dependency. -
Uniform command grammar. Repo-scoped commands read
themelio <type> <ns/repo> <verb>(the repo reference immediately after the type). Every resource type (models,datasets,spaces,repos) exposes the same core verbs —create,fork,ls,info,card,settings,ls-files,download,upload— with no type-specific verbs. -
All compute flows through actions.
models,spaces, andreposcarry anactionssubgroup;<type> <ns/repo> actions runis the create-verb that yields a job or a deployment.jobsanddeploymentsare observe-only (ls,get,logs,wait,destroy). This mirrors ADR-0012/0013 exactly: there are no ad-hoc "run a container" or per-type "deploy" verbs. -
A new server-side validation endpoint.
<type> actions validateposts a localactions.yamlto a newPOST /api/actions/validateendpoint. It reuses the web executor's existing validation logic (action-loader.ts+action-parameters.ts) and delegatesref:resolution tok8s-root-actor(populateRefs), so the CLI and the web authoring UI share one source of truth and the CLI never reimplements rules it cannot fully evaluate locally.
Pros:
- Familiar,
hf-like ergonomics with a uniform, predictable grammar. - A single
api-scoped token drives both the API and git; no bespoke credential store or new auth backend. - Thin client: validation and orchestration stay on the server; the CLI formats and hands off.
- Reuses
actions.yaml, jobs, and deployments unchanged; only one small additive endpoint. - Python +
pipx/uvmatches the ML audience's tooling.
Cons:
- Content transfer depends on the user having
git/git-lfsinstalled and configured (mitigated bygit-setup). - Pasting a PAT is less slick than a browser device-login (deferred).
- Some
hf-familiar conveniences are intentionally absent (no local content cache; nomove/branch/tag/delete-files) because the backend does not support them yet. - One new endpoint (
POST /api/actions/validate) must be built beforeactions validateworks.
Decision
We will build Option A: a Python themelio CLI that is a thin client of the web API, authenticated by a pasted api-scoped GitLab personal access token, using a uniform themelio <type> <ns/repo> <verb> grammar, driving compute exclusively through actions.yaml (yielding observe-only jobs and deployments), and handing repository content transfer off to the user's own git/git-lfs (configured via themelio git-setup). We will add one backend endpoint, POST /api/actions/validate, to back actions validate. The Settings token UI has already been extended to offer the api scope required by the CLI.
See also: DD-0021: Themelio CLI — Implementation
Consequences
Positive:
- Themelio gains a scriptable, CI- and agent-friendly client without new architecture.
- One credential (
apiPAT) works across the web API and git; keyring storage by default. - The action-driven command model keeps the CLI and platform semantics aligned (ADR-0012/0013), avoiding a divergent "run" surface.
- Server-side
actions.yamlvalidation benefits the web authoring UI too.
Negative:
- Users must have
git/git-lfsavailable for content transfer. - Interactive login is a manual copy-paste until (and unless) a device-login flow is built.
- The CLI cannot offer repository delete, file-level commits, branches, or tags until the corresponding endpoints exist.
Neutral:
- The CLI is a separate deliverable (its own Python package), not part of the pnpm monorepo build.
- Jobs/deployments are addressed by id within a repo scope, so those commands take
--repo.
Migration
No migration of existing infrastructure is required. The work is additive: a new client package, one new additive endpoint (POST /api/actions/validate), and an already-shipped, backward-compatible addition of the api scope option to the Settings token UI. No data stores, schemas, or existing endpoints change.
Open Questions
- A browser device-login flow (reusing OIDC + impersonation-token machinery to remove the copy-paste step) is a candidate future enhancement, out of scope for v1.
References
- ADR-0011: Human Web UI and Agent Client Access
- ADR-0012: Job and Deployment Management System
- ADR-0013: actions.yaml Automation System
- DD-0021: Themelio CLI — Implementation
- Full command specification:
plans/themelio-cli/SPEC.md - Hugging Face
hfCLI — prior art - git credential helper protocol
Page source
Source snapshot · Revision f928834c8.