Running Pipelines
glci run executes CI jobs locally via a background daemon that survives terminal disconnection.
Basic usage#
glci run # run everything
glci run lint test # run specific jobs
glci run --stage build # run all jobs in a stage
glci run -d build-job # detached: start in background, exit immediately
In a terminal, glci run shows a live pipeline graph; press Enter on a job to open its log. The
graph pane supports / job-name search (see
Searching the pipeline graph)
and the log view supports follow mode, w line wrap, ←→ panning, plus / search with n/N
match navigation (see
Log view keys).
Job selection#
# Glob patterns (only * is a metacharacter)
glci run 'qa:*' # all qa: jobs
glci run 'static-analysis *' # all static-analysis shards
glci run rubocop 'lint-*' # mix exact and glob
Skipping and manual jobs#
glci run --skip slow-integration # skip a job (treated as success)
glci run --no-skip deploy-canary # force-run a normally-skipped job
glci run --no-skip-all # disable ALL skip rules
glci run --manual deploy-staging # auto-run a specific manual job
glci run --manual-all # auto-run ALL manual jobs
glci run --no-manual # disable manual auto-run
Skip rules can be configured permanently in .glciconfig.toml:
[skip]
jobs = ["slow-integration"]
job_patterns = [".*windows.*"]
stages = ["deploy"]
Dirty mode#
By default, uncommitted and untracked files are included in the pipeline (respects .gitignore). Use --no-dirty to only use committed code.
Simulation mode#
Replace all scripts with echo commands. Produces dummy artifacts so you can validate pipeline structure and artifact flow in seconds:
glci run --simulate
Artifact reuse#
Skip upstream jobs when their artifacts exist from a prior run – useful for iterating on a single failing job:
glci run --reuse-artifacts test-job
Cross-project triggers#
Map trigger: project: targets to local directories:
glci run --project-dir group/other-project=../other-project
Or in .glciconfig.toml:
[projects."group/other-project"]
dir = "../other-project"
branch = "main"
Watch mode#
glci run --watch automatically re-runs the pipeline when source files change. The watcher monitors the entire project directory, respects .gitignore patterns, and debounces rapid edits.
glci run --watch # re-run full pipeline on changes
glci run --watch test-job # re-run specific job on changes
glci run --watch --debounce 1s # custom debounce interval
glci run --watch --on-change 'make lint' # run a hook before re-running
The --on-change flag runs a shell command each time changes are detected, before the pipeline re-executes. The command receives GLCI_CHANGED_FILES in its environment (newline-separated list of changed paths).
--on-change-mode controls how that command runs:
block(default) — run the command synchronously and wait for it to exit before re-running. Best for short hooks like linters or notifications.restart— kill the previously launched process and relaunch it in the background without waiting. Best for long-running processes such as servers. On each change glci sendsSIGTERMto the process group (escalating toSIGKILLafter 3s), then starts a fresh instance; the final instance is terminated when you stop watching.
# Regenerate Pages on every change while keeping a preview server alive
glci run --watch pages --on-change 'glci pages serve' --on-change-mode restart
Watch mode is also available on glci show, glci lint, glci jobs, and glci merged:
glci show --watch # live pipeline visualization
glci lint --watch # continuous validation
glci jobs --watch --json # live job list as JSON
glci merged --watch # live fully-resolved config
Concurrent runs#
If you start glci run while another pipeline is already being prepared for the same project directory, the new request automatically queues behind the in-progress preparation. The CLI and TUI display “Waiting for pipeline preparation to finish…” while queued. Up to 3 requests can queue per directory; additional requests are rejected. Press Ctrl+C to abort the wait at any time.
Tolerated failures#
allow_failure is a property of the job, not of the kind of failure — exactly as it is on GitLab. A job that declares allow_failure: true may fail for any reason without sinking the pipeline: a non-zero script exit, a job timeout (which is also how glci surfaces a runner that never picked the job up), or a runner that went silent mid-job. Jobs declaring allow_failure: true show the ⚠ marker in the pipeline view, and a tolerated failure leaves the run’s exit code at 0.
flaky-integration:
allow_failure: true
script:
- ./flaky.sh
The mapping form is different, and matches GitLab: allow_failure:exit_codes tolerates a job only when it reported one of the listed exit codes. A job that failed without reporting one — a timeout, or a runner system failure — is never tolerated by an exit_codes list, and allow_failure: {} with no exit codes tolerates nothing at all.
tolerate-137:
# Tolerated only when the script itself exits 137.
allow_failure:
exit_codes:
- 137
script:
- ./maybe-oom.sh
As on GitLab, rules:allow_failure replaces the job-level keyword outright, including any exit_codes list it declared. The same goes for an allow_failure override in a .glciconfig.toml job section.
The effective value — the one the pipeline’s verdict used — is what a terminal job_status event carries under --json, and what decides whether the JUnit report records the job as skipped. See Structured output.
Trigger jobs (trigger:, including cross-project ones) run no script and so never report an exit code: only the boolean form can tolerate them. See Cross-project pipelines.
Two failures are never tolerated, whatever the job declared:
- A cancelled run. Cancelling with
glci stopor a second Ctrl+C stops the pipeline rather than failing it; the run is recorded as canceled and never reports a pass. Cancelling a single job (glci stop <pipeline> --job <name>, or the TUI’s cancel key) leaves the run going, and that job is tolerated like any other failure — as GitLab does. - A glci-side error, such as failing to queue the job on the embedded mock server. The job never ran, so
allow_failurehas nothing to say about it, and the run fails with the error rather than reporting a green pipeline for a glci malfunction.
Ctrl+C behavior#
In attached mode (the default):
- First Ctrl+C: detaches from the pipeline. Jobs continue in the background. Re-attach with
glci logor cancel withglci stop. Re-attaching replays what you missed while detached — in full for a named job, from the daemon’s capped event buffer otherwise. See Viewing logs. - Second Ctrl+C: cancels the pipeline immediately.
Flags reference#
| Flag | Description |
|---|---|
-d, --detached | Start pipeline in background and exit |
-e, --executor | Executor: docker, kubernetes (default “docker”) |
-f, --file | Path to CI config file (default “.gitlab-ci.yml”) |
--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 | Fetch remote variables: all, project, or none (default “all”) |
--refresh-secrets | Force refresh cached API variables |
--git-strategy | Source code strategy: clone, fetch, none, remote (default “clone”) |
--context | CI context: branch=NAME, merge_request, tag=NAME, env=NAME, or preset name |
--mr-source | Source branch for merge_request context |
--mr-target | Target branch for merge_request context |
--input KEY=VALUE | Set pipeline input (repeatable) |
--inputs-file | Load pipeline inputs from YAML file |
--dirty | Include uncommitted files (default: true) |
--no-dirty | Disable dirty mode |
--reuse-artifacts | Skip upstream deps when their artifacts exist |
--simulate | Echo commands without executing |
--timeout | Override job timeout (e.g. 30m, 1h) |
--no-registry | Disable embedded container registry |
--registry | Custom container 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 (default “if-not-present”) |
--token | GitLab private token |
--gitlab-url | GitLab instance URL |
--project | GitLab project path |
--no-token | Disable forwarding host GitLab 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 |
--manual | Auto-run a manual job (repeatable) |
--manual-all | Auto-run ALL manual jobs |
--no-manual | Disable manual auto-run |
--project-dir | Map a project path to a local dir, for cross-project triggers and submodules (repeatable) |
--json | Emit line-delimited JSON events on stdout instead of human output |
--json-logs | With --json, include job trace output as job_log events |
--report FILE | Write the run’s result report to FILE when the pipeline finishes |
--report-format | Format for --report: junit (default) or json |
-p, --pipeline | Named pipeline preset from .glciconfig.toml |
-w, --watch | Re-run on file changes |
--debounce | Debounce interval for watch mode (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) |
Driving glci from a script, a CI job or an editor integration? Use --json and
--report rather than parsing the terminal output — see
Structured Output.