# How Session Capture Works in Sandcastle Using `sandboxSessionStore`

> Learn how session capture works in Sandcastle using sandboxSessionStore to extract, transfer, and persist AI agent session files for analysis. Understand the process clearly.

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

---

**Sandcastle captures AI agent sessions by using `sandboxSessionStore` to extract JSONL session files from a running container, `transferSession` to rewrite path references from sandbox to host paths, and `hostSessionStore` to persist the final file on your local filesystem for later analysis.**

Session capture in Sandcastle enables you to record every interaction between the Claude Code agent and your codebase inside a sandboxed environment. This feature leverages the `sandboxSessionStore` abstraction to move session files from ephemeral containers to persistent host storage, making debugging and audit logging possible. According to the mattpocock/sandcastle source code, the implementation relies on a bind-mount handle and a path-rewriting transfer mechanism to ensure session integrity across filesystem boundaries.

## The Session Capture Architecture

Sandcastle’s session capture system comprises three coordinated components defined in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts).

### Host Session Store (`hostSessionStore`)

The **host session store** manages JSONL files on your local filesystem. Located at lines 57-75 in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts), this implementation creates the necessary directory structure under `~/.claude/projects/<encoded-cwd>/` and provides methods to read and write session files. It returns absolute paths via `sessionFilePath(id)` and handles the final persistence of captured sessions.

### Sandbox Session Store (`sandboxSessionStore`)

The **sandbox session store** acts as a bridge to the containerized environment. Implemented at lines 91-135 in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts), this store accepts a `bindMountHandle` (providing `copyFileIn`, `copyFileOut`, and `exec` capabilities) to manipulate files inside the sandbox. It uses POSIX path joins for container-side paths and translates high-level storage operations into bind-mount file transfers. This component is essential because it allows Sandcastle to access session files while the sandbox process is still alive.

### Session Transfer Helper (`transferSession`)

The **`transferSession`** function handles the actual migration of session data between stores. Found at lines 142-170 in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts), this utility reads the entire JSONL from the source store, rewrites every `"cwd"` field from the sandbox working directory to the host working directory, and writes the transformed payload to the destination. This path rewriting ensures that session logs remain valid references when moved from container to host.

## How the Orchestrator Triggers Session Capture

The capture logic executes within [`src/Orchestrator.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/Orchestrator.ts) (lines 68-99) after the agent finishes running. The **orchestrator** determines whether to capture based on the `provider.captureSessions` flag defined in [`src/AgentProvider.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/AgentProvider.ts) (lines 115-120).

When `captureSessions` evaluates to true alongside a valid `sessionId` and `bindMountHandle`, Sandcastle executes the following sequence:

1. **Initialize stores**: Creates a sandbox-side store using `sandboxSessionStore(ctx.sandboxRepoDir, bindMountHandle, sandboxProjectsDir)` and a host-side store using `hostSessionStore(hostRepoDir, hostProjectsDir)`.

2. **Transfer data**: Invokes `transferSession(sbStore, hStore, sessionId)` to move the JSONL file while rewriting path references.

3. **Record path**: Stores `hStore.sessionFilePath(sessionId)` in the `OrchestratorResult` as `sessionFilePath`.

4. **Parse usage**: Optionally calls `provider.parseSessionUsage` if implemented, reading the captured file via `hStore.readSession(sessionId)` to extract token statistics.

This process occurs while the sandbox process remains alive, guaranteeing access to temporary container files through the bind-mount handle.

## Implementing Session Capture in Your Code

You can interact with session capture programmatically using the store factory functions and transfer utilities.

### Manual Session Capture

To manually transfer a session between sandbox and host:

```typescript
import {
  hostSessionStore,
  sandboxSessionStore,
  transferSession,
} from "sandcastle/src/SessionStore";
import type { BindMountSandboxHandle } from "sandcastle/src/SandboxProvider";

async function captureSession(
  sessionId: string,
  hostCwd: string,
  sandboxCwd: string,
  bindMount: BindMountSandboxHandle,
) {
  const hostStore = hostSessionStore(hostCwd);
  const sandboxStore = sandboxSessionStore(
    sandboxCwd,
    bindMount,
    "/root/.claude/projects",
  );

  await transferSession(sandboxStore, hostStore, sessionId);
  return hostStore.sessionFilePath(sessionId);
}

```

### Configuring Provider Settings

Claude Code providers enable session capture by default via the `captureSessions` flag:

```typescript
import { claudeCode } from "sandcastle/src/AgentProvider";

// Enable capture (default)
const provider = claudeCode("claude-sonnet-4-6", {
  captureSessions: true,
});

// Disable capture for faster runs
const fastProvider = claudeCode("claude-sonnet-4-6", {
  captureSessions: false,
});

```

### Reading Captured Sessions

Access captured session data after transfer:

```typescript
import { hostSessionStore } from "sandcastle/src/SessionStore";

async function analyzeSession(hostCwd: string, sessionId: string) {
  const store = hostSessionStore(hostCwd);
  const jsonlContent = await store.readSession(sessionId);
  console.log("Session interactions:", jsonlContent);
}

```

## Summary

- **`sandboxSessionStore`** provides container-side file access via bind-mount handles, enabling session extraction from running sandboxes.
- **`transferSession`** rewrites `cwd` paths during the copy operation to ensure session files reference host paths rather than ephemeral container directories.
- **`hostSessionStore`** persists captured sessions to `~/.claude/projects/<encoded-cwd>/` on the local filesystem.
- The **orchestrator** coordinates the capture automatically when `provider.captureSessions` is true, storing the final path in `OrchestratorResult`.
- Session capture requires a **bind-mount handle** and occurs while the sandbox process remains active to ensure file accessibility.

## Frequently Asked Questions

### How does `sandboxSessionStore` access files inside a running container?

The `sandboxSessionStore` function receives a `BindMountSandboxHandle` parameter containing methods like `copyFileIn`, `copyFileOut`, and `exec`. As implemented in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts) (lines 91-135), these methods interact with the container's filesystem through bind mounts, allowing the store to read and write files without requiring SSH or network protocols. This design ensures session files remain accessible while the sandbox process is alive.

### What path transformations occur during session transfer?

According to [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts) (lines 142-170), the `transferSession` function performs a search-and-replace operation on every line of the JSONL session file. It identifies `"cwd"` fields containing the sandbox working directory and rewrites them to match the host working directory. This transformation ensures that file references in the captured session remain valid when analyzed on the host system outside the container.

### Can I use session capture with non-Claude Code agents?

Session capture is supported for any provider that sets `captureSessions` to `true` in [`src/AgentProvider.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/AgentProvider.ts) (lines 115-120). However, Claude Code defaults to enabling this feature while other providers may disable it if they do not generate compatible session files. You must also ensure the provider returns a valid `sessionId` and that you are using a bind-mount sandbox handle rather than an SSH-based one.

### Where are captured sessions stored on the host filesystem?

Captured sessions are written to `~/.claude/projects/<encoded-cwd>/` as JSONL files. The `hostSessionStore` implementation in [`src/SessionStore.ts`](https://github.com/mattpocock/sandcastle/blob/main/src/SessionStore.ts) (lines 57-75) handles directory creation and file management, returning absolute paths via `sessionFilePath(id)`. The orchestrator stores this path in the `sessionFilePath` property of the `OrchestratorResult` object returned after agent execution.