Skip to main content

loom run

Execute a Loom or GitLab workflow locally. Recorded runs produce state.jsonl and events.jsonl under .loom/.runtime/runs/<run_id>/. Use loom logs to inspect state and output after execution.

Canonical command usage​

Use the core CLI command reference for the exact loom run synopsis, flags, and displayed defaults.

Requirements​

  • Local execution: every run executes on this machine. The historical --local flag is still accepted but hidden and ignored; it is no longer required.
  • Docker: jobs with an image: field run inside Docker. The Docker daemon must be installed and reachable. See Docker provider.
  • Host shell: jobs without image: run directly on your host shell. See Host provider.

Select jobs​

Use repeatable --job to execute source jobs or exact final job IDs and their transitive ordering and artifact prerequisites, for either source format:

loom run --job consumer --job smoke

Omitting both selectors selects the full workflow. IDs are exact: commas are literal, surrounding whitespace is rejected, and duplicate IDs form one set. Unknown or unavailable jobs fail before snapshot materialization or provider work. Selection preserves workflow/job rules and existing dependency behavior.

An explicit request prints job selection with sorted requested_jobs, optional requested_instances, effective_jobs and a stable scope identity; quiet suppresses the console line. The same protected event is retained once in events.jsonl, from the final snapshot or a terminal preflight outcome. A selected run verifies that scope, not the entire workflow. Unrelated jobs are excluded.

For integer fanout, --job shard selects all source members before prerequisite closure. --instance 'shard 2/3' selects only that exact final node, even when its name is also a source alias. Repeat or combine both flags. job_selection binds both request sets and effective jobs into its identity. See integer fanout.

Native caller variables​

Native --context accepts the strict caller variable envelope. Values override composed root/job values, including empty strings. Exported directory overrides do not change physical cwd or mounts. Native contexts work for synchronous CLI runs and MCP synchronous/server-owned runs. Config defaults.context remains GitLab-only.

GitLab workflow input​

Omitted flags fall back to the defaults block of the layered runtime config (see runtime config syntax); explicit flags always win.

Default discovery selects .loom/workflow.yml, then .loom/workflow.yaml, before the repository root .gitlab-ci.yml. With --workflow and no --format, Loom infers the format from the file content (a root version key or a job target means Loom; other ordinary mappings mean GitLab). Include-only mappings are ambiguous; an explicit context envelope hints its frontend. Use --format to override inference and --context with a project-relative loom.gitlab-pipeline-context.v1 JSON file or a short name that resolves to .loom/contexts/<name>.json (see loom context init). Explicit formats never fall back to another parser.

The context file is limited to 1 MiB. Its variables and changes drive GitLab rules and expansion. runner_tags describes local runner capabilities used to satisfy or reject plan requirements; it is not job-selection data. Ambient CI variables and runtime settings do not affect selection. Grant a selected privileged service explicitly with repeatable --privileged-service <alias>. Blank, duplicate, unknown, and ambiguous aliases fail before provider setup.

changes.paths is optional. When a matched rules:changes has no explicit context paths, loom run resolves changed paths the same way as loom check: git diff --merge-base in the repository root against the rule's compare_to or changes.base, comparing the working tree when compare_to is set and the context has no changes. Fail-closed cases (unknown ref, shallow clone, no git) stop before providers start with GL_RULE_CHANGES_UNAVAILABLE. The resolved comparisons determine the selected execution plan.

GitLab execution is Linux-only. Hosted macOS, OIDC tokens, Pages, and environments are unsupported requirements. Optional manual jobs are reported and not executed. Report processing and artifact expiry are recorded limitations. workflow_skipped exits 0 with a visible skipped result; source_invalid and non_executable exit nonzero before providers start.

Output verbosity: --quiet, --verbose, --stream​

These flags control terminal output only. Verbosity settings do not disable recording under .loom/.runtime/runs/<run_id>/.

The CLI prints the run locator before preparing the isolated workspace. Normal output reports rooted preflight, snapshot preparation and compilation; --verbose also shows real clone, reference, checkout and overlay phase boundaries with elapsed time. Overlay counts report successful entries; reference counts report the inventory selected for preservation, including when transfer later fails. --quiet suppresses preparation commentary but retains the early run locator and final outcome. Quiet takes precedence when both quiet and verbose are set. Recorded preparation events remain available in every mode and describe actual work boundaries, not process liveness.

Invalid source and known blocked, skipped or unsupported cache-diff GitLab plans finish before snapshot materialization. Their run records preserve the planning outcome and diagnostics. Accepted source is compiled again from the isolated snapshot before execution; the initial mutable-source check never authorizes a job to run.

