Environment Variables

glci reads environment variables to control its own behavior and sets CI/CD variables inside job containers to emulate GitLab CI. This page covers both categories.

glci control variables#

These variables configure glci itself. Set them in your shell or .glci.env before running glci.

Paths & data directory#

VariableDefaultDescription
GLCI_HOME~/.glciOverride the data directory where glci stores daemon state, pipeline history, registry data, and logs. Useful for test isolation or running multiple daemon instances.
GLCI_NO_DEFAULT_CONFIG(unset)Set to 1 to prevent glci from auto-creating a .glciconfig.toml when none exists. By default, glci creates one with [skip] stages = [".pre"].
# Use a custom data directory
export GLCI_HOME=/tmp/glci-test
glci run

# Disable auto-creation of .glciconfig.toml
GLCI_NO_DEFAULT_CONFIG=1 glci run

Daemon#

VariableDefaultDescription
GLCI_DAEMON_SOCK~/.glci/daemon.sockOverride the Unix socket path for daemon communication. Useful when running parallel daemon instances (e.g. in CI).
export GLCI_DAEMON_SOCK=/tmp/my-glci.sock
glci run

Container engine (Docker / Podman)#

VariableDefaultDescription
DOCKER_HOST(auto-detected)Docker daemon endpoint, used when the engine is Docker. Outranks the active Docker context — see Endpoint resolution order.
DOCKER_CONTEXT(unset)Selects a named Docker context. glci does not read it to pick an endpoint; it resolves the current context, which the docker CLI derives from DOCKER_CONTEXT first and ~/.docker/config.json second. Outranked by DOCKER_HOST. The name in effect at resolution is recorded, so changing it is reported as drift.
CONTAINER_HOST(auto-detected)Podman’s endpoint variable, used when the engine is Podman ([docker] engine = "podman").
CONTAINER_CONNECTION(unset)Selects a named podman system connection. Podman ranks this above CONTAINER_HOST, and so does glci. Left in place for podman commands so the connection’s own SSH identity still applies.
CONTAINER_SSHKEY(auto-detected)SSH identity for an ssh:// CONTAINER_HOST — the form used by podman machine (the macOS/Windows default) and remote Podman hosts. Exported alongside CONTAINER_HOST when the endpoint was resolved from the default connection, using its Identity, because setting CONTAINER_HOST overrides the named connection podman would otherwise read the key from. An inherited value is left alone.
DOCKER_CONFIG~/.dockerDirectory containing Docker config.json. Used for Docker Hub credentials that are propagated into DinD containers. Read from the environment the daemon was spawned with, so changing it takes effect after glci daemon stop.
DOCKER_CERT_PATH(unset)Directory containing TLS client certificates (ca.pem, cert.pem, key.pem). Per-runner override: tls_cert_path in [runners.<name>]. Docker only — Podman does not honor it.
DOCKER_TLS_VERIFY(unset)Set to 1 to enable TLS verification. Per-runner override: tls_verify in [runners.<name>]. Docker only — Podman does not honor it.

The config keys that back these variables — [docker] engine/host/container_socket and the per-runner engine, docker_host, docker_context, container_socket, tls_cert_path, tls_verify — are honored only in ~/.glci/config.toml. A project .glciconfig.toml that sets them has them dropped with a warning. See Config files > Container-endpoint keys.

Whenever a named runner targets its own endpoint — via either docker_host or docker_context — glci strips DOCKER_HOST, DOCKER_CONTEXT, CONTAINER_HOST, CONTAINER_CONNECTION, CONTAINER_SSHKEY, DOCKER_CERT_PATH, and DOCKER_TLS_VERIFY from that command’s environment before applying the runner’s own settings. The --context/--connection flags do outrank the variables, so for that path stripping is defence in depth; it is load-bearing for the raw-endpoint path, because Podman ranks CONTAINER_CONNECTION above CONTAINER_HOST and would otherwise send a runner that sets docker_host to whatever connection the ambient variable names.

Endpoint resolution order#

The daemon resolves one endpoint at startup, mirroring each engine’s own precedence:

DockerPodman
1[docker] host in ~/.glci/config.toml[docker] host in ~/.glci/config.toml
2DOCKER_HOSTCONTAINER_CONNECTION (named connection)
3active context (docker context use / DOCKER_CONTEXT)CONTAINER_HOST
4Docker CLI defaultdefault podman system connection, then Podman’s default

Only [docker] host outranks the environment. Two endpoint values are refused rather than passed to the engine:

When the endpoint does not come from the environment (config, context, or connection), glci also drops inherited DOCKER_CERT_PATH/DOCKER_TLS_VERIFY: those name trust anchors for one specific daemon, and keeping them against a different endpoint is a false assurance of TLS.

Because the TLS variables are Docker-only, a runner with engine = "podman" and a tcp:// docker_host gets no TLS even with tls_cert_path/tls_verify set (glci config --network warns about this). For a remote Podman endpoint, use an ssh:// endpoint — Podman’s only authenticated and encrypted remote transport. A podman system connection referenced via docker_context is only as secure as its own URI: a connection pointing at tcp:// is still unencrypted and unauthenticated.

# Point glci at a remote Docker daemon
export DOCKER_HOST=ssh://remote-host
glci run

# Point glci at a remote Podman endpoint
export CONTAINER_HOST=ssh://podman-host
glci run

# Use a custom Docker config directory
export DOCKER_CONFIG=/path/to/docker-config
glci run

An exported endpoint variable takes precedence over the active Docker context (and over the default podman system connection), matching how the docker and podman CLIs themselves behave. So a remote daemon can be selected per shell, with no config file changes:

DOCKER_HOST=tcp://build-box:2375 glci run

Security: glci sends more to the resolved endpoint than docker alone does — the repository tree, your ~/.docker/config.json registry credentials, and the forwarded GitLab token all land on that daemon. A plain tcp:// endpoint carries them unencrypted and unauthenticated, so glci prints a warning when it resolves one without TLS. Prefer ssh://, or configure Docker TLS.

Endpoint changes and the shared daemon#

The glci daemon is process-global and resolves its endpoint once at startup, inheriting the environment of the CLI invocation that spawned it. A later command that selects a different endpoint does not restart it — glci reports the mismatch once and leaves the daemon alone:

glci: warning: daemon is using unix:///var/run/docker.sock but $DOCKER_HOST selects tcp://build-box:2375
glci:          run `glci daemon stop` to pick it up (the daemon re-starts on the next command)

Restarting is deliberately not automatic. Endpoint selection is per-shell while the daemon is global, so auto-restarting would let two shells with different DOCKER_HOST values evict each other’s daemon on every command — and a restart races any pipeline that starts while it is being decided. glci daemon stop is the explicit switch; the daemon re-starts with the new endpoint on the next command. If pipelines are still running, the warning says how many, because stopping the daemon cancels them.

Four mismatches are reported:

One case is not detected: running docker context use other, which changes the current context on disk without changing any variable. Catching that would mean asking the docker CLI for the context’s endpoint on every glci command. glci daemon status and glci doctor both report the endpoint in use (and the context it came from), and doctor says explicitly when a value was not compared.

GitLab API#

VariableDefaultDescription
GITLAB_URL(auto-detected from git remote)GitLab instance URL. Overrides auto-detection from git remote and config file settings. Falls back to https://gitlab.com.
GITLAB_TOKEN(unset)GitLab personal access token or CI job token. Used for cross-project includes, fetching remote CI/CD variables, and auto-cloning trigger targets.
GITLAB_PRIVATE_TOKEN(unset)Alias for GITLAB_TOKEN. If both are set, GITLAB_TOKEN takes precedence.
export GITLAB_URL=https://gitlab.example.com
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
glci run

Parsing behavior#

