Skip to main content

GitLab pipeline context contract

loom.gitlab-pipeline-context.v1 is the caller-owned JSON document that loom check, loom compile, and loom run read through --context (or defaults.context) when the workflow source is GitLab. It supplies the pipeline facts GitLab would inject on a runner so that workflow:rules, rules:, and variable expansion select the same jobs locally.

Where it comes from​

  • loom context init --as push|mr [--name <name>] writes .loom/contexts/<name>.json from the checked-out branch. See loom context.
  • Any hand-written file that follows this contract works the same way.
  • --context <name> without a path separator or .json suffix resolves to .loom/contexts/<name>.json; other values are project-relative paths beneath the repository root. Files are limited to 1 MiB.

Document shape​

{
"version": "loom.gitlab-pipeline-context.v1",
"variables": {
"CI_PIPELINE_SOURCE": "push",
"CI_COMMIT_BRANCH": "main",
"CI_DEFAULT_BRANCH": "main",
"CI_COMMIT_SHA": "9ec2bc2e9b997525703e29917db2a21a86ad75cc",
"CI_COMMIT_BEFORE_SHA": "119abcd8d4282468372df322f92cc51c60b30ac7"
},
"changes": {
"base": "119abcd8d4282468372df322f92cc51c60b30ac7",
"head": "9ec2bc2e9b997525703e29917db2a21a86ad75cc"
},
"runner_tags": ["saas-linux-medium-amd64"]
}

Only the four top-level keys below are accepted; any other key fails decoding with GL_CONTEXT_TYPE_INVALID and the accepted key list.

KeyRequiredTypeMeaning
versionyesstringExactly loom.gitlab-pipeline-context.v1
variablesyesobject of stringsPipeline variables visible to rules and expansion (may be empty)
changesnoobjectThe comparison rules:changes evaluate against
runner_tagsnoarray of stringsTags the local runner claims to satisfy; not job-selection data

variables​

Every value is a string. Names follow GitLab's predefined variables (CI_PIPELINE_SOURCE, CI_COMMIT_BRANCH, CI_DEFAULT_BRANCH, CI_COMMIT_SHA, CI_COMMIT_BEFORE_SHA, CI_COMMIT_REF_SLUG, CI_MERGE_REQUEST_*, ...). Undefined variables evaluate as null in rules. Explicit directory values (CI_BUILDS_DIR, CI_PROJECT_DIR) are ordinary caller overrides available to earlier consumers. When absent, their actual defaults remain unavailable before provider assignment; earlier-phase use fails with GL_CONTEXT_PHASE_UNAVAILABLE. Ambient environment variables of the loom process are never consulted.

changes​

FieldRequiredMeaning
baseyesCommit, branch, or ref the comparison starts from (merge_base(base, head)..head)
headyesCommit or ref being compared; HEAD compares the working tree
pathsnoExplicit changed paths; when present, git is never consulted and these paths always win

Without paths, Loom resolves the changed paths with git diff --merge-base in the repository root, using the rule's compare_to as the base when the rule sets one. Without a changes object, a rule with rules:changes cannot be evaluated unless it carries compare_to, in which case the working tree is compared. Unknown refs and shallow clones without a merge base fail closed with GL_RULE_CHANGES_UNAVAILABLE.

runner_tags​

Trimmed, non-empty, unique strings. A selected job whose tags are not all listed here produces GL_CAPABILITY_RUNNER_TAGS_UNSATISFIED and a non_executable plan; the hint tells you to add the tags. Tags never select or deselect jobs.

Validation codes​

CodeCause
GL_CONTEXT_VERSION_UNSUPPORTEDversion is missing or not loom.gitlab-pipeline-context.v1
GL_CONTEXT_TYPE_INVALIDUnknown key, wrong type, blank changes.base/head, or malformed runner_tags entry
GL_CONTEXT_PHASE_UNAVAILABLEA missing runner-phase default was referenced before assignment

Error messages name the JSON pointer of the offending field and never echo variable values, so a context can be shared in a bug report after redaction.

Identity​

The receipt and plan report record a selection_identity derived from the canonical context (sorted variables, changes, and any git-resolved paths). Two runs with the same source and context produce the same identity, which is how loom check receipts can be replayed.

Ordinary scalar binding​

Caller variables override composed root/job definitions, including empty values. Ordinary job scalars use released server dependency expansion followed by one Runner dollar-expansion pass. Missing runtime defaults are supplied after provider assignment; explicit CI_PROJECT_DIR, CI_BUILDS_DIR and LOOM_PROJECT_DIR values remain exported overrides. They do not change physical execution paths. Rules and cache fields retain their earlier-phase availability checks. Native workflows use the separate caller variable context.

Authored root variables accept rich value/expand/description/options definitions; jobs accept only value/expand. Explicit caller strings replace the whole effective definition, including its expansion mode, and are not restricted by authored options. Missing/null rich values become empty; false/null expand preserves literal bytes. See rich variables for authored typing, composition and consumer phases.