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.

FlagDescription
-d, --detachedStart pipeline in background and exit
-e, --executorExecutor: docker, kubernetes (default “docker”)
--imageDefault Docker image (default “alpine:latest”)
--stageRun only jobs in this stage
--env KEY=VALUESet variable (repeatable)
--env-fileLoad variables from env file
--secretsRemote variables: all (project+group+instance), project, none (default “all”)
--refresh-secretsForce refresh cached API variables
--git-strategyclone, fetch, none, remote (default “clone”)
--contextbranch=NAME, merge_request, tag=NAME, env=NAME
--mr-sourceSource branch for merge_request
--mr-targetTarget branch for merge_request
--input KEY=VALUEPipeline input (repeatable)
--inputs-fileLoad inputs from YAML file
--dirtyInclude uncommitted files (default: true)
--no-dirtyOnly use committed code
--reuse-artifactsReuse artifacts from prior run
--simulateEcho commands, produce dummy artifacts
--show-variablesPrint each job’s resolved variables (and rule trace) before it runs
--unmaskWith --show-variables, reveal masked/secret values
--expandWith --show-variables, show full values (default truncates long values)
--all-variablesWith --show-variables, include predefined CI_* variables (hidden by default)
--timeoutOverride job timeout (e.g. 30m, 1h)
--no-registryDisable embedded registry
--registryCustom registry URL
--registry-userContainer registry username
--registry-passwordContainer registry password
--push-throughMirror pushes to upstream registry
--pull-policyDocker image pull policy: always, if-not-present, never
--no-tokenDisable forwarding host token as CI_JOB_TOKEN
--skipSkip a job (treated as success; repeatable)
--no-skipForce-run a normally-skipped job (repeatable)
--no-skip-allDisable all skip rules from config
--manualAuto-run a manual job (repeatable)
--manual-allAuto-run ALL manual jobs
--no-manualDisable manual auto-run
--project-dirMap trigger target to local dir (repeatable)
-p, --pipelineNamed preset from .glciconfig.toml
-w, --watchRe-run on file changes
--debounceDebounce interval (default 500ms)
--on-changeShell command to run when files change (requires –watch)
--on-change-modeHow --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).

FlagDescription
-w, --watchRe-render on file changes
--debounceDebounce interval (default 500ms)
--on-changeShell command to run when files change (requires –watch)
--on-change-modeHow --on-change runs: block (default) or restart (kill & relaunch in background)
--plainDisable colors
--no-dagHide needs annotations
--jsonJSON output
--contextCI context: branch=NAME, merge_request, tag=NAME, env=NAME
--mr-sourceSource branch for merge_request
--mr-targetTarget branch for merge_request
--env KEY=VALUESet variable for rules: evaluation (repeatable)
--env-fileLoad variables from env file
--input KEY=VALUEPipeline input (repeatable)
--inputs-fileLoad inputs from YAML file
-p, --pipelineNamed 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.

FlagDescription
--jobStop specific job

glci log [pipeline-id] [job-name]#

Show job trace logs. Streams live for running jobs.

glci retry [pipeline-id]#

Retry failed jobs.

FlagDescription
--jobRetry specific job

glci jobs#

List parsed pipeline jobs. Applies the same context filtering as glci show. Global flags also apply.

FlagDescription
--stageFilter by stage
--jsonJSON output
--contextCI context: branch=NAME, merge_request, tag=NAME, env=NAME
--mr-sourceSource branch for merge_request
--mr-targetTarget branch for merge_request
--env KEY=VALUESet variable for rules: evaluation (repeatable)
--env-fileLoad variables from env file
--input KEY=VALUEPipeline input (repeatable)
--inputs-fileLoad inputs from YAML file
-p, --pipelineNamed preset
-w, --watchRe-list on file changes
--debounceDebounce interval (default 500ms)
--on-changeShell command to run when files change (requires –watch)
--on-change-modeHow --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.

FlagDescription
--stageFilter by stage
--jsonJSON output
-a, --allInclude predefined CI_* variables (hidden by default)
--unmaskReveal masked/secret values
--expandShow full values (default truncates long values to 512 chars)
--env KEY=VALUESet variable (repeatable)
--env-fileLoad variables from env file
--contextCI context: branch=NAME, merge_request, tag=NAME, env=NAME
--mr-sourceSource branch for merge_request
--mr-targetTarget branch for merge_request
--input KEY=VALUEPipeline input (repeatable)
--inputs-fileLoad inputs from YAML file
-p, --pipelineNamed preset
-w, --watchRe-resolve on file changes
--debounceDebounce interval (default 500ms)
--on-changeShell command to run when files change (requires –watch)
--on-change-modeHow --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.

FlagDescription
-q, --quietExit code only, no output on success
-w, --watchRe-validate on file changes
--debounceDebounce interval (default 500ms)
--on-changeShell command to run when files change (requires –watch)
--on-change-modeHow --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.yml

Both glci lint run from framework1/ and glci lint --file framework1/.gitlab-ci.yml run 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, and doctor.

glci history#

List past pipeline runs.

FlagDescription
--limitMax results (default 20)

glci history show [id]#

Show pipeline details with job list. Defaults to the latest pipeline.

FlagDescription
--plainPlain text output (no colors)
--no-dagHide DAG dependency arrows

glci history clean#

Delete history.

FlagDescription
--keep NKeep last N

glci ps#

List active pipelines and containers.

FlagDescription
-c, --containersShow only glci-managed containers

glci artifacts#

glci artifacts list [pipeline-id]#

FlagDescription
--allAcross all pipelines

glci artifacts download [pipeline-id] <job>#

FlagDescription
--outputOutput path

glci artifacts extract [pipeline-id] <job>#

FlagDescription
--outputOutput directory

glci artifacts inspect [pipeline-id] <job>#

glci artifacts diff <id1> <id2>#

FlagDescription
--jobJob name

glci artifacts delete [pipeline-id] [job]#

FlagDescription
--allAll pipelines
--older-thanDuration (e.g. 7d)

glci releases#

glci releases list [pipeline-id]#

FlagDescription
--allAcross all pipelines

glci releases show [pipeline-id] <tag>#

glci releases download [pipeline-id] <tag> [file]#

FlagDescription
-o, --outputOutput path/directory

glci registry#

Manage the embedded container registry.

glci registry list#

List images stored in the local registry.

FlagDescription
--projectFilter 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.

FlagDescription
--projectOnly 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.

FlagDescription
-p, --portPort to serve on (default 8080)
--hostHost 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.

FlagDescription
--gitlabShow resolved GitLab instance config (URL, token source, project)
--networkShow 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.

FlagDescription
-a, --allRemove everything including registry and history
--forceSkip 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.

FlagDescription
--forceForce kill the daemon immediately

glci daemon logs#

Show daemon log output.

FlagDescription
-F, --followFollow log output in real time (like tail -f)
-n, --linesNumber 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.

FlagDescription
--agentTarget agent(s): claude-code, cursor, windsurf, vscode, gitlab-duo, codex, opencode (comma-separated)
--scopeInstallation 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.

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

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:

FlagDescription
-f, --filePath to CI config file (default “.gitlab-ci.yml”)
--tokenGitLab private token (or set GITLAB_TOKEN env var)
--gitlab-urlGitLab instance URL (or set GITLAB_URL env var)
--projectGitLab project path (e.g. group/subgroup/project)
Esc