CLI
LabPod ships as a single binary with four command surfaces:
labpod server- starts the HTTP server.labpod admin <subcommand>- bootstrap and break-glass operations.labpod env [--all]- prints resolved environment variable settings for this host; see Environment variables.labpod whoami,labpod servers,labpod ws,labpod template,labpod image,labpod fs,labpod token,labpod api, andlabpod skill- client commands that talk to the LabPod service running on the same host. See Client commands below.
labpod --version # print build SHAlabpod --help # print usageDatabase path resolution
Section titled “Database path resolution”Every command that opens SQLite resolves the database path in this order:
- CLI
--db <path>(placed after the subcommand) LABPOD_DBenvironment variable in the current processLABPOD_DBauto-loaded from/etc/labpod/labpod.envlabpod.dbin the current working directory
For installed admin commands, use sudo on sudo-based hosts. On Rocky/RHEL systems where you
usually work in a root shell, use the root-shell tab instead:
sudo labpod admin --db /var/lib/labpod/labpod.db list-users# or:sudo labpod admin list-users # auto-reads /etc/labpod/labpod.env# Run these as rootlabpod admin --db /var/lib/labpod/labpod.db list-users# or:labpod admin list-users # auto-reads /etc/labpod/labpod.envCheck which path a command would use:
labpod admin db-pathsudo labpod admin db-path# Run these as rootlabpod admin db-pathlabpod server
Section titled “labpod server”labpod server [--db <path>] [--port <port>] [--dev]| Flag | Default | Notes |
|---|---|---|
--db <path> | From env / labpod.db | Override the database path |
--port <port> | 24680 | Override LABPOD_PORT |
--dev | off | Enable localhost CORS, ephemeral JWT secret |
The installed systemd service runs:
/usr/local/bin/labpod serverConfiguration comes from /etc/labpod/labpod.env. See
Environment variables for the full list.
Client commands
Section titled “Client commands”Client commands run only on the LabPod host, through the installed /usr/local/bin/labpod.
Run them as a regular Linux user, without sudo - there is no login step. The CLI connects to a
root-owned Unix socket, where the server reads your Linux UID from the kernel and maps it to your
LabPod account. There is no --server URL, no saved alias, no password, session file, PAT, or TLS
option to supply - a remote server URL is rejected as a usage error. Work with a LabPod server on
another host from a browser or LabPod Connect instead.
Who am I, and what can this host build?
Section titled “Who am I, and what can this host build?”labpod whoamilabpod servers hardwarewhoami shows the Linux account the socket authenticated. If that account exits with code 3,
either it has no LabPod account yet or its account setup needs an administrator’s attention - there
is no client-side account-enable command. servers hardware reports this host’s NVIDIA driver,
maximum CUDA runtime, and each GPU’s model/VRAM/compute capability - pair it with labpod ws capacity (your current quota and free headroom) before creating a GPU workspace.
Workspaces
Section titled “Workspaces”labpod ws listlabpod ws capacitylabpod ws recommend --template tmpl-pytorch-jupyterlab --gpu-use-case mediumlabpod ws create --template tmpl-pytorch-jupyterlab --name train1 --gpu-count 1labpod ws setup --template tmpl-pytorch-jupyterlab --name train1 # prepare image + create, then stoplabpod ws start <workspace-id>labpod ws logs <workspace-id> --tail 200labpod ws logs <workspace-id> --launcher jupyter --tail 200 # a launcher's captured stdout/stderrlabpod ws edit <workspace-id> --file patch.json # stopped workspace onlylabpod ws rename <workspace-id> --name train2labpod ws launchers <workspace-id>labpod ws launcher start <workspace-id> jupyterlabpod ws launcher stop <workspace-id> jupyterlabpod ws ports <workspace-id>labpod ws port add <workspace-id> streamlit --container-port <free-slot>labpod ws monitor <workspace-id> # one-shot CPU/MEM/GPU/process snapshotlabpod ws stop <workspace-id>labpod ws delete <workspace-id> --yesws create sends only the resource flags you set, so the template defaults fill in the rest.
ws recommend asks the server for the same safe defaults the web composer shows, without reserving
anything. ws setup is the durable prepare-and-create path: it downloads or builds a missing image
and creates the workspace as one operation, but still does not start it or launch an app - follow it
with ws start and ws launcher start. Run labpod ws --help for the complete flag list.
ws logs without --launcher shows the container’s raw stdout/stderr. With --launcher <name> it
shows the bounded, persistent output LabPod captured for that configured app (the same feed as the
workspace page’s View app logs), which stays readable even while the workspace is stopped;
manually started processes and extra-app ports are not captured this way.
To run one non-interactive command in a running workspace you own, put the container command
after --:
labpod ws exec <workspace-id> -- nvidia-smi -Llabpod ws exec <workspace-id> --timeout 600 -- bash train_prep.shWorkspace execution is owner-only, including for administrators. It has a 300-second default
timeout, a 600-second maximum, and a 256 KiB output limit. Detach long jobs with nohup or
setsid, then inspect their output with ws logs or labpod fs read.
Templates and images
Section titled “Templates and images”labpod template listlabpod template get <template-id>labpod template dockerfile <template-id> # print a clone/import's Dockerfilelabpod template clone tmpl-pytorch-jupyterlab --name my-copylabpod template export tmpl-pytorch-jupyterlab --out bundle.tarlabpod template import bundle.tar --build-later
labpod image listlabpod image allowlistlabpod image status <template-id>labpod image pull <template-id> --waitlabpod image build <template-id> --waitlabpod image buildslabpod image overviewlabpod image prune --yesUse template create --file <spec.json|-> and template edit <id> --file <patch.json|-> when
automating template definitions; - reads JSON from standard input. Imported templates land
disabled for review. Dockerfile-backed clones and imports must be built before being enabled, and
template dockerfile <id> --set --file <path> replaces the Dockerfile in a clone’s own editable
build context (a global template’s Dockerfile is read-only - clone it first).
Starting a workspace never pulls or builds a missing image. Use image pull for a registry image
or image build for a Dockerfile-backed template, then start the workspace again. image pull and
image build operate in your own rootless Podman store: LabPod has no shared or root-owned
image cache, so every account pulls or builds its own copy under the registry and terms rules the
administrator set.
Published managed recipes pull normally and, if that download fails, you may explicitly build the
unchanged embedded Dockerfile as a private fallback under the same tested image reference:
labpod image build <template-id> --wait covers this case too, not just Dockerfile templates you
own. Local-only managed recipes such as MATLAB and MS Code Serve-Web are built directly in your own
store: the administrator enables the recipe, and each user builds it in their own account with
labpod image build.
LabPod has no root/shared image scope and no user-to-root promotion request. Root configures registry policy but cannot use the image list, pull, build, delete, or prune commands. These workflows will not be supported for simplicity; publish a reusable image through an external registry instead.
File transfer (labpod fs)
Section titled “File transfer (labpod fs)”Move files between the local Linux account and the server’s file roots - useful for staging inputs
or collecting results from a script or agent without going through the browser file manager.
Addresses are <root>/<path>; labpod fs roots lists the root ids you can address (work maps to
/work inside your workspaces).
labpod fs rootslabpod fs ls work/exp1labpod fs upload dataset.tar.gz work/exp1/ # trailing "/" keeps the local file namelabpod fs download work/exp1/results.ckpt # refuses to overwrite without --forcelabpod fs archive work/exp1 exp1.tar.gz # a directory as tar.gzlabpod fs rm work/exp1 --recursive --yesdownload and archive write local files and, like template export, do not accept --json.
Every fs operation is audited server-side.
Personal access tokens
Section titled “Personal access tokens”Personal access tokens (PATs) are for a separate, deliberate integration that calls the LabPod
HTTP API from another host - the host-local CLI itself never uses or stores one. Create, list, and
revoke them with labpod token:
labpod token create --name ci-runner # prints the token ONCElabpod token create --name nightly --expires 30 # custom expiry in days (1-365; default 90)labpod token listlabpod token revoke <token-id>A new token’s secret is printed once at creation and is never stored on the server, so copy it
right away. Use it from the calling script or agent, not from labpod:
curl -H "Authorization: Bearer labpod_pat_..." https://lab-gpu.example.local/api/workspacesA token carries the same permissions as the user who created it - it drives that user’s own workspaces, templates, and images, and never administrator operations. A PAT cannot mint or revoke tokens; issuing, listing, and revoking always authenticates as the signed-in browser session or the host-local socket itself.
You can also review and revoke your tokens in the browser under Settings → API tokens, which flags any token expiring within seven days. Creating a token is CLI-only, because the secret is shown a single time and never persisted.
Raw API passthrough
Section titled “Raw API passthrough”labpod api GET /api/usage/melabpod api PATCH /api/users/kim --body '{"display_name":"Kim"}'labpod api POST /api/workspaces --body @create.jsonlabpod api <METHOD> <path> sends one peer-authenticated request to a supported /api/* endpoint
and prints the raw response - the escape hatch for anything without a dedicated ws/template/
image wrapper. There are no confirmation prompts, so a raw DELETE deletes immediately.
Streaming endpoints (terminal, live monitor/event streams) are refused; use the --wait wrappers
and ws monitor instead. It cannot bootstrap credentials: POST /api/auth/login and password
changes are rejected on this socket.
JSON output and exit codes
Section titled “JSON output and exit codes”Add --json to a client command when a script needs the raw API response:
labpod ws list --jsonlabpod ws create --template tmpl-pytorch-jupyterlab --jsontemplate export, fs download, and fs archive are the exceptions, because each writes a local
file instead of printing JSON. Exit codes are 0 for success, 1 for an API or network error (or
an aborted confirmation), 2 for invalid command usage, and 3 when the current Linux account has
no LabPod account or its account setup is incomplete.
Installing the CLI agent skill
Section titled “Installing the CLI agent skill”labpod skill install is local-only: it installs the CLI-usage skill embedded in the binary into an
LLM agent’s skills directory, without contacting the server.
labpod skill install --agent claude # -> ${CLAUDE_CONFIG_DIR:-~/.claude}/skillslabpod skill install --agent codex # -> ${CODEX_HOME:-~/.codex}/skillslabpod skill install --path /path/to/skillsExactly one of --agent or --path is required, and it refuses to overwrite an existing skill
unless you add --force.
labpod admin
Section titled “labpod admin”labpod admin [--db <path>] <subcommand> [args]| Subcommand | What it does |
|---|---|
migrate | Apply any pending database schema migrations (idempotent) |
create-user <name> | Create a LabPod account; provisions Linux account if absent |
set-password <name> | Rotate the LabPod password (DB only, not the Linux password) |
revoke-tokens <name> | Revoke all of a user’s API tokens (break-glass; a password reset also does this) |
list-users | Print all users with their superuser flag and PROVISIONING_CLEANUP_REQUIRED status |
db-path | Print the resolved database path for this invocation |
doctor | Check host prerequisites and report what to fix |
tls-fingerprint | Print SHA-256 fingerprint of the serving TLS certificate |
update <status|check|apply> | Show, refresh, or apply the latest LabPod release |
backup --out <path> | One-shot snapshot to an explicit file |
backup [--dir <dir>] --retention <N> | Timestamped snapshot in --dir or the configured backup directory; prune to newest N |
checkpoint | Flush the offline WAL and close SQLite sidecars (stop labpod and backups first) |
restore <path> [--yes] | Copy a snapshot onto the live DB (stop service first) |
rollback list [--json] | List the retained pre-upgrade recovery sets and whether each one can be applied |
rollback apply <recovery-id> --yes | Restore a retained set’s binary, application files, and paired database |
template import <path.tar> (--owner <server_userid> | --global) | Import a host-local template bundle, disabled for review |
license show | Show the resolved trial or signed-license entitlement |
license request | Print the host activation request code |
license verify <file> | Validate a license file without installing it |
license install <file> | Verify and install a license file to LABPOD_LICENSE_PATH |
create-user and set-password read the password interactively or from stdin when piped:
New and changed LabPod passwords are normalized before validation. Regular accounts require 8–64
Unicode characters; root and superuser accounts require 12–64. Common passwords and easy
username or labpod derivatives are rejected, but there is no required mix of character classes.
Existing passwords are not invalidated by an upgrade.
The examples below use sudo for Ubuntu-style administration. If you are already in a root shell,
as is common on Rocky/RHEL systems, omit sudo.
# Interactivesudo labpod admin set-password alice
# Piped (automation)printf '%s\n' 'new-password' | sudo labpod admin --db /var/lib/labpod/labpod.db set-password alice# Run these as root# Interactivelabpod admin set-password alice
# Piped (automation)printf '%s\n' 'new-password' | labpod admin --db /var/lib/labpod/labpod.db set-password aliceLicense commands
Section titled “License commands”Without an installed signed license, LabPod runs under the built-in 90-day trial. License files are installed locally with the admin CLI:
sudo labpod admin license showsudo labpod admin license requestsudo labpod admin license verify ./license.licsudo labpod admin license install ./license.lic# Run these as rootlabpod admin license showlabpod admin license requestlabpod admin license verify ./license.liclabpod admin license install ./license.licThe shipped binary handles local request, verification, installation, and status display.
Template import command
Section titled “Template import command”Use this when a bundle already exists on the LabPod host and you want to import it without going through the browser upload flow:
sudo labpod admin template import ./template.tar --globalsudo labpod admin template import ./template.tar --owner alice# Run these as rootlabpod admin template import ./template.tar --globallabpod admin template import ./template.tar --owner alice--global creates a managed template visible to everyone after review. --owner creates a
private template for that Linux-backed LabPod user. Imported templates are disabled by default.
Dockerfile bundles are not supported by the CLI because they require an image build. Import those
from the Workspace templates admin area (/admin/templates) instead.
Common flows
Section titled “Common flows”Fresh production bootstrap:
sudo labpod admin --db /var/lib/labpod/labpod.db migratesudo labpod admin --db /var/lib/labpod/labpod.db set-password rootsudo systemctl enable --now labpod# Run these as rootlabpod admin --db /var/lib/labpod/labpod.db migratelabpod admin --db /var/lib/labpod/labpod.db set-password rootsystemctl enable --now labpodInspect the running service:
systemctl status labpodjournalctl -u labpod -fcurl http://127.0.0.1:24680/api/healthcurl http://127.0.0.1:24680/api/versionsudo labpod admin doctor# Run these as rootsystemctl status labpodjournalctl -u labpod -fcurl http://127.0.0.1:24680/api/healthcurl http://127.0.0.1:24680/api/versionlabpod admin doctorSee Environment variables and Runtime settings.