Resume on any machine
When several machines share one storage database, a session or workflow run started on one machine can continue on any of them. Atomic finds the session in the shared storage, rebuilds the repository state it was working against, and continues the conversation where it stopped.Join each machine
Every machine must use the same shared storage. Install the libSQL adapter and join the database on each one:atomic storage join keeps sessions and workflow runs in the shared database, so both resume on any joined machine. atomic team join shares workflow runs and Intercom but keeps sessions on each machine, so with it only workflow runs resume elsewhere; to share sessions on a machine joined that way, run atomic team leave and then atomic storage join. See Sharing storage across hosts for prefixes, tokens and atomic storage status.
Keep snapshots on (snapshots.enabled, the default). A session records the state of each Git checkout it changes at the end of every turn that ran a file-writing tool, including uncommitted edits, untracked files and commits that were never pushed. That record lives in the shared storage, so a joined machine needs nothing else. Work inside submodules and in untracked repositories nested in the checkout is not recorded. A resume names each such path in a warning (nested-repository, submodule-changes, unpushed-submodule-commit); commit and push that work to bring it along. See What is left out.
Resume a session
Resume as usual, withatomic --session <id>, atomic --resume or /resume. When the session’s checkout is missing or changed on this machine:
- If you start Atomic inside a checkout of the same repository and its files match what the session recorded, the session continues there.
- Otherwise Atomic restores the recorded state into a worktree under
~/.atomic/agent/worktree-snapshotsand continues there. It never writes into your checkouts. When an idle worktree of the same repository that Atomic restored earlier holds nothing a snapshot did not record, Atomic resets it to the recorded state and keeps its dependencies and build output, so setup is faster; otherwise it restores into a new worktree. One line names the new worktree. The session holds that worktree while it is open; resuming it again on this machine continues there, unless another session took the worktree meanwhile, in which case it gets a fresh one. See Restored worktrees. - If the recorded state cannot be rebuilt exactly, for example because unpushed commits touch files that are never recorded (
.env, keys), a remote is unreachable, or a snapshot blob is missing, the session still opens with its whole conversation. Atomic restores the best state it can reach: the recorded commit with the uncommitted changes that apply, else the closest commit it can fetch (the last pushed commit, an earlier snapshot’s commit, or the branch tip), else nothing, and then the session continues in its recorded directory, or in the directory you started from when that is not on this machine. One notice says what was restored, what is missing and what to do, for example push the missing commits from the original machine and/resumeagain./session snapshotshows the same. See Resuming. - To see where a slow resume spent its time, run
/session snapshot: its Last resume block lists each restore phase (fetch, materialize, LFS, verify, …) and each blueprint step with its duration.ATOMIC_TIMING=1 atomic --session <id>prints the same lines to stderr. See Inspecting snapshots. - If you start
atomicinside a checkout of the same repository that differs from the recording and has uncommitted or untracked changes, Atomic asks whether to restore a fresh worktree (the default), continue in your checkout as it is, or cancel./resumeand non-interactive modes such as-pdo not ask; they restore a fresh worktree. A clean checkout that differs, such as a fresh clone at another commit, is left alone without asking, and a fresh worktree is restored. A checkout where the recorded edits were committed counts as matching. - A session that worked in several checkouts gets each of them back where it can, also when it worked from a directory outside all of them: the checkout you started in is used for its repository, and every other recorded checkout that is missing here is restored. Only the checkout the session works in has to be restorable. Any other checkout that is missing or changed never stops the resume: one the session worked in on this machine (a sibling worktree, for example) and that changed since continues as it is, and one that cannot be restored is left out. Each checkout that is left out or kept as it is gets a warning that names its path and why, for example
Continuing without restoring /tmp/probe (snapshot 3f2a9c1d7b04): it does not exist on this node, and Git is unavailable here (not-installed), which restoring it needs. If you choose to continue in a checkout that differs, the other checkouts are not restored, and a warning names those that are missing here.
--session id whose recorded directory does not exist on this machine, or that a restore moved to the current directory, opens directly instead of offering to fork the session into the current directory.
An SDK createAgentSession({ sessionManager }) call prepares a supplied session the same way before it starts, unless you pass cwd or workspace. That includes a session whose recorded directory exists on this machine but holds a different tree, for example a runner built from the same image: the session continues in a restored worktree, not in that directory.
When the shared storage does not answer, atomic --session, --resume, --continue and /resume stop after 15 seconds with a retryable ResumeCatalogTimeoutError instead of waiting for the network to give up. Nothing was changed; resume again once atomic storage status reaches the database.
When the session is already open
A session runs in one process at a time.atomic --session, --resume and --continue claim the session they open before they write to it or restore its checkouts. When another process on this machine still has the session open, the resume changes nothing and exits with code 75:
SIGKILL, is taken over by the next resume. The process is matched by its pid and, on Linux, by when it started, so a later process given the same pid does not count as the holder. Claims are files under ~/.atomic/agent/session-claims, so they are seen by the processes that share that agent directory. If a process with another agent directory writes to the same session store at the same time, the run whose write conflicts stops with Another process wrote to session <id> … and exit code 1; resume the session again to continue from what was saved.
Wake a released subagent
A background subagent that was released while it waited keeps its session in the shared storage when it was launched withcontext: "fork", so it can be woken on another machine. The wake maps its recorded directory through the restores of the session that owns it. The subagent’s own session is then prepared as a woken session is: each checkout it worked in on this machine stays as it is, and every other checkout is restored from its snapshots into a worktree on this machine, with its blueprints built. Its tools resolve the earlier machine’s absolute paths there, and follow the restores of the session or run it was launched in. A subagent started without context: "fork" keeps a session file on the machine that launched it, which another machine cannot reopen; it is reported as unrestorable.
Resume a workflow run
Resume a run with/workflow resume <run>, or from the SDK with run(definition, inputs, { runId }). A run restores its checkouts from the snapshots on its checkpoints, once, before it continues; see Worktree snapshots:
- Each checkout gets its latest recorded state. Completed
ctx.toolcalls are not run again; the step that was interrupted runs again in the restored worktree. - A child workflow bound to a repository with
workspace({ repo, branch })continues in its restored worktree, also when its repository or branch exists only on the machine that recorded it. - A run bound to an input worktree (
worktreeFromInputs, asgoalandralphuse) continues in the worktree restored for it. - Children of a pooled run restore their worktree on whichever host claims them, and only hosts that can restore it claim them. A worker host builds the blueprints below, from its own agent directory, in each worktree it restores, before the child starts there; a host given its own
restorefunction builds none. See Workers on other hosts. forkRunon another machine materializes the worktrees recorded where the fork starts, not the source run’s latest state.
run() with the id of a run in shared storage stops after 15 seconds with a retryable ResumeCatalogTimeoutError when the storage does not answer; once it answers, listing the journal’s runs is not bounded, and a retry opens the journal again. /workflow resume with a run id this machine cannot find fails with the journal’s run-not-found error, which tells a machine on local storage only to join the shared storage. run() with a run id its journal does not hold starts a new run under that id, so check with atomic storage status that the machine uses the shared storage before resuming a run from the SDK. If the machine that ran it stopped without releasing it, another machine can take the run over two minutes after its last heartbeat; until then the resume reports that another execution owns it before it restores or sets up anything, and resuming again later continues it.
Set the environment up with a blueprint
A restored worktree contains the repository’s files but not installed dependencies, tools or build output. A blueprint tells Atomic how to set that up again. It is Devin’s blueprint format, with one change: the repository file is.atomic/blueprint.yaml where Devin reads .devin/blueprint.yaml. Atomic reads no .devin/ path.
A section is either a string, which is one
run step, or a list of steps. A list entry may be a bare string. A step is { name?, run, env? } or { name?, uses, with?, env? }, never both run and uses. with is valid only on uses, and its values are strings. uses takes a github.com/<owner>/<repo>[/<subpath>]@<ref> GitHub Action, in initialize and post-build but not in maintenance, where it is rejected with 'uses' steps are not supported in maintenance sections. Node.js and composite actions run; Docker actions, actions Atomic cannot fetch or read, and composite actions that use hashFiles, secrets or matrix expressions fail the step. Fetched actions are cached per ref under ~/.atomic/agent/blueprint-actions; set ATOMIC_BLUEPRINT_GITHUB_BASE_URL to fetch them from another host than https://github.com.
- Shell.
runsteps run in bash (Git Bash on Windows) and stop at the first failing command.shell: powershellruns them in PowerShell on Windows. Commands must not wait for input. - Environment.
envapplies to its own step. A line written to$ENVRC, such asecho "API_URL=http://localhost:3000" >> $ENVRCor anexport PATH=...line, is exported to later steps and to the resumed session’s bash tool. In PowerShell, the file path is$env:ENVRC; append UTF-8 bash assignments with LF line endings and no byte-order mark, since later bash steps source the same file.PATHentries written by bash reach PowerShell and Node.js actions in native Windows path-list format.$ENVRCstarts empty in every build, somaintenancemust not rely on whatinitializewrote to it in an earlier build. - Timeout. A step that runs for 3 hours is stopped and counts as failed.
- Platforms.
runs-onis a string or a list, defaultdefault.defaultandlinuxare the same platform;macosandwindowsare always explicit. A file can hold several---documents, each a mapping, and two documents cannot resolve to the same platform. A machine uses only the document for its own platform; when none matches, nothing runs and nothing is shown. - Includes. The repository blueprint may list workspace directories in
includes. An entry is a directory, or the full path of its blueprint file (<dir>/.atomic/blueprint.yaml; no other file name is read), without.., and each workspace appears once. Includes are not allowed in a workspace blueprint. A missing workspace blueprint, or a missing workspace directory, means that workspace is removed.includesis ignored in the global blueprint, andpost-buildis allowed only there. - Clone.
cloneis accepted and ignored, with a warning: a restore recreates the recorded tree instead of cloning. - Other keys. Keys the format does not define are ignored. A
cache:key earns a one-line warning: list extra cache paths in theresume.cachesetting instead (see Caches for runners).
Builds
When a resume restores a worktree, Atomic builds it, in this order: the global blueprint’sinitialize and maintenance, then each repository’s initialize and maintenance (its included workspaces follow it), then the global post-build. Builds run only for restored worktrees: a checkout the session continues in as it is is never built. A build runs only for a trusted project (--approve or "defaultProjectTrust": "always"); an untrusted worktree is skipped, silently, and the global blueprint runs only when at least one restored worktree is trusted.
Like Devin’s differential builds, a build compares each workspace’s blueprint with the last successful build of that workspace on this machine. An unchanged workspace is inherited: its initialize is skipped and its maintenance runs on top of the existing state. A changed, new or previously failed workspace is rebuilt: initialize and maintenance both run. A workspace that is no longer configured is removed from the record. A full build, where every workspace is rebuilt and the global initialize runs, replaces a differential one when the global blueprint changed or the last full build is older than 7 days. Editing a blueprint is all it takes to retry it.
A step fails when its command exits non-zero, a PowerShell error is raised, or it times out. As in GitHub Actions, the rest of that step stops at once, and as in Devin, “only the setup steps of the failing blueprints did not run”: the remaining initialize steps and the maintenance of that blueprint are skipped, while the other repositories and workspaces keep building. Setup never blocks a resume:
Every step writes a log under
~/.atomic/agent/worktree-snapshots/blueprint-logs with the step’s name, command, start and finish times, duration, exit status or timeout and output; the warning gives the path. The fix is to read the log, fix the environment and the blueprint, and resume: a worktree whose last build failed or never finished is built again on its next resume, whether you resume a session or a workflow run, and an edited blueprint is rebuilt. Builds that run at the same time, for example several pooled children restoring on one host, take turns writing the build record.
Start the first turn while the build runs
By default a resume opens the session once the build has finished. To send the first request while the build still runs, setresume.waitForBlueprint to "tools" in your settings:
bash, powershell, edit, write, read, ls, find, grep, search, and extension tools that write files) wait until the build ends. The first of them then shows how the build went, with the same warnings a resume shows when it waits, before its own output. A failed build releases the tools as a finished one does. Interrupting the turn stops the wait, not the build. If Atomic exits before the build ends, the next resume builds the worktree again.
What the agent sees
The first turn of a resumed session carries each applicable blueprint’smaintenance steps and knowledge items, labelled with what happened: ran in this build, not yet run on this machine (skipped or untrusted), or not run or partial with the failing step and its log. The same holds for the stages of a resumed workflow run and for pooled children that start in a restored worktree: their sessions get that worktree’s context and its $ENVRC variables. The agent re-runs maintenance itself when it finds that dependencies changed. Atomic’s default system prompt also asks the agent to keep .atomic/blueprint.yaml current as part of normal work: to write one when a repository has none, to update it in the same change that adds a dependency, tool or workspace, to record hard-won commands in knowledge, to leave secrets out, and to fix it after a Partial build. It edits ~/.atomic/agent/blueprint.yaml only when you ask.
Caches for runners
On an ephemeral runner, such as a GitHub-hosted one, every resume starts with an empty home directory: dependencies download again, the repository is fetched in full, and Atomic transpiles your extensions again.atomic blueprint cache-key prints a key, a restore prefix and the paths of each cache entry worth keeping, for a cache action such as actions/cache. Atomic never uploads or downloads caches itself.
actions/setup-node and actions/setup-python, it finds package stores from the lockfiles at the repository root, so most repositories need no configuration:
The variables in parentheses move a store, as they do for the tool;
XDG_CACHE_HOME moves the Linux ~/.cache locations. macOS uses ~/Library/Caches (pnpm ~/Library/pnpm/store; npm, uv, Bun, Cargo, Go modules, Gradle and Maven as on Linux), and Windows uses %LOCALAPPDATA% (for example npm-cache, pnpm\store, Yarn\Cache, uv\cache, pip\Cache). Lockfiles below the root, as in a monorepo’s packages, are not searched.
To cache more, such as a store in another location or build output, add resume.cache to the project’s .atomic/settings.json (or your global settings; a project’s list replaces the global one). The blueprint keeps Devin’s format and declares no caches.
paths, an optional kind, and optional keyFiles. A "store" path (the default) is absolute or starts with ~/, and lies outside the worktree; it joins the detected stores. A "build" path is relative to the repository root; it names build output that a trusted job parks under ~/.atomic/agent/worktree-snapshots/seeds/ for a later restore. keyFiles lists root-relative files whose content keys the paths; without it, they are keyed by the files that decide a snapshot’s environment (lockfiles and toolchain files). Paths are plain paths: one with glob characters (*, ?, [, ], {, }) or a leading ! is ignored, since a cache action would read it as a pattern. An invalid entry is left out with a warning.
An entry with no paths is left out. The
git and build entries need a Git remote, since the object store is named after the checkout’s remote URLs. Atomic compares HTTPS remotes, and SSH remotes as the git user that hosting services use, by host and repository path, so git@github.com:acme/app.git, ssh://git@github.com/acme/app and https://github.com/acme/app name the same repository: a runner’s HTTPS checkout gets the entries of a session recorded over SSH. SSH remotes of other users, such as alice@server:repo.git, stay distinct. The build entry also lists the seed manifest that atomic blueprint prebuild --park writes. Paths that could hold credentials (~/.ssh, ~/.cargo with its credentials.toml, ~/.config/gh, .npmrc, .env* and the snapshot deny list), store paths inside the worktree, whether detected or declared, and invalid entries are left out with a warning on stderr. The credential checks ignore letter case and follow symbolic links, so ~/.SSH and a link to ~/.ssh are refused too. They look at the paths, not at the files inside them, which may not exist yet when the keys are printed: declare only directories that hold packages and build output, never one where a tool keeps tokens or keys. --format github-output prints <name>-key, <name>-restore-prefix and <name>-paths lines to append to $GITHUB_OUTPUT; see Caching between runs for a workflow.
Prebuilt worktrees
atomic blueprint prebuild builds a repository ahead of time, so a later resume starts in a worktree whose dependencies and build output are already there:
HEAD of the checkout at dir (default: the current directory) into a new restored worktree, runs the blueprints’ initialize and maintenance there as a resume would, and leaves the worktree idle. The next resume of a session of the same repository on this machine claims it, resets its tracked files to the session’s snapshot and keeps the ignored folders the build filled. Only committed files are restored: ignored and untracked files of the checkout, such as .env, never reach the worktree. The checkout needs a Git remote and no uncommitted changes to tracked files. A prebuild runs project code, so it runs only for a trusted project: one you trusted before, any project with "defaultProjectTrust": "always", or this run with --approve. When a blueprint step fails, the command exits 1, removes the new worktree and keeps earlier ones and their seeds. It prints the restore and each blueprint step with its duration on stderr.
With --park, the build output that resume.cache declares with "kind": "build" moves out of the new worktree into ~/.atomic/agent/worktree-snapshots/seeds/, the paths of the build cache entry, with a manifest naming the commit it was built for. Save them from a trusted job (see Caching between runs). On another machine that restores them, a resume that has no idle worktree to claim restores that commit into a new worktree at the same path the prebuild used, moves the parked output into place, and then claims that worktree for the session’s snapshot. Only files Git does not track are parked: when a build path holds committed files, such as a checked-in dist/, those stay in the worktree, the output beside them is parked and later moved back beside them, and atomic blueprint cache-key warns about the path. Parked output never replaces files that are already there, and output parked for another repository is ignored. When anything about the seed fails, the resume restores a fresh worktree as before. /session snapshot shows such a resume as (seeded), with the time spent moving the output as seed.
resume.setupCommand and .atomic/setup
.atomic/setup is no longer read. resume.setupCommand is deprecated and stays for one release as an alias for one maintenance step of the global blueprint, run in the root of each restored worktree. A resume that builds a worktree prints a deprecation warning while it is set; move the command into the maintenance of .atomic/blueprint.yaml.
What can stop a resume
Missing setup is checked in one pass before anything is restored: the storage adapter and its token (for a session resumed withatomic) and Git. A machine without Git gets a portable Git automatically, as it does for other Git work; only when that is impossible, for example in offline mode or when the download fails, does git-unavailable stop the resume. Every missing piece is reported together, with the command that fixes it. For a session, Git being unavailable never stops the resume: the session continues without restoring its checkouts, in its recorded directory or the directory you started from, with one notice per checkout that names its path and why. A session resume stops only when the session cannot be read, when a snapshot record fails the security checks (invalid-snapshot, for example a remote with credentials or a Git remote helper), or when a restore would write into a directory that holds other files (unsafe-target). A blueprint is never one of them: it is built after the restore and cannot stop the resume.
Secret values never appear in these messages; they name the environment variable or file instead. The classes, their codes and the
isResume…Error guards are exported from @bastani/atomic.
Windows
Sessions and workflow runs resume on Windows as they do elsewhere. Local workers are not available on Windows, because Atomic cannot contain their tool processes there: a run withlocalWorkers fails with SharedPoolSetupError (code process-containment-unavailable) before it starts, so resume pooled runs on Linux or macOS.
Trust
A restored worktree is a new directory, so project trust starts unset there, exactly as for a fresh clone. Until you trust it, project instructions and resources are not loaded and its blueprints are not built; the agent still gets theirmaintenance and knowledge, marked as not yet run.