Commands
glci#
Launch the interactive TUI. Browse pipeline structure, run jobs, view history. If stdout is not a TTY, prints help.
glci run [job...]#
Run pipeline jobs locally. Job names support glob patterns (* is the only metacharacter). Global flags also apply.
| Flag | Description |
|---|---|
-d, --detached | Start pipeline in background and exit |
-e, --executor | Executor: docker, kubernetes (default “docker”) |
--image | Default Docker image (default “alpine:latest”) |
--stage | Run only jobs in this stage |
--env KEY=VALUE | Set variable (repeatable) |
--env-file | Load variables from env file |
--secrets | Remote variables: all (project+group+instance), project, none (default “all”) |
--refresh-secrets | Force refresh cached API variables |
--git-strategy | clone, fetch, none, remote (default “clone”) |
--context | branch=NAME, merge_request, tag=NAME, env=NAME |
--mr-source | Source branch for merge_request |
--mr-target | Target branch for merge_request |
--input KEY=VALUE | Pipeline input (repeatable) |
--inputs-file | Load inputs from YAML file |
--dirty | Include uncommitted files (default: true) |
--no-dirty | Only use committed code |
--reuse-artifacts | Reuse artifacts from prior run |
--simulate | Echo commands, produce dummy artifacts |
--show-variables | Print each job’s resolved variables (and rule trace) before it runs |
--unmask | With --show-variables, reveal masked/secret values |
--expand | With --show-variables, show full values (default truncates long values) |
--all-variables | With --show-variables, include predefined CI_* variables (hidden by default) |
--timeout | Override job timeout (e.g. 30m, 1h) |
--no-registry | Disable embedded registry |
--registry | Custom registry URL |
--registry-user | Container registry username |
--registry-password | Container registry password |
--push-through | Mirror pushes to upstream registry |
--pull-policy | Docker image pull policy: always, if-not-present, never |
--no-token | Disable forwarding host token as CI_JOB_TOKEN |
--skip | Skip a job (treated as success; repeatable) |
--no-skip | Force-run a normally-skipped job (repeatable) |
--no-skip-all | Disable all skip rules from config |
--manual | Auto-run a manual job (repeatable) |
--manual-all | Auto-run ALL manual jobs |
--no-manual | Disable manual auto-run |
--project-dir | Map trigger target to local dir (repeatable) |
-p, --pipeline | Named preset from .glciconfig.toml |
-w, --watch | Re-run on file changes |
--debounce | Debounce interval (default 500ms) |
--on-change | Shell command to run when files change (requires –watch) |
--on-change-mode | How --on-change runs: block (default) or restart (kill & relaunch in background) |
glci show#
Visualize pipeline without running it. Evaluates rules: using the specified context (default: merge_request).
| Flag | Description |
|---|---|
-w, --watch | Re-render on file changes |
--debounce | Debounce interval (default 500ms) |
--on-change | Shell command to run when files change (requires –watch) |
--on-change-mode | How --on-change runs: block (default) or restart (kill & relaunch in background) |
--plain | Disable colors |
--no-dag | Hide needs annotations |
--json | JSON output |
--context | CI context: branch=NAME, merge_request, tag=NAME, env=NAME |
--mr-source | Source branch for merge_request |
--mr-target | Target branch for merge_request |
--env KEY=VALUE | Set variable for rules: evaluation (repeatable) |
--env-file | Load variables from env file |
--input KEY=VALUE | Pipeline input (repeatable) |
--inputs-file | Load inputs from YAML file |
-p, --pipeline | Named preset |
--env/--env-file let you preview how the pipeline resolves under variable-scoped rules: (e.g. a $DEPLOY_ENV == "prod" gate) without running any jobs — orders of magnitude faster than a real run for debugging rules: changes.
glci stop [pipeline-id]#
Stop running pipelines or individual jobs. If the daemon no longer tracks the pipeline (e.g., after a daemon restart), glci stop <id> falls back to force-removing leftover containers and the pipeline network, then marks the pipeline as canceled in history.
| Flag | Description |
|---|---|
--job | Stop specific job |
glci log [pipeline-id] [job-name]#
Show job trace logs. Streams live for running jobs.
glci retry [pipeline-id]#
Retry failed jobs.
| Flag | Description |
|---|---|
--job | Retry specific job |
glci jobs#
List parsed pipeline jobs. Applies the same context filtering as glci show. Global flags also apply.
| Flag | Description |
|---|---|
--stage | Filter by stage |
--json | JSON output |
--context | CI context: branch=NAME, merge_request, tag=NAME, env=NAME |
--mr-source | Source branch for merge_request |
--mr-target | Target branch for merge_request |
--env KEY=VALUE | Set variable for rules: evaluation (repeatable) |
--env-file | Load variables from env file |
--input KEY=VALUE | Pipeline input (repeatable) |
--inputs-file | Load inputs from YAML file |
-p, --pipeline | Named preset |
-w, --watch | Re-list on file changes |
--debounce | Debounce interval (default 500ms) |
--on-change | Shell command to run when files change (requires –watch) |
--on-change-mode | How --on-change runs: block (default) or restart (kill & relaunch in background) |
glci variables [job...]#
Show the resolved CI/CD variables for each job, with the source of each value, alongside the per-rule evaluation trace — for debugging variable precedence and rules: matching. Aliased as glci vars. Resolves locally without running the pipeline, so jobs excluded by their rules: are still shown (status excluded).
Predefined CI_* variables are hidden by default to keep the focus on the variables you control (job, rules:, global, --env, etc.); use --all to show them. A predefined variable referenced by a rule’s if: is always shown so you can see the value the rule was evaluated against. Does not fetch GitLab API secrets or runtime values — use glci run --show-variables for those. Global flags also apply.
| Flag | Description |
|---|---|
--stage | Filter by stage |
--json | JSON output |
-a, --all | Include predefined CI_* variables (hidden by default) |
--unmask | Reveal masked/secret values |
--expand | Show full values (default truncates long values to 512 chars) |
--env KEY=VALUE | Set variable (repeatable) |
--env-file | Load variables from env file |
--context | CI context: branch=NAME, merge_request, tag=NAME, env=NAME |
--mr-source | Source branch for merge_request |
--mr-target | Target branch for merge_request |
--input KEY=VALUE | Pipeline input (repeatable) |
--inputs-file | Load inputs from YAML file |
-p, --pipeline | Named preset |
-w, --watch | Re-resolve on file changes |
--debounce | Debounce interval (default 500ms) |
--on-change | Shell command to run when files change (requires –watch) |
--on-change-mode | How --on-change runs: block (default) or restart (kill & relaunch in background) |
Sample output:
deploy_prod (stage: deploy) [included, when: on_success]
Rules:
#0 $CI_COMMIT_BRANCH (main) == $CI_DEFAULT_BRANCH (main) → true
Variables:
KEY VALUE SOURCE
CI_COMMIT_BRANCH main predefined
DEPLOY_ENV production rules
GREETING hello global
glci lint#
Validate CI configuration. Parses the full CI file (including include: directives) and checks for structural issues.
| Flag | Description |
|---|---|
-q, --quiet | Exit code only, no output on success |
-w, --watch | Re-validate on file changes |
--debounce | Debounce interval (default 500ms) |
--on-change | Shell command to run when files change (requires –watch) |
--on-change-mode | How --on-change runs: block (default) or restart (kill & relaunch in background) |
Note: Local
include:paths resolve from the repository root, matching GitLab — not from the directory that holds the CI file. A CI file in a subdirectory can therefore reference a file elsewhere in the repo:# framework1/.gitlab-ci.yml include: - local: common/.app-workflow.yml # resolved as <repo-root>/common/.app-workflow.ymlBoth
glci lintrun fromframework1/andglci lint --file framework1/.gitlab-ci.ymlrun from the repo root resolve the include the same way. glci finds the repository root by walking up to the nearest.git; outside a git repository it falls back to the CI file’s own directory. This applies to every command that parses the CI config —lint,run,jobs,show,variables, anddoctor.
glci history#
List past pipeline runs.
| Flag | Description |
|---|---|
--limit | Max results (default 20) |
glci history show [id]#
Show pipeline details with job list. Defaults to the latest pipeline.
| Flag | Description |
|---|---|
--plain | Plain text output (no colors) |
--no-dag | Hide DAG dependency arrows |
glci history clean#
Delete history.
| Flag | Description |
|---|---|
--keep N | Keep last N |
glci ps#
List active pipelines and containers.
| Flag | Description |
|---|---|
-c, --containers | Show only glci-managed containers |
glci artifacts#
glci artifacts list [pipeline-id]#
| Flag | Description |
|---|---|
--all | Across all pipelines |
glci artifacts download [pipeline-id] <job>#
| Flag | Description |
|---|---|
--output | Output path |
glci artifacts extract [pipeline-id] <job>#
| Flag | Description |
|---|---|
--output | Output directory |
glci artifacts inspect [pipeline-id] <job>#
glci artifacts diff <id1> <id2>#
| Flag | Description |
|---|---|
--job | Job name |
glci artifacts delete [pipeline-id] [job]#
| Flag | Description |
|---|---|
--all | All pipelines |
--older-than | Duration (e.g. 7d) |
glci releases#
glci releases list [pipeline-id]#
| Flag | Description |
|---|---|
--all | Across all pipelines |
glci releases show [pipeline-id] <tag>#
glci releases download [pipeline-id] <tag> [file]#
| Flag | Description |
|---|---|
-o, --output | Output path/directory |
glci registry#
Manage the embedded container registry.
glci registry list#
List images stored in the local registry.
| Flag | Description |
|---|---|
--project | Filter by project path |
glci registry pull <image> [prefix]#
Pull an image from the daemon registry into the local container engine (Docker or Podman). An optional prefix retags the image (e.g., local produces local.registry.gitlab.com/...).
glci registry clean#
Remove stored registry blobs.
| Flag | Description |
|---|---|
--project | Only clean specific project’s images |
glci registry stats#
Show registry storage usage (total size, image count, layer count).
glci pages#
Preview GitLab Pages sites from local pipeline runs.
glci pages serve [pipeline-id] [job-name]#
Extract and serve a Pages job’s artifact over HTTP. Pipeline ID defaults to the latest pipeline. Job name defaults to the first Pages-enabled job found (pages: true or pages: { publish: "dir" }). The publish directory within the artifact is served (default public/). If the publish directory is not found, the artifact root is served. If the preferred port is taken, the next available port is chosen automatically.
| Flag | Description |
|---|---|
-p, --port | Port to serve on (default 8080) |
--host | Host to bind to (default 127.0.0.1) |
glci config#
Show effective merged configuration (global ~/.glci/config.toml + project .glciconfig.toml). Running glci config with no subcommand is equivalent to glci config show.
Displays [docker], [runner], [runners.<name>], [skip], and [pipelines.*] sections. Runner configuration including config templates is validated at load time — template syntax errors appear as warnings.
If the project .glciconfig.toml set any global-only key, the ignored-keys warning is printed first, above the configuration sources — those keys are the one case where what you wrote is not what glci uses, so a silently missing section would read as a bug. A [runners.<name>] section whose fields were all stripped is skipped rather than printed as an empty header, and when nothing at all survives you get No configuration set (the project config only set ignored keys — see the warning above).
The [docker] block shows engine, host, and container_socket; a [runners.<name>] block shows engine, docker_host, docker_context, container_socket, config_template (as a line count), config_template_file, tls_cert_path, and tls_verify. engine and the TLS keys are included because they decide which daemon glci talks to and how far it trusts it.
| Flag | Description |
|---|---|
--gitlab | Show resolved GitLab instance config (URL, token source, project) |
--network | Show network, paths, and TLS config with defaults annotated |
--gitlab resolves through the same path as every other command, so --token and --gitlab-url are honored here — checking whether your remedy worked works.
It annotates the URL with the source that won, highest precedence first: (from --gitlab-url flag), (from GITLAB_URL env var), (from project config file), (from global config file), (from git remote), or (default). The two config-file sources are named separately because it changes which tokens glci is willing to send — a URL from the project file only ever gets a token from that same file or --token.
The token is never printed, only its state: token = <set> (from ...) naming the source (--token flag, env var, project config file, global config file, glab credential-helper, or glab CLI config (fallback)), token = <not set>, or — when a token was found but withheld:
token = <withheld>
(url comes from the project config, which travels with the repository,
so only --token or a [gitlab] token in that same file is sent there)
When a project config names both the URL and the host variable whose value is sent there (token = "$FOO"), the variable name is added as a continuation line under token — never its value.
See [gitlab] url in a project config.
glci config show#
Same as glci config – accepts the same --gitlab and --network flags.
glci config init#
Scaffold a starter .glciconfig.toml in the current project. Errors if the file already exists.
glci config edit#
Open the project config in $EDITOR (falls back to $VISUAL). If no project config exists, opens $EDITOR on .glciconfig.toml in the current directory.
glci system#
glci system df#
Show disk usage of all glci resources.
glci system prune#
Remove unused containers, networks, volumes, CI cache.
| Flag | Description |
|---|---|
-a, --all | Remove everything including registry and history |
--force | Skip confirmation prompt |
glci system cache clean#
Wipe CI cache volume.
glci system logs info#
Show log file path and size.
glci system logs clean#
Remove the log file.
glci system engine containers|networks|volumes#
Inspect glci-managed container-engine resources (Docker or Podman). Aliased as glci system docker for backward compatibility.
glci daemon#
glci daemon status#
Show PID, uptime, active pipelines, commit, the container engine, and the endpoint it is driving:
engine: docker
engine endpoint: tcp://build-box:2375 (from env)
The engine endpoint line names where the endpoint was resolved from — config, env, connection, context, or default — including the context/connection name when one was in effect (from context "arch"), and shows (engine default) when no endpoint was resolved and the engine CLI uses its own. Any password in the endpoint’s userinfo is redacted. A daemon built before this field existed reports (unknown — daemon predates this field) rather than a guess.
glci daemon start#
Start the daemon manually.
glci daemon stop#
Graceful shutdown. Waits for running jobs to complete.
| Flag | Description |
|---|---|
--force | Force kill the daemon immediately |
glci daemon logs#
Show daemon log output.
| Flag | Description |
|---|---|
-F, --follow | Follow log output in real time (like tail -f) |
-n, --lines | Number of lines to show (default 50, 0 for all) |
glci skill#
glci skill install#
Download and install the glci skill file for AI coding agents. When run interactively, prompts for agent and scope selection. Supports: Claude Code, Cursor, Windsurf, VS Code (Copilot), GitLab Duo, Codex (OpenAI), OpenCode.
The file is fetched at the commit the binary was built from (with any -dirty suffix trimmed), falling back to main when that ref is unavailable — e.g. an unpushed local commit or an unstamped go install build. The ref used is printed while fetching.
| Flag | Description |
|---|---|
--agent | Target agent(s): claude-code, cursor, windsurf, vscode, gitlab-duo, codex, opencode (comma-separated) |
--scope | Installation scope: project or global |
glci doctor#
Run health checks: container engine, project config, daemon, token, CI config, git. Each check reports pass (✓), fail (✗), or warning (~) with details. Remediation and provenance are printed as an unsymboled → ... continuation line underneath the row they belong to, so a single broken engine does not read as “1 failure + 1 warning”.
Color is applied only when stderr is an interactive terminal and NO_COLOR is unset (its presence is the signal, whatever the value) — doctor output is routinely captured into logs and CI job traces, where escape codes are noise.
Exit status#
glci doctor prints the full report either way, then exits 1 if any check hard-failed and 0 otherwise — so glci doctor && glci run is meaningful in a script.
| Condition | Result |
|---|---|
| Container engine not reachable | ✗ fail — exit 1 |
| Podman API socket not reachable | ✗ fail — exit 1 |
| CI config file not found | ✗ fail — exit 1 |
| CI config does not parse | ✗ fail — exit 1 |
| Not a git repository | ✗ fail — exit 1 |
| Error checking daemon status | ✗ fail — exit 1 |
| Daemon not running | ~ warning — exit 0 |
| No GitLab token (or withheld) | ~ warning — exit 0 |
| Project config set global-only keys | ~ Project config warning — exit 0 |
Engine config drift (daemon started before [docker] engine changed) | ~ Engine config warning — exit 0 |
The warnings are deliberately not failures. The daemon starts automatically on first use, so “not running” is its normal resting state; a token is only needed for remote include: and private registries, and local pipelines run against the embedded mock server without one; and dropped project keys are already neutralized, so the run ahead is safe. Treating any of them as a failure would make every glci doctor && gate refuse to run on a perfectly working setup.
“CI config file not found” and “does not parse” are separate rows because the fixes differ — reporting a missing file as a YAML error sends you hunting through a file that is not there. The not-found case is decided by a stat of the top-level file, so a missing include: local: target still reports as a parse error rather than claiming .gitlab-ci.yml is absent, and it adds a → use -f to point at another file hint.
On macOS/Windows the Podman socket check cannot fail — it reports “cannot verify from host” as a warning, because the socket lives inside the Podman VM (see below). The same is true on Linux when the resolved Podman endpoint is not a local unix:// path: a remote socket cannot be dialed from here either.
“Error checking daemon status” is the failure case of the daemon check — glci could not tell whether a daemon is running (e.g. an unreadable ~/.glci/daemon.pid), which is a broken state rather than the normal “not running” one.
The container-engine check is engine-agnostic: it probes <engine> info (with a bounded timeout so a wedged socket cannot hang glci doctor) and reports the engine version. The active engine (labelled Docker or Podman) is taken from the running daemon when it is up, otherwise from your [docker] engine config.
When Podman is selected, the Docker-compatible API socket is checked separately, because podman info succeeds even when podman system service is not running:
- Linux — glci dials every candidate socket path (an explicit
CONTAINER_HOST, the rootless$XDG_RUNTIME_DIR/podman/podman.sock, and the rootful/run/podman/podman.sock) and reports whichever one is reachable, so a rootless setup is never pointed at a rootful path it doesn’t use. If none respond, it hints how to start the socket (systemctl --user enable --now podman.socketfor rootless,sudo systemctl enable --now podman.socketfor rootful). - Linux with a remote endpoint — when the resolved endpoint (
CONTAINER_HOST, else the defaultpodman system connection) isssh://ortcp://, the socket is on the far side and no local dial can reach it. Rather than fail a healthy remote Podman, the check reports “cannot verify from host” as a warning, exactly as it does on macOS. - macOS / Windows — the socket lives inside the Podman VM and cannot be reached from the host, so the check reports “cannot verify from host” and reminds you to start
podman machine/podman system service.
If Docker is the selected engine but is unreachable, the hint depends on what else is installed: with Podman present, doctor suggests setting [docker] engine = "podman" in ~/.glci/config.toml (and starting its API socket); otherwise it suggests starting Docker (Docker Desktop, colima start, or sudo systemctl start docker).
When a daemon is already running, the check also reports engine-config drift as a warning: the global [docker] engine was changed after the daemon started, so it is not yet in effect. Fix it with glci daemon stop — the daemon re-starts with the new engine on the next command.
Separately, if a project .glciconfig.toml sets any global-only key ([docker] engine/host/container_socket/privileged, [paths] container_builds_dir/container_cache_dir/container_certs_dir, a per-runner engine/docker_host/docker_context/container_socket/tls_cert_path/tls_verify, a widening [token] rule, or a config_template for a runner the global config already templates), those keys are dropped during the merge and named in a warning. Doctor reports them as a ~ Project config row, and suppresses the free-standing stderr line for the duration of the report so it cannot land between two rows and break the alignment.
Other commands print that line instead — glci: warning: .glciconfig.toml: ignoring ... — once per process. It comes from resolving GitLab info or starting a pipeline, so the commands that emit it are glci run, show, jobs, lint, and variables. glci config / glci config show prints it too, first, before any section — otherwise a stripped [docker] host would just have no section and a [runners.x] that set nothing else would vanish with no hint that anything was dropped. When a pipeline starts, the daemon writes the same text to ~/.glci/daemon.log, since it is the process that would have driven the endpoint. See Container-endpoint keys.
The daemon check reports the endpoint the running daemon is driving as Daemon endpoint, and warns when your shell selects a different one (a DOCKER_HOST/CONTAINER_HOST export, an edited [docker] host, or a selection you removed). Applying a new endpoint needs glci daemon stop — glci does not restart a shared daemon over a per-shell variable. When nothing explicit is selected the check says (from the engine's context — not compared), because verifying a context would cost a subprocess per command. It also surfaces the daemon’s endpoint security warning (e.g. a plaintext tcp:// endpoint) and fails the Daemon check outright when the process is alive but its socket does not answer.
glci version#
Show CLI and daemon build commit. Reports a [VERSION MISMATCH] warning if the CLI and daemon were built from different commits.
Global flags#
These flags are available on all commands:
| Flag | Description |
|---|---|
-f, --file | Path to CI config file (default “.gitlab-ci.yml”) |
--token | GitLab private token (or set GITLAB_TOKEN env var) |
--gitlab-url | GitLab instance URL (or set GITLAB_URL env var) |
--project | GitLab project path (e.g. group/subgroup/project) |