# How the Sandcastle `resumeSession` Feature Restores Claude Code Sessions

> Discover how Sandcastle's resumeSession feature restores Claude Code sessions by validating IDs, copying JSONL, and appending the resume flag. Learn more now.

- Repository: [Matt Pocock/sandcastle](https://github.com/mattpocock/sandcastle)
- Tags: how-to-guide
- Published: 2026-05-24

---

**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`](https://github.com/mattpocock/sandcastle/blob/main/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**: `maxIterations` must be set to `1` because 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`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts) and [`src/Orchestrator.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/Orchestrator.ts).

### SessionStore Abstractions

The [`SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/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`](https://github.com/mattpocock/sandcastle/blob/main/src/Orchestrator.ts) file manages the per-iteration loop. On lines 79-99, when `i === 1` and a `resumeSession` value is present, the orchestrator:

1. Constructs a sandbox-side store and host-side store
2. Invokes `transferSession` to copy the JSONL file into the sandbox's `~/.claude/projects/<encoded>/` directory
3. Uses `bindMountHandle.copyFileIn` for 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`](https://github.com/mattpocock/sandcastle/blob/main/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.ts`](https://github.com/mattpocock/sandcastle/blob/main/run.ts) throws 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 in [`Orchestrator.ts`](https://github.com/mattpocock/sandcastle/blob/main/Orchestrator.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:

```typescript
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:

1. Validates that `~/.claude/projects/<encoded>/abc-123.jsonl` exists and that `maxIterations` equals 1
2. Copies the session file into the sandbox via `transferSession` before the first iteration
3. Launches `claude --print … --resume abc-123 …` inside the sandbox, restoring the previous conversation state

## Summary

- **Validation**: The `resumeSession` feature requires `maxIterations: 1` and validates the session file exists in [`src/run.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/run.ts) before execution
- **Transfer**: [`SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/SessionStore.ts) provides `transferSession()` to copy JSONL files between host and sandbox stores, invoked by [`Orchestrator.ts`](https://github.com/mattpocock/sandcastle/blob/main/Orchestrator.ts) on lines 79-99
- **CLI Integration**: [`AgentProvider.ts`](https://github.com/mattpocock/sandcastle/blob/main/AgentProvider.ts) appends the `--resume` flag on lines 70-74 to restore Claude Code's internal state
- **Error Safety**: Missing files trigger immediate errors in [`run.ts`](https://github.com/mattpocock/sandcastle/blob/main/run.ts), while transfer failures raise `SessionCaptureError` in 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`](https://github.com/mattpocock/sandcastle/blob/main/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`](https://github.com/mattpocock/sandcastle/blob/main/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`](https://github.com/mattpocock/sandcastle/blob/main/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`](https://github.com/mattpocock/sandcastle/blob/main/src/run.ts)). This prevents the orchestrator from attempting to transfer a non-existent file and failing silently inside the sandbox.