VariableDefaultDescription
GLCI_PREFER_API(unset)Set to 1 to use the GitLab Lint API as the primary CI config parser instead of the offline parser. The offline parser is the default (with API as fallback).
GLCI_PREFER_API=1 glci run

Cache (internal, mock server)#

These variables are set internally by the daemon when launching the mock server container. They are documented here for completeness but are not typically set by users.

VariableDefaultDescription
GLCI_MOCK_PORT39741Port the mock server listens on inside its container. Set by the daemon from the resolved mock_server_port config value. Configurable via [network] mock_server_port in config.toml.
GLCI_CACHE_DIR(unset)Disk-backed cache directory for the mock server. Set by the daemon to /cache-store inside the mock container. When unset, cache stays in memory.
GLCI_CACHE_MAX_SIZE500MBMaximum total size for CI cache entries. Uploads are rejected when this limit is exceeded. Accepts suffixes: KB, MB, GB.
GLCI_CACHE_TTL24hTime-to-live for cached entries. Entries older than this are expired. Uses Go duration format (e.g. 1h30m, 24h).

Editor#

VariableDefaultDescription
EDITOR(unset)Used by glci config edit to open the project config file. Falls back to VISUAL if unset.
VISUAL(unset)Fallback editor when EDITOR is not set.
export EDITOR=vim
glci config edit

Simulation#

VariableDescription
GLCI_SIMULATESet to true inside job containers when running in --simulate mode. Not typically set by users; scripts can check this to detect simulation.

CI/CD variables set in jobs#

glci populates standard GitLab CI/CD predefined variables inside job containers. Commit, project, server, pipeline, job, user, and runner variables are all derived from local git state and mock server configuration, matching what GitLab CI would set.

The following variables behave differently in glci compared to GitLab CI:

Variables with fixed/local values#

Variableglci valueWhy it differs
CI_COMMIT_BEFORE_SHA0000000000... (null SHA)No previous pipeline to compare against locally
CI_COMMIT_REF_PROTECTEDfalseProtected branch status is not available locally
CI_PROJECT_ID0No real project ID locally
CI_PROJECT_NAMESPACE_ID0No real namespace ID locally
CI_PROJECT_VISIBILITYprivateNot detectable locally
CI_PIPELINE_IIDSame as CI_PIPELINE_IDNo project-scoped counter separation locally
GITLAB_USER_LOGINSame as GITLAB_USER_NAMENo GitLab account mapping; uses git config user.name
GITLAB_USER_ID0No real user ID locally
CI_RUNNER_ID1 (default runner)Per-runner ID; named runners ([runners.<name>]) get unique IDs
CI_RUNNER_DESCRIPTIONglci-local-runner (default runner)Per-runner description; named runners use their container name
CI_JOB_TOKENSynthetic mock tokenUnless real token is forwarded via [token] config

Registry variables#

Set when the embedded container registry is active (default).

VariableSource
CI_REGISTRYEmbedded registry address (e.g. host.docker.internal:12345)
CI_REGISTRY_USERgitlab-ci-token
CI_REGISTRY_PASSWORDSet per-job; equals CI_JOB_TOKEN
CI_REGISTRY_IMAGERegistry address + project path
DOCKER_AUTH_CONFIGDocker auth JSON merged with host ~/.docker/config.json

Environment and release variables#

CI_ENVIRONMENT_* variables are set when a job has an environment: keyword. CI_RELEASE_DESCRIPTION is set when a job has a release: keyword (truncated to 1024 chars).

Merge request variables#

Set when using --context merge_request.

Variableglci value
CI_PIPELINE_SOURCEmerge_request_event
CI_MERGE_REQUEST_SOURCE_BRANCH_NAMECurrent git branch (or --mr-source)
CI_MERGE_REQUEST_TARGET_BRANCH_NAMEDefault branch (or --mr-target)
CI_MERGE_REQUEST_IID1
CI_MERGE_REQUEST_TITLElocal

Variable precedence#

See Variables & Secrets for the full precedence table and details on remote secrets, .glci.env, and token resolution.

Esc