Skip to main content

Providers

Providers control where each job executes during loom run --local. Your choice of provider determines isolation level, reproducibility, and available tooling.

Provider selection​

Loom picks a provider for each job based on the resolved job definition:

ConditionProvider
Job has a non-empty image: valueDocker — runs in a container
Job has image.build (build spec)Docker — builds an image, then runs in a container
Job has neither image: nor image.buildHost — runs on the local shell
Job includes cache:Cache wrapper around whichever provider above applies

Cache is always a wrapper — it restores/saves around the base provider (host or Docker).

Inherited configuration matters​

Provider selection happens after Loom resolves the full job definition. A job can inherit image: from sources you don't see inline:

  • Workflow defaults: default.image applies to every job that doesn't override it.
  • Template inheritance: extends or imported templates can contribute image:.

If a job unexpectedly runs in Docker (or on host), inspect the resolved configuration:

loom compile --workflow .loom/workflow.yml

Quick example​

stages: [ci]

host-job:
stage: ci
target: linux
script:
- echo "runs on host — no image set"

docker-job:
stage: ci
target: linux
image: alpine:3.20
script:
- echo "runs in a container"

cached-docker-job:
stage: ci
target: linux
image: alpine:3.20
cache:
paths: [.pnpm-store]
script:
- pnpm i --frozen-lockfile

Confirming which provider ran​

Inspect the resolved workflow with loom compile. To confirm the runtime selected for an executed command, print its nonsecret provider variable:

script:
- printf 'provider=%s\n' "$LOOM_PROVIDER"

Read the output with loom logs <run_id> --json, or use loom_read_events with that job's job_id. The run's state.jsonl identifies whether the job and command ran; events.jsonl contains their output and provider diagnostics.

For the full file layout, see the Runtime logs contract.

Prerequisites​

  • loom run --local execution.
  • Linux is the supported local target in the current MVP.
  • For Docker jobs: Docker must be installed and the daemon must be reachable.

Choosing between host and Docker​

DimensionHostDocker
IsolationRuns in your local shell; inherits the process environmentRuns in a container; environment is explicit
Startup speedNo container overheadContainer pull + startup adds latency
ReproducibilityDepends on local machine stateImage pins a known environment
Tool availabilityWhatever is in your PATHOnly what the image provides
Security boundaryJobs see local environment variables and filesystemContainer limits implicit host access (workspaces, secrets, and mounts still apply)

For sensitive workflows, minimize secrets and mounts regardless of provider. Validate what a job can access by reviewing the provider's runtime events.

Provider pages​

Troubleshooting​

SymptomLikely causeWhat to do
Job unexpectedly ran on hostMissing image:Run loom compile and verify the resolved job has a non-empty image:
Job unexpectedly ran in DockerInherited image:Check for image: from default, extends, or templates
"Cannot connect to the Docker daemon"Docker daemon downConfirm the daemon is running, then re-run
Image pull failsAuth / not found / rate limitConfirm the image name/tag and registry access; check contextual event messages for the exact error
Docker job fails before script startsDocker setup issueCheck Docker daemon status and image availability
Cache restore "miss" or no cache sectionsCache misconfigurationConfirm cache: is in the resolved job; check event messages for cache restore or save activity

For provider failures before a command starts, inspect the job state and contextual event messages: