Skip to content

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, and labpod skill - client commands that talk to the LabPod service running on the same host. See Client commands below.
Terminal window
labpod --version # print build SHA
labpod --help # print usage

Every command that opens SQLite resolves the database path in this order:

  1. CLI --db <path> (placed after the subcommand)
  2. LABPOD_DB environment variable in the current process
  3. LABPOD_DB auto-loaded from /etc/labpod/labpod.env
  4. labpod.db in 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:

Terminal window
sudo labpod admin --db /var/lib/labpod/labpod.db list-users
# or:
sudo labpod admin list-users # auto-reads /etc/labpod/labpod.env
Terminal window
# Run these as root
labpod admin --db /var/lib/labpod/labpod.db list-users
# or:
labpod admin list-users # auto-reads /etc/labpod/labpod.env

Check which path a command would use:

Terminal window
labpod admin db-path
sudo labpod admin db-path
Terminal window
# Run these as root
labpod admin db-path
Terminal window
labpod server [--db <path>] [--port <port>] [--dev]
FlagDefaultNotes
--db <path>From env / labpod.dbOverride the database path
--port <port>24680Override LABPOD_PORT
--devoffEnable localhost CORS, ephemeral JWT secret

The installed systemd service runs:

/usr/local/bin/labpod server

Configuration comes from /etc/labpod/labpod.env. See Environment variables for the full list.

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.

Terminal window
labpod whoami
labpod servers hardware

whoami 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.

Terminal window
labpod ws list
labpod ws capacity
labpod ws recommend --template tmpl-pytorch-jupyterlab --gpu-use-case medium
labpod ws create --template tmpl-pytorch-jupyterlab --name train1 --gpu-count 1
labpod ws setup --template tmpl-pytorch-jupyterlab --name train1 # prepare image + create, then stop
labpod ws start <workspace-id>
labpod ws logs <workspace-id> --tail 200
labpod ws logs <workspace-id> --launcher jupyter --tail 200 # a launcher's captured stdout/stderr
labpod ws edit <workspace-id> --file patch.json # stopped workspace only
labpod ws rename <workspace-id> --name train2
labpod ws launchers <workspace-id>
labpod ws launcher start <workspace-id> jupyter
labpod ws launcher stop <workspace-id> jupyter
labpod 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 snapshot
labpod ws stop <workspace-id>
labpod ws delete <workspace-id> --yes

ws 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 --:

Terminal window
labpod ws exec <workspace-id> -- nvidia-smi -L
labpod ws exec <workspace-id> --timeout 600 -- bash train_prep.sh

Workspace 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.

Terminal window
labpod template list
labpod template get <template-id>
labpod template dockerfile <template-id> # print a clone/import's Dockerfile
labpod template clone tmpl-pytorch-jupyterlab --name my-copy
labpod template export tmpl-pytorch-jupyterlab --out bundle.tar
labpod template import bundle.tar --build-later
labpod image list
labpod image allowlist
labpod image status <template-id>
labpod image pull <template-id> --wait
labpod image build <template-id> --wait
labpod image builds
labpod image overview
labpod image prune --yes

Use 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.

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).

Terminal window
labpod fs roots
labpod fs ls work/exp1
labpod fs upload dataset.tar.gz work/exp1/ # trailing "/" keeps the local file name
labpod fs download work/exp1/results.ckpt # refuses to overwrite without --force
labpod fs archive work/exp1 exp1.tar.gz # a directory as tar.gz
labpod fs rm work/exp1 --recursive --yes

download and archive write local files and, like template export, do not accept --json. Every fs operation is audited server-side.

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:

Terminal window
labpod token create --name ci-runner # prints the token ONCE
labpod token create --name nightly --expires 30 # custom expiry in days (1-365; default 90)
labpod token list
labpod 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:

Terminal window
curl -H "Authorization: Bearer labpod_pat_..." https://lab-gpu.example.local/api/workspaces

A 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.

Terminal window
labpod api GET /api/usage/me
labpod api PATCH /api/users/kim --body '{"display_name":"Kim"}'
labpod api POST /api/workspaces --body @create.json

labpod 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.

Add --json to a client command when a script needs the raw API response:

Terminal window
labpod ws list --json
labpod ws create --template tmpl-pytorch-jupyterlab --json

template 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.

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.

Terminal window
labpod skill install --agent claude # -> ${CLAUDE_CONFIG_DIR:-~/.claude}/skills
labpod skill install --agent codex # -> ${CODEX_HOME:-~/.codex}/skills
labpod skill install --path /path/to/skills

Exactly one of --agent or --path is required, and it refuses to overwrite an existing skill unless you add --force.

Terminal window
labpod admin [--db <path>] <subcommand> [args]
SubcommandWhat it does
migrateApply 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-usersPrint all users with their superuser flag and PROVISIONING_CLEANUP_REQUIRED status
db-pathPrint the resolved database path for this invocation
doctorCheck host prerequisites and report what to fix
tls-fingerprintPrint 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
checkpointFlush 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> --yesRestore 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 showShow the resolved trial or signed-license entitlement
license requestPrint 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.

Terminal window
# Interactive
sudo labpod admin set-password alice
# Piped (automation)
printf '%s\n' 'new-password' | sudo labpod admin --db /var/lib/labpod/labpod.db set-password alice
Terminal window
# Run these as root
# Interactive
labpod admin set-password alice
# Piped (automation)
printf '%s\n' 'new-password' | labpod admin --db /var/lib/labpod/labpod.db set-password alice

Without an installed signed license, LabPod runs under the built-in 90-day trial. License files are installed locally with the admin CLI:

Terminal window
sudo labpod admin license show
sudo labpod admin license request
sudo labpod admin license verify ./license.lic
sudo labpod admin license install ./license.lic
Terminal window
# Run these as root
labpod admin license show
labpod admin license request
labpod admin license verify ./license.lic
labpod admin license install ./license.lic

The shipped binary handles local request, verification, installation, and status display.

Use this when a bundle already exists on the LabPod host and you want to import it without going through the browser upload flow:

Terminal window
sudo labpod admin template import ./template.tar --global
sudo labpod admin template import ./template.tar --owner alice
Terminal window
# Run these as root
labpod admin template import ./template.tar --global
labpod 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.

Fresh production bootstrap:

Terminal window
sudo labpod admin --db /var/lib/labpod/labpod.db migrate
sudo labpod admin --db /var/lib/labpod/labpod.db set-password root
sudo systemctl enable --now labpod
Terminal window
# Run these as root
labpod admin --db /var/lib/labpod/labpod.db migrate
labpod admin --db /var/lib/labpod/labpod.db set-password root
systemctl enable --now labpod

Inspect the running service:

Terminal window
systemctl status labpod
journalctl -u labpod -f
curl http://127.0.0.1:24680/api/health
curl http://127.0.0.1:24680/api/version
sudo labpod admin doctor
Terminal window
# Run these as root
systemctl status labpod
journalctl -u labpod -f
curl http://127.0.0.1:24680/api/health
curl http://127.0.0.1:24680/api/version
labpod admin doctor

See Environment variables and Runtime settings.