FlagBehavior
(default)Standard output — job started/finished, status, run directory
--quietMinimal output — run directory, summary and final status
--verboseAdditional metadata (useful when you don't want to open runtime logs yet)
--streamStream job stdout/stderr in real time (increases console volume substantially)

Execution concurrency: --parallel​

By default, loom run --local starts one runnable job at a time. Set --parallel to a positive integer to allow up to that many runnable jobs to execute concurrently. Dependencies and stage barriers still determine when each job becomes runnable.

loom run --local --parallel 4

Explicit zero, negative, and malformed values are rejected before the workflow starts.

Environment variables​

VariableValuesDescription
LOOM_DOCKER_WORKSPACE_MOUNTbind_mount, ephemeral_volumeDocker workspace mount mode. Overridden by --docker-workspace-mount flag

Docker workspace mount resolution order​

  1. --docker-workspace-mount flag value (if set)
  2. LOOM_DOCKER_WORKSPACE_MOUNT environment variable (if set)
  3. Repo config: .loom/config.yml
  4. User config: ~/.config/loom/config.yml
  5. Default: ephemeral_volume

The config field is runtime.docker.workspaceMount. See Precedence and merge rules.

Optional Loom Web evidence upload​

Uploads are disabled by default. Use project setup and project authorization, explicitly choosing web.upload: true, to use a bound local project credential. Authentication alone does not enable delivery. The upload guide describes credential selection, offline preparation and saved-run retry.

For CI mode, provide the complete host environment tuple:

export LOOM_WEB_UPLOAD=true
export LOOM_WEB_URL=https://loom.example.com
export LOOM_WEB_PROJECT_ID=11111111-1111-4111-8111-111111111111
export LOOM_WEB_TOKEN_ENV=LOOM_INGEST_TOKEN
# Supply LOOM_INGEST_TOKEN through your existing secret-management environment.
export LOOM_WEB_REDACT_ENV=DEPLOY_TOKEN,PACKAGE_TOKEN
loom run

An explicitly supplied LOOM_WEB_UPLOAD value other than exactly true disables upload, including credential lookup and network operations. Any CI destination or token selector requires explicit consent and the complete tuple; partial modes never borrow fields from repository configuration or the local credential store. The destination and selected credential are bound before workflow execution. LOOM_WEB_URL must be an HTTPS origin without a path, query, fragment or user information. TLS verification is required; redirects and ambient proxies are disabled. Upload uses a project-bound ingest:write credential and never starts browser/device login.

The current Web upload protocol handles previously saved native artifacts. The two-file workflow recording format is retained locally; upload does not convert it to an older receipt format. An upload warning does not change the workflow outcome or exit code.

Outputs​

Each recorded invocation writes:

.loom/.runtime/runs/<run_id>/
state.jsonl
events.jsonl

State records describe workflow, job, step and command transitions. Event records carry contextual messages and stdout/stderr output. The CLI prints the run location and file paths, including for failures after recording starts.

loom logs <run_id> --state
loom logs <run_id> --tail 30
loom logs <run_id> --json

See Runtime logs for record fields.

Exit codes​

CodeMeaning
0All jobs succeeded
1One or more jobs failed, or the run failed to start

When --cache-diff is used, exit code 1 also indicates mechanical divergence between the cache-off and cache-on runs.

Output streams​

StreamContent
stderrStatus messages, run directory, loom run passed / error summary
stdout(unused in normal operation)

Example output​

run: .loom/.runtime/runs/<run_id>
state: .loom/.runtime/runs/<run_id>/state.jsonl
events: .loom/.runtime/runs/<run_id>/events.jsonl
loom run passed

For an executed job failure, Loom also prints the first failing job's output tail and a pointer to events.jsonl. --quiet omits that tail.

Examples​

Run the default workflow​

loom run --local

Run with streaming output​

loom run --local --stream

Run up to four jobs concurrently​

loom run --local --parallel 4

Run a custom workflow with verbose output​

loom run --local --workflow ci/nightly.yml --verbose
loom run --local --format gitlab --workflow ci/pipeline.yml \
--context contexts/mr.json --privileged-service docker

Run with bind mount workspace mounting​

loom run --local --docker-workspace-mount bind_mount

Cache differential analysis​

loom run --local --cache-diff

Runs the workflow twice (first with cache disabled, then with cache enabled) and compares outputs. Mechanical divergence causes a non-zero exit. After collecting complete evidence for both executions, Loom quarantines a participating cache-hit candidate only when the node's declared outputs differ and exactly one eligible scope/key pair is associated with that node. It records ambiguous candidates without quarantine. This comparison does not establish universal cache safety. See Cache quarantine.

Failure triage​

Read the state transitions to identify the failed job, then inspect its events:

loom logs <run_id> --state
loom logs <run_id> --tail 30

JSON output retains context for filtering by job or step. If recording could not start, inspect the CLI error. See the Diagnostics ladder.

Provider selection​

loom run selects a provider per job based on the workflow definition:

Job has image:ProviderDocumentation
YesDockerDocker provider
NoHost shellHost provider

Workflow-level caching (when configured) is documented at Cache.

  • loom logs — inspect a recorded run
  • loom check — validate the workflow schema before running
  • loom compile — inspect the compiled job graph without executing