loom compile
Compile a Loom workflow into Graph IR v1 JSON or project a GitLab workflow into a value-safe plan report, without executing jobs.
Canonical command usage
Use the
generated core CLI command reference for the exact
loom compile synopsis, flags, and displayed defaults.
Workflow source and context
Default discovery selects .loom/workflow.yml before the repository root
.gitlab-ci.yml. --format loom|gitlab selects exactly one parser. An explicit
.gitlab-ci.yml basename is recognized as GitLab at any trusted project path;
other custom GitLab filenames need --format gitlab. Parser and read failures do
not cause fallback.
Use --context with GitLab sources to load a strict
loom.gitlab-pipeline-context.v1 JSON document. The file is project-relative,
limited to 1 MiB, and keeps variables, changes, and runner_tags separate.
Ambient CI variables and runtime settings do not affect selection.
Workflow path trust boundary
--workflow paths are resolved relative to the repository root. Absolute paths,
paths containing .., and paths that resolve through escaping or dangling symlinks
are rejected with WF_TRUSTED_PATH before workflow content is read. The same
boundary applies to include.local.
Use cases
- Diff compiled plans across branches or commits to spot unexpected job changes
- Verify include/template resolution — confirm
extendsandinclude.localmerge correctly - Inspect the job graph (nodes +
needsedges) before running - Feed Graph IR to external tools for visualization or analysis
Exit codes
| Code | Meaning |
|---|---|
0 | Loom compilation succeeded, or GitLab plan is executable or skipped |
1 | Source is invalid, GitLab plan is non-executable, or the command fails |
Output streams
| Stream | Content |
|---|---|
| stdout | Graph IR v1 JSON, or a GitLab plan report once a plan exists |
| stderr | Warnings, diagnostics, and fatal errors |
For GitLab, stdout uses loom.gitlab-plan-report.v1. It contains the plan
schema and state, selection identity, selection records, requirements,
diagnostics, and executable job topology. It excludes scripts, variables, and
resolved context values. source_invalid and non_executable still write this
report before returning nonzero; workflow_skipped writes a skipped report and
returns 0.
Compile reports privileged-service requirements but cannot grant consent. It also exposes unsupported hosted macOS, OIDC token, Pages, and environment requirements; optional manual jobs remain visible but are not executed. Report processing and artifact expiry are diagnostic limitations.
Graph IR output format
loom compile outputs a JSON object with these top-level keys:
| Key | Type | Description |
|---|---|---|
schema | string | IR schema identifier — currently loom.graph-ir.v1 |
stages | string[] | Ordered list of stage names |
nodes | object[] | Executable jobs (template-only jobs are excluded) |
edges | object[] | Dependency edges (currently: needs relationships) |
Example output
{
"schema": "loom.graph-ir.v1",
"stages": ["ci"],
"nodes": [
{
"id": "check",
"stage": "ci",
"target": "linux",
"image": "alpine:3.20",
"script": ["pnpm i --frozen-lockfile", "task check"],
"allow_failure": false,
"variables": [{ "key": "PNPM_STORE_DIR", "value": ".pnpm-store" }],
"cache": {
"paths": [".pnpm-store", ".nx/cache"],
"policy": "pull-push",
"when": "always",
"key": { "prefix": "loom-cache", "files": ["pnpm-lock.yaml"] }
}
}
],
"edges": []
}
Notes on node fields:
image,variables, andcacheare omitted when not present or not effective for a node.cachecan be a single object or a list, matching the workflow's single-cache vs. multi-cache shape.allow_failureis always a boolean and defaults tofalse. Whentrue, only an ordinary nonzero exit from the main script may satisfy dependency ordering. The command result keeps its actual status, exit code, and reason. Setup, cancellation, timeout, provider, publication, finalization, and cleanup errors remain fatal.- Workflow source may declare
allow_failureon jobs and template jobs. Resolved template values are emitted in Graph IR, and an explicit child value overrides its template.
Warnings
Warnings are non-fatal. They are written to stderr in this format:
warning: <code> <path> <message>
Known warning codes
| Code | Meaning |
|---|---|
WF_PLANNER_VARIABLE_NON_SCALAR | A variable value was not a scalar; it was ignored while building the Graph IR |
Invalid needs targets, self-dependencies, and dependency cycles are compilation
errors. They are reported at the offending needs source path and exit with code
1.
This list may grow. If you see an unknown warning code, include it when reporting issues.
Examples
Compile the default workflow
loom compile
Compile a workflow at a custom path
loom compile --workflow ci/staging-workflow.yml
Pipe Graph IR to jq for inspection
loom compile | jq '.nodes[] | {id, stage, image}'
Diff compiled plans between branches
diff <(git stash && loom compile) <(git stash pop && loom compile)
Reporting issues
When loom compile fails or emits unexpected warnings, include:
- The command you ran (including
--workflowif used) - Warning or error lines from stderr
- The first ~20 lines of JSON output (redacted if needed)
See What to share for the full checklist.
Related commands
loom check— validate schema without compilingloom run— execute the compiled workflow