Skip to main content

Isolated workspace

During setup, loom run --local creates an isolated workspace: a disposable, on-disk snapshot where jobs execute. It separates execution from your live checkout and excludes ignored files. It does not isolate host processes or guarantee the same result as CI.

If a command fails, use the printed isolated workspace path to reproduce the command against the exact source snapshot. Use the printed run ID to inspect persistent state and events; declared artifacts are stored separately in the live checkout.

Why it exists​

The snapshot lets you inspect and rerun commands against the source used by the run. Missing ignored files can expose dependencies on local state. Host tools, environment variables, user config, secrets, and external services can still affect the result.

When comparing with CI, match the source, tool versions or image digest and platform, variables, services, secrets, and external inputs. Uncommitted source in a local snapshot may differ from the source checked out in CI.

What gets snapshotted​

Loom starts from HEAD and includes your uncommitted source changes:

SourceIncluded?Details
HEAD commitYesLoom clones the repo and checks out HEAD in detached mode
Modified tracked filesYesDirty changes to tracked files are copied into the snapshot
Added/renamed tracked filesYesStaged additions and renames are applied
Deleted tracked filesYesTracked deletions are removed from the snapshot
Untracked, non-ignored filesYesFiles visible to git status (not in .gitignore) are copied
Gitignored filesNoFiles matched by .gitignore are excluded
SymlinksPreservedSymlinks are copied as symlinks (targets are not dereferenced)
Non-regular filesNoDevices, sockets, and other special files are not supported

If a command behaves differently in the snapshot, check whether it depends on an ignored file that Loom excluded.

Shared Git object stores​

Loom supports direct local object stores listed in .git/objects/info/alternates, including clones created with git clone --shared. Entries may be absolute paths or relative paths resolved from the selected checkout's object database directory (.git/objects). Loom reads committed objects from those stores while keeping the selected checkout's HEAD, branch, and working files. It does not copy the lending repository's working files or modify its object store.

Only one hop is supported. Environment-only GIT_ALTERNATE_OBJECT_DIRECTORIES, HTTP alternates, chained or cyclic alternate layouts, and linked worktrees of shared clones are outside this support. This does not add submodule support. Encountered chains or cycles stop snapshot preparation with a diagnostic.

If an alternate directory is missing, unreadable, malformed, or cannot supply the required objects, Loom stops before jobs start, removes the temporary snapshot, and reports alternate-store repair advice. Restore access to the referenced local store, or create a standalone clone with its own objects, for example git clone --no-local /path/to/healthy-repository /path/to/standalone-checkout. Preserve any uncommitted changes separately when moving to a fresh clone.

How to use it​

1. Find the path​

Local runs print the isolated workspace path near the start of output:

isolated workspace: /tmp/loom-run-local-1772666574190575000-3847261095

Copy this path when you need to inspect or rerun against the source snapshot.

2. Inspect the snapshot​

The snapshot looks like a normal repo checkout. It is the execution workspace, not the persistent runtime-artifact destination:

/tmp/loom-run-local-<run_id>-*/
apps/
libs/
packages/
.git/ # real git clone (detached HEAD)

3. Check run artifacts​

Execution workspaces are disposable. The run's persistent recording directory is .loom/.runtime/runs/<run_id>/ in the live checkout. It contains state.jsonl for workflow, job, step and command transitions, and events.jsonl for contextual messages and stdout/stderr. Read them with loom logs <run_id> --state and loom logs <run_id> --json, or MCP loom_read_run and loom_read_events.

Declared artifact files are retained separately under .loom/.runtime/artifacts/<run_id>/jobs/<job-id>/. Their publication messages appear in the same run event stream. Deleting the execution workspace preserves both the recording and published files. See Runtime logs.

4. Reproduce failures​

Before changing anything in your main checkout, try reproducing from inside the isolated workspace:

cd /tmp/loom-run-local-<run_id>-*
loom run --local --workflow .loom/workflow.yml

This starts another run from that source snapshot. Environment variables, tools, configuration, and external services can still differ. Check those inputs as well as files when reproducing a failure.

Disk usage and cleanup​

Because each snapshot is a full copy of your repo, it can use significant disk space for large repositories.

BehaviorDetails
LocationOS temp directory (e.g., /tmp/loom-run-local-<run_id>-*)
On preparation failureSnapshot directory is cleaned up automatically
On run success or failureSnapshot is preserved for debugging
Manual cleanupDelete the directory when done — it is fully disposable

Deleting the snapshot does not delete recorded state, events, or published job artifacts in the live checkout's .loom/.runtime/ directory.

Common pitfalls​

PitfallFix
Debugging in your original checkout instead of the snapshotAlways cd into the printed isolated workspace path first
Depending on a gitignored file (e.g., .env.local)Commit the file, pass values via variables:, or generate it in a script: step
Assuming "snapshot" means remote executionThe snapshot is for local reproducibility only — it does not imply remote execution
Referencing ~/... paths during debuggingStay within the snapshot directory to reproduce what Loom actually ran

Example: gitignored file causes failure​

A common "it works on my machine" scenario:

  1. You have a gitignored config file (e.g., .env.local) in your checkout.
  2. Your script reads it implicitly (directly, or via tooling that auto-loads it).
  3. The isolated workspace does not include that file, so the job runs with different configuration and fails.

Fix options:

  • Commit the config if it's not sensitive.
  • Pass values explicitly via workflow or job variables: — see Variables.
  • Generate the file inside the job as an explicit script: step (avoid printing secrets).

The workflow file itself is gitignored​

The same exclusion applies to the workflow file you pass to loom run. If it is untracked and matched by a .gitignore rule (for example a generated .loom/ci.yml under an ignored .loom/ directory), the snapshot cannot contain it. Loom stops before any Docker work, removes the snapshot directory, and reports the cause:

loom run: prepare isolated workspace: workflow file ".loom/ci.yml" is excluded from the isolated workspace because it matches a .gitignore rule; commit it or remove the rule

Fix options:

  • Commit the workflow file so it is part of HEAD.
  • Remove or narrow the .gitignore rule; a negation such as !.loom/ci.yml also re-includes it.

Privacy and secrets​

Treat the isolated workspace as potentially sensitive:

  • It contains your source code and command-generated files.
  • The live checkout's .loom/.runtime/ may contain logs and published artifacts with environment details, commands, and error output.
  • Loom redacts exact secret matches in supported console, state and event output. Transformed values and raw artifacts are outside that protection; review them before sharing externally.

See What to share for guidance on what's safe to share.

Docker workspace mount modes​

When Docker jobs execute inside the isolated workspace, the workspace is mounted into the container using one of two modes:

  • bind_mount — the isolated workspace directory is bind-mounted directly into the container at /workspace. Artifact matching reads that snapshot after execution.
  • ephemeral_volume (default) — a Docker volume is created and seeded with the snapshot. Candidate artifact roots are exported to private staging before the volume is removed; Loom then applies includes and excludes and publishes only selected files to the persistent destination.

Configure with the --docker-workspace-mount flag, LOOM_DOCKER_WORKSPACE_MOUNT environment variable, or runtime.docker.workspaceMount in repo or user config, in that precedence order. See Docker provider for details.

  • Runtime logs — how to navigate the persistent structured log tree in the live checkout
  • Run evidence and receipts — current recording and validation receipts
  • Variables — pass configuration into jobs without relying on local files
  • Cache — cached outputs are restored inside the isolated workspace
  • Docker provider — workspace mount modes and container behavior
  • CLI loom run — full flag reference for local runs