Predefined CI/CD variables
Loom injects a set of predefined environment variables into every job at runtime. Use them in scripts to access job identity, workspace paths, Git metadata, and runtime context without hardcoding values.
check:
stage: ci
target: linux
script:
- echo "Job $LOOM_JOB_NAME running in $LOOM_PROJECT_DIR"
- echo "Commit: $CI_COMMIT_SHORT_SHA on branch $CI_COMMIT_BRANCH"
Variable naming
Loom provides two sets of predefined variables:
| Prefix | Purpose |
|---|---|
LOOM_ | Native Loom variables. Use these when writing Loom-first workflows. |
CI_ | Compatibility layer for scripts that also run in GitLab CI, GitHub Actions, or other platforms. |
Many CI_ variables are aliases of their LOOM_ counterparts (for example, CI_JOB_NAME and LOOM_JOB_NAME resolve to the same value). Prefer LOOM_ variables in new workflows — they are the canonical names and will always be supported.
Using variables in scripts
Variables are injected as shell environment variables. Reference them with $VARIABLE_NAME:
check:
stage: ci
target: linux
script:
- echo "Job $LOOM_JOB_NAME running in $CI_PROJECT_DIR"
- cd $CI_PROJECT_DIR && pnpm run build
Provider behavior affects which variables a job sees:
| Provider | Behavior |
|---|---|
Host (no image: set) | Job inherits the local process environment, then Loom applies workflow/job variables as overrides. |
Docker (image: set) | Loom passes only workflow/job variables into the container. Host environment variables are not forwarded — declare any needed values in default.variables or job variables. |
Precedence
When a workflow or job defines a variable with the same name as a predefined variable, the user-defined value wins. User intent always takes priority.
version: v1
stages: [ci]
default:
variables:
CI_PROJECT_DIR: "/custom/workdir"
show-dir:
stage: ci
target: linux
script:
- echo "$CI_PROJECT_DIR"
Output:
/custom/workdir
If you depend on Loom's default value for a predefined variable, avoid overriding it. Use a different variable name instead — for example, prefix custom variables with your org or team name.
The full merge order is:
- Predefined variables (Loom system) — baseline values.
- Workflow-level
variables/default.variables— override predefined values for matching keys. - Job-level
variables— override both predefined and workflow-level values for matching keys.
See Variables for the full precedence model.
Predefined variables reference
Pipeline-scoped variables are resolved once per loom run and then merged into every job environment. Job-scoped and step-scoped variables are resolved per job right before script execution.
Loom pipeline variables
| Variable | Description | Availability | Example |
|---|---|---|---|
LOOM_CI | Always true when Loom is executing a job. | Pipeline | true |
LOOM_RUN_ID | Executor run id. Unique per loom run invocation. | Pipeline | loom-run-local-1772867400012726000 |
LOOM_PIPELINE_ID | Executor pipeline id. | Pipeline | loom-local-1772867400012726000 |
LOOM_WORKFLOW_PATH | Workflow file path used for this run in the snapshot. | Pipeline | .loom/workflow.yml |
Pipeline compatibility variables
| Variable | Description | Availability | Example |
|---|---|---|---|
CI | Always true when Loom is executing a job. | Pipeline | true |
CI_RUN_ID | Compatibility alias for Loom's run id. | Pipeline | loom-run-local-1772867400012726000 |
CI_PIPELINE_ID | Executor pipeline id. | Pipeline | loom-local-1772867400012726000 |
CI_PIPELINE_IID | Same value as CI_PIPELINE_ID today. | Pipeline | loom-local-1772867400012726000 |
CI_PIPELINE_STARTED_AT | RFC 3339 timestamp captured when the run starts. | Pipeline | 2026-03-06T12:00:00Z |
CI_PIPELINE_STARTED_AT_SLUG | Slug of CI_PIPELINE_STARTED_AT limited to 63 bytes. | Pipeline | 2026-03-06t12-00-00z |
CI_PROJECT_NAME | Project name derived from the workspace root or explicit project metadata. | Pipeline | loom |
CI_PROJECT_NAMESPACE | Currently resolves to the same value as CI_PROJECT_NAME. | Pipeline | loom |
CI_PROJECT_NAMESPACE_SLUG | Slug of CI_PROJECT_NAMESPACE limited to 63 bytes. | Pipeline | loom |
CI_PROJECT_NAMESPACE_ID | Placeholder namespace id. | Pipeline | 0 |
CI_RUNNER_ID | Runner identifier for local Loom execution. | Pipeline | loom-local |
CI_RUNNER_VERSION | Runner version marker for local Loom execution. | Pipeline | local |
Pipeline Git variables
| Variable | Description | Availability | Example |
|---|---|---|---|
CI_COMMIT_SHA | Snapshot HEAD SHA that Loom runs against. | Pipeline when Git metadata is known | abcdef1234567890abcdef12 |
CI_COMMIT_SHORT_SHA | First 8 characters of CI_COMMIT_SHA. | Pipeline when Git metadata is known | abcdef12 |
CI_COMMIT_BRANCH | Current branch name when Loom can resolve it. | Pipeline when branch is resolvable | main |
CI_COMMIT_REF_NAME | Alias of CI_COMMIT_BRANCH for GitLab-compatible scripts. | Pipeline when branch is resolvable | main |
Job variables
| Variable | Description | Availability | Example |
|---|---|---|---|
LOOM_JOB_NAME | Job name (graph node id). | Job | check |
LOOM_JOB_ID | Job id (currently same as job name). | Job | check |
LOOM_JOB_STAGE | Job stage name. | Job | ci |
LOOM_JOB_TARGET | Job target. | Job | linux |
LOOM_JOB_IMAGE | Job image when image: is set. | Job when image: is set | node:20-alpine |
LOOM_PROVIDER | host or docker, depending on whether image: is set. | Job | docker |
LOOM_PROJECT_DIR | Working directory when the job starts. | Job | /workspace |
CI_BUILDS_DIR | Top-level directory where builds or workspaces live. | Job | /tmp |
CI_PROJECT_DIR | Workspace root where the job runs. | Job | /workspace |
CI_JOB_NAME | Job name (graph node id). | Job | check |
CI_JOB_ID | Job id (currently same as job name). | Job | check |
CI_JOB_STAGE | Job stage name. | Job | ci |
CI_JOB_TARGET | Job target. | Job | linux |
CI_JOB_IMAGE | Job image when image: is set. | Job when image: is set | node:20-alpine |
CI_DEBUG_TRACE | Defaults to false; set to true to enable verbose shell tracing. | Job | false |
CI_JOB_STATUS | Always running during script execution. | Job | running |
CI_JOB_TIMEOUT | Placeholder timeout value. | Job | 0 |
CI_JOB_STARTED_AT | RFC 3339 timestamp captured when the job environment is injected. | Job | 2026-03-06T12:01:00Z |
CI_JOB_STARTED_AT_SLUG | Slug of CI_JOB_STARTED_AT limited to 63 bytes. | Job | 2026-03-06t12-01-00z |
CI_STAGE_STARTED_AT | RFC 3339 timestamp for the stage start tracked for the current job. | Job | 2026-03-06T12:01:00Z |
CI_STAGE_STARTED_AT_SLUG | Slug of CI_STAGE_STARTED_AT limited to 63 bytes. | Job | 2026-03-06t12-01-00z |
Step variables
| Variable | Description | Availability | Example |
|---|---|---|---|
CI_STEP_ID | Always 1; Loom currently executes a job as a single shell step. | Step | 1 |
CI_STEP_STARTED_AT | RFC 3339 timestamp captured when the current step starts. | Step | 2026-03-06T12:01:00Z |
CI_STEP_STARTED_AT_SLUG | Slug of CI_STEP_STARTED_AT limited to 63 bytes. | Step | 2026-03-06t12-01-00z |
These variables are defined by Loom and do not depend on any external CI provider.
Variables in workflow rules
workflow.rules.if expressions reference variables using $VARIABLE_NAME syntax:
workflow:
rules:
- if: $CI_COMMIT_BRANCH == "main"
Today, Loom validates rule structure (each rule must have a non-empty if string) but does not evaluate expressions at runtime. Which variables are available during rule evaluation — and the expression language itself — is planned. See Rules for current status.
Until expression evaluation is implemented, use workflow.rules for forward-compatible structure and handle gating logic in job scripts or your surrounding CI system.
Running inside another CI system
When you invoke loom run --local from within a GitLab CI job, GitHub Actions step, or other CI runner:
- Host-provider jobs (no
image:) inherit the parent CI environment. Variables likeCI_COMMIT_REF_NAMEorGITHUB_SHAfrom the outer CI system are visible alongside Loom's predefined variables. - Docker-provider jobs (
image:set) receive only workflow/job variables. To forward a value from the outer CI system, declare it explicitly invariables.
check:
stage: ci
target: linux
image: node:20-alpine
variables:
GITHUB_SHA: $GITHUB_SHA
script:
- echo "Outer CI SHA: $GITHUB_SHA"
Migration from other CI platforms
Loom's CI_ variables provide a compatibility layer, not a perfect emulation. Key differences:
| Area | What Loom provides | What may be missing |
|---|---|---|
| Job identity | Job name, id, stage, target, image, status | — |
| Workspace | Project directory, builds directory | — |
| Git metadata | Commit SHA, short SHA, branch name | Tag name, MR/PR metadata, author, labels |
| Pipeline | Pipeline id, run id, timestamps | Pipeline source, trigger info, upstream pipeline |
| Runner | Runner id (loom-local), version (local) | Runner description, tags, architecture |
If your scripts need values Loom does not provide (merge request metadata, actor names, tags), pass them explicitly via workflow or job variables, or rely on the host environment when running Loom inside another CI system.
When writing portable scripts, prefer LOOM_ variables inside Loom workflows and map to provider-specific names at the boundary:
check:
stage: ci
target: linux
script:
- echo "Project dir: $LOOM_PROJECT_DIR"
- echo "Provider: $LOOM_PROVIDER"
Not yet supported
Loom does not currently derive Git metadata beyond commit SHA and branch name. Tag names, merge request details, author information, and similar context are not automatically populated. Pass these explicitly via variables if your workflow needs them.
Security considerations
Some predefined variables can expose sensitive information even when they do not look like secrets:
- Paths (
CI_PROJECT_DIR,CI_BUILDS_DIR,LOOM_PROJECT_DIR) can reveal usernames, internal mount paths, or repository layout. - Identifiers (
CI_COMMIT_SHA,CI_PIPELINE_ID,LOOM_RUN_ID) can be used to correlate runs and access logs. - Image references (
CI_JOB_IMAGE) may reveal base images or private registries.
Sharing variable names is safe. Sharing values may not be — redact path segments and internal hostnames when asking for help. If you need to share debugging context, provide the run_id and structured log pointers instead of raw environment dumps. See What to share.
Troubleshooting
Print all predefined variables available in a job:
script:
- env | grep -E '^CI_|^LOOM_' | sort
Enable verbose shell tracing for detailed execution output:
variables:
CI_DEBUG_TRACE: "true"
Validate your workflow before running:
loom check
Next steps
- Variables — precedence rules, provider behavior, troubleshooting
- Syntax (v1) — full workflow keyword reference
- Rules — conditional workflow execution
- Predefined CI variables (optional reference) — upstream provider variable snapshot