Skip to main content

Host provider

The Host provider runs jobs directly on the local machine shell during loom run --local. It is the fastest path to execution — no containers, no image pulls, no startup overhead.

When Loom uses host

Loom selects the Host provider when a job has no image: value in its resolved definition:

lint:
stage: ci
target: linux
script:
- task lint

If a job sets image:, Loom uses the Docker provider instead.

Prerequisites

  • A POSIX shell available as sh in PATH.
  • Required tools installed in the local environment.
  • Linux local execution target (current MVP scope).

Runtime behavior

The Host provider:

  1. Executes via sh — runs each script entry as sh -lc "<instrumented script>" (or sh -x -c when debug tracing is enabled via LOOM_DEBUG_TRACE).
  2. Inherits the local environment — the process environment of loom run --local is inherited, then job variables: are applied on top.
  3. Captures output — stdout, stderr, and exit code are recorded into structured runtime events.
  4. Sets LOOM_PROVIDER=host — this variable is available in every host job.

Shell rules and gotchas

Host jobs execute under POSIX sh. Each script: entry is a single command string — embedded newlines are not allowed. For the full syntax rules, see Syntax (v1) → script.

Multiline YAML blocks are rejected

Using | produces embedded newlines and fails validation:

# BAD — will not validate
bad:
stage: ci
target: linux
script:
- |
echo "this has a newline"
echo "and will not validate"

Instead, use separate list entries:

# GOOD — each entry is a single command
good:
stage: ci
target: linux
script:
- echo "first command"
- echo "second command"

Variable expansion

Host uses sh, not bash. Prefer portable constructs:

script:
- printf '%s\n' "$MY_VAR"

Avoid bash-specific features like [[ ]], arrays, or process substitution.

Environment inheritance and security

Host jobs inherit the full environment of the loom run --local process. This can unintentionally expose local credentials, proxy settings, or secrets exported in your shell.

Best practices:

  • Use explicit variables: for every value the job needs. Don't rely on ambient environment.
  • If sharing logs or receipts for support, follow What to share — avoid pasting raw environment dumps.
  • For stronger isolation, consider the Docker provider which starts with a clean container environment.

Deterministic toolchains

Host execution depends on local machine state. Two developers with different tool versions will get different results.

Strategies to reduce drift:

StrategyExample
Pin tool versionsUse lockfiles (pnpm-lock.yaml, go.sum) and explicit version specs
Use a task runnertask lint ensures the same commands run everywhere
Wrap with NixRunning tools inside a Nix shell pins exact versions across machines

Confirming the Host provider ran

  1. Check the resolved workflow: the job must have no image:. If you use templates or defaults, inspect the output of loom compile --workflow .loom/workflow.yml.
  2. Check runtime logs: follow the pointer chain from pipeline/manifest.jsonjobs/<job_id>/manifest.jsonsystem/provider/events.jsonl. The provider events record host as the selected provider.

For the full log structure, see the Runtime logs contract.

Troubleshooting

Error / symptomCauseFix
shell "sh" not found in PATHsh not availableInstall a POSIX shell or fix PATH
Tool not found errorsMissing dependenciesInstall the required tools in your local environment
Different behavior than Docker jobEnvironment mismatchConfirm the job does not set image: — host inherits local state while Docker uses a clean image
Script fails with "newline in command"Multiline YAML blockUse separate script: list entries instead of | blocks

Limitations

  • Host runs depend on the local machine environment — no built-in isolation.
  • Host provider selection is automatic when no image: is set; there is no separate flag to force it.
  • Weaker reproducibility compared to Docker — results vary with local tool versions and configuration.