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:
| Source | Included? | Details |
|---|---|---|
HEAD commit | Yes | Loom clones the repo and checks out HEAD in detached mode |
| Modified tracked files | Yes | Dirty changes to tracked files are copied into the snapshot |
| Added/renamed tracked files | Yes | Staged additions and renames are applied |
| Deleted tracked files | Yes | Tracked deletions are removed from the snapshot |
| Untracked, non-ignored files | Yes | Files visible to git status (not in .gitignore) are copied |
| Gitignored files | No | Files matched by .gitignore are excluded |
| Symlinks | Preserved | Symlinks are copied as symlinks (targets are not dereferenced) |
| Non-regular files | No | Devices, 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.
| Behavior | Details |
|---|---|
| Location | OS temp directory (e.g., /tmp/loom-run-local-<run_id>-*) |
| On preparation failure | Snapshot directory is cleaned up automatically |
| On run success or failure | Snapshot is preserved for debugging |
| Manual cleanup | Delete 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
| Pitfall | Fix |
|---|---|
| Debugging in your original checkout instead of the snapshot | Always 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 execution | The snapshot is for local reproducibility only — it does not imply remote execution |
Referencing ~/... paths during debugging | Stay within the snapshot directory to reproduce what Loom actually ran |
Example: gitignored file causes failure
A common "it works on my machine" scenario:
- You have a gitignored config file (e.g.,
.env.local) in your checkout. - Your script reads it implicitly (directly, or via tooling that auto-loads it).
- 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
.gitignorerule; a negation such as!.loom/ci.ymlalso 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.
What to read next
- 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