How the Sandcastle `resumeSession` Feature Restores Claude Code Sessions
The resumeSession feature lets you resume a previously saved Claude Code session by validating the session ID, copying the JSONL file into the sandbox, and appending the --resume flag to the agent CLI command.
Sandcastle is an isolation framework for AI agents that runs Claude Code inside ephemeral sandboxes. The resumeSession option enables persistent agent workflows by restoring conversation state across distinct sandbox executions, ensuring long-running tasks can pause and resume without losing context.
Input Validation in run.ts
When you invoke run({ resumeSession: "abc-123" }), the entry point in src/run.ts performs strict validation before accepting the resume request.
The function checks two critical conditions on lines 52-58 and 76-84:
- Single iteration requirement:
maxIterationsmust be set to1because the resume hook only applies to the first iteration - File existence: The referenced session file must exist on the host filesystem at
~/.claude/projects/<encoded>/abc-123.jsonl
If either check fails, the function throws an Error with a descriptive message preventing invalid resume attempts.
Session Transfer Between Host and Sandbox
Once validated, Sandcastle transfers the session file from the host into the isolated sandbox environment. This process involves two core components in src/SessionStore.ts and src/Orchestrator.ts.
SessionStore Abstractions
The SessionStore.ts file defines concrete implementations for both host and sandbox storage:
hostSessionStore: Reads and writes JSONL files in~/.claude/projects/<encoded>/sandboxSessionStore: Handles file operations through the bind-mount sandbox handle
The unified API transferSession(from, to, id) on lines 119-136 orchestrates the copy operation between these stores (lines 20-70 define the store implementations).
Orchestrator Execution
The src/Orchestrator.ts file manages the per-iteration loop. On lines 79-99, when i === 1 and a resumeSession value is present, the orchestrator:
- Constructs a sandbox-side store and host-side store
- Invokes
transferSessionto copy the JSONL file into the sandbox's~/.claude/projects/<encoded>/directory - Uses
bindMountHandle.copyFileInfor bind-mount providers or container-specific copy mechanisms for isolated sandboxes
Passing the Resume Flag via AgentProvider.ts
After transferring the session file, Sandcastle must instruct Claude Code to load it. In src/AgentProvider.ts, the buildPrintCommand method (lines 70-74) checks for the resumeSession option and appends --resume <id> to the generated CLI command.
This flag directs Claude Code to restore its internal state from the supplied JSONL, preserving conversation history, tool calls, and token usage from the previous run.
Error Handling and Edge Cases
The resume flow includes specific error handling mechanisms:
- Missing session: If the session file does not exist during validation,
run.tsthrows a clear error message (lines 77-84) - Transfer failures: If the copy operation fails due to permissions or network issues, the orchestrator wraps the error in a
SessionCaptureError(lines 92-98 inOrchestrator.ts)
These checks ensure that resume attempts fail fast with actionable feedback rather than silent failures inside the sandbox.
Complete Usage Example
To resume a session in your Sandcastle script:
import { run } from "./src/run.js";
import { claudeCode } from "./src/AgentProvider.js";
import { docker } from "./src/SandboxFactory.js";
await run({
agent: claudeCode("claude-opus-4-7"),
sandbox: docker({ imageName: "sandcastle:myrepo" }),
cwd: "/my/project",
prompt: `
// Existing prompt; must match the one used when the session was saved
// … your instructions …
`,
resumeSession: "abc-123", // ID of the saved Claude Code session
});
This workflow executes three distinct phases:
- Validates that
~/.claude/projects/<encoded>/abc-123.jsonlexists and thatmaxIterationsequals 1 - Copies the session file into the sandbox via
transferSessionbefore the first iteration - Launches
claude --print … --resume abc-123 …inside the sandbox, restoring the previous conversation state
Summary
- Validation: The
resumeSessionfeature requiresmaxIterations: 1and validates the session file exists insrc/run.tsbefore execution - Transfer:
SessionStore.tsprovidestransferSession()to copy JSONL files between host and sandbox stores, invoked byOrchestrator.tson lines 79-99 - CLI Integration:
AgentProvider.tsappends the--resumeflag on lines 70-74 to restore Claude Code's internal state - Error Safety: Missing files trigger immediate errors in
run.ts, while transfer failures raiseSessionCaptureErrorin the orchestrator - Storage Locations: Host sessions reside in
~/.claude/projects/<encoded>/, mirrored inside the sandbox before agent execution
Frequently Asked Questions
What are the requirements for using resumeSession in Sandcastle?
You must set maxIterations to 1 when calling the run() function, and the session ID must correspond to an existing JSONL file in your host's ~/.claude/projects/<encoded>/ directory. The feature only works for the first iteration of the agent loop, as implemented in src/run.ts lines 52-58.
How does Sandcastle move the session file into an isolated sandbox?
The framework uses the transferSession(from, to, id) method defined in src/SessionStore.ts to copy the JSONL file. For bind-mount sandboxes, it uses bindMountHandle.copyFileIn. For isolated containers, it employs docker cp or podman cp mechanisms through the sandboxSessionStore implementation, ensuring the file is available at the expected path inside the sandbox before Claude Code starts.
Why does resumeSession require maxIterations to be 1?
The resume hook only applies to the initial iteration of the agent run. Sandcastle validates this constraint in src/run.ts (lines 76-84) because resuming a session implies continuing a single, specific conversation rather than running multiple independent iterations, which would each require their own session management logic.
What error occurs if the session file is missing?
If the referenced session file does not exist on the host filesystem, the run() function throws an Error with a descriptive message during the validation phase (lines 77-84 of src/run.ts). This prevents the orchestrator from attempting to transfer a non-existent file and failing silently inside the sandbox.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →