---
adr_number: 15
title: Sandbox and Checkpoint
status_history:
- - '2026-02-16'
  - Proposed
  - Jeffrey Phillips Freeman
- - '2026-02-16'
  - Accepted
  - Jeffrey Phillips Freeman
tier: 3
authors:
- Jeffrey Phillips Freeman
superseded_by: null
related_adrs:
- number: 6
  title: Plan Lifecycle
  relationship: Sandboxes are created per-plan and destroyed on plan completion or reversion
- number: 8
  title: Resource System
  relationship: Sandbox strategy is determined by resource type (git_worktree, filesystem_copy, etc.)
- number: 11
  title: Tool System
  relationship: Tool invocations create checkpoints for granular rollback
- number: 28
  title: Agent Skills Standard (AgentSkills.io)
  relationship: Sub-tool-calls within Agent Skill execution are individually checkpointed
- number: 29
  title: Model Context Protocol (MCP) Adoption
  relationship: MCP tool execution must respect sandbox boundaries via path rewriting
- number: 35
  title: Decision Tree Rollback and Replay
  relationship: Decision-aligned checkpoints extend the checkpoint system for coordinated rollback during Execute-phase corrections
- number: 36
  title: Resource DAG Operational Semantics
  relationship: Formalizes sandbox boundaries as a DAG property with the sandbox boundary algebra
- number: 38
  title: Cross-Mechanism Sandbox Coordination
  relationship: Extends sandbox coordination to cross-mechanism scenarios with coherence and write-then-sync
acceptance:
  votes_for:
  - voter: Jeffrey Phillips Freeman <Jeffrey.Freeman@CleverThis.com>
    comment: Lazy sandboxing with per-resource-type strategies avoids unnecessary overhead while keeping changes reversible
  votes_against: []
  abstentions: []
---
## Context

Plans modify project resources — source code, configuration files, databases — during the Execute phase. These modifications must be isolated from the real project until they are reviewed and approved during Apply. If execution fails partway through, the system must be able to roll back to a known-good state. Different resource types require different isolation mechanisms (git worktrees for source code, filesystem copies for non-git directories, transaction rollback for databases).

## Decision Drivers

- Execute-phase modifications must be isolated from real project resources until reviewed and approved during Apply
- Different resource types require different isolation mechanisms (git worktrees, filesystem copies, database transactions)
- Fine-grained rollback to individual tool invocations is needed rather than reverting entire phases
- Sandboxing overhead should be avoided for resources the plan never touches (lazy over eager)
- Concurrent plans must not interfere with each other's sandboxed state

## Decision

CleverAgents uses **per-plan sandboxes** with **lazy sandboxing** (resources sandboxed only when first accessed) and **five isolation strategies** selected per resource type. Checkpointing is integrated at the tool level — each tool declares whether it supports checkpoints, and the system creates checkpoints before write operations to enable fine-grained rollback.

## Design

### Sandbox Principles

1. **Lazy sandboxing**: Resources are sandboxed only when first accessed during execution, not eagerly at plan start. This avoids unnecessary copies for resources that the plan may not touch.
2. **Per-plan sandboxes**: Each plan (including child plans) has its own sandbox. No sandbox sharing between plans.
3. **Resource-defined strategy**: The sandbox strategy is defined by the resource type, with a global default override via `sandbox.strategy` (default: `git_worktree`).
4. **Cleanup behavior**: Cleanup before exit; abandoned sandboxes cleaned on next run; completed sandboxes based on retention policy (`sandbox.cleanup`: `on_apply`, `on_terminal`, or `manual`).

### Five Isolation Strategies

**git_worktree** — Creates a git worktree with a plan-specific branch. Rollback via git reset/checkout. The default strategy for `git-checkout` resources. Provides full isolation while sharing the repository's object store.

**filesystem_copy** (copy_on_write) — Copies the target directory. Rollback via restoring from the original snapshot. Used for `fs-directory` resources.

**overlay** — Overlay filesystem mount. Writes go to an overlay layer; rollback by discarding the overlay. Used for `fs-mount` resources. More efficient than full copy for large directories.

**transaction_rollback** — Database transaction with rollback capability. Used for custom database resource types. Changes within the transaction are invisible to other connections until committed.

**none** — No isolation. Used for read-only resources or resources that cannot be sandboxed (e.g., external APIs). Requires `require_sandbox: false` in the automation profile.

### Multi-Resource Sandboxing

When a plan operates on multiple resources:
- Each resource gets its own sandbox with its own strategy.
- Apply commits each resource's sandbox separately.
- Partial apply is possible — some resources may be committed while others are not.
- Shared resources (linked to multiple projects in a multi-project plan) get a single sandbox.

### Checkpointing

Checkpointing operates at the tool level. Each tool declares:

- `checkpointable`: Boolean — whether the tool supports checkpointing.
- `checkpoint_scope`: The granularity of the checkpoint — `file`, `transaction`, `commit`, or `snapshot`.
- `rollback_mechanism`: How rollback is performed.

Per-source checkpoint mechanisms:

| Source | Mechanism |
|--------|-----------|
| Built-in file ops | Git commit in worktree |
| Built-in git ops | Git reflog |
| MCP tools | MCP checkpoint protocol (if supported) |
| Agent Skills | Snapshot-based |
| Custom tools | Tool-declared mechanism |

Checkpoint creation is automatic before write operations when `sandbox.checkpoint.enabled` is `true` (default). Maximum checkpoints per plan: `sandbox.checkpoint.max-per-plan` (default: 50). When exceeded, oldest checkpoints are pruned (keeping the first and most recent).

### Execution as Transactions

Each execution step is treated as a transaction: on success, a checkpoint is committed; on failure, the step is rolled back to the previous checkpoint. This enables fine-grained recovery without re-executing the entire plan.

### Checkpoint Configuration

| Key | Default | Description |
|-----|---------|-------------|
| `sandbox.checkpoint.enabled` | `true` | Global checkpoint enable/disable |
| `sandbox.checkpoint.dir` | `<data-dir>/checkpoints` | Storage directory (subdirectory per plan ULID) |
| `sandbox.checkpoint.max-per-plan` | `50` | Maximum checkpoints retained |

Plans can require checkpoints via the `require_checkpoints` flag. If enabled, only tools with `checkpointable: true` are permitted.

## Constraints

- All resource modifications during Execute must happen in a sandbox. Direct modification of real resources is prohibited (unless `sandbox.strategy: none` is explicitly configured and the automation profile allows it).
- Lazy sandboxing means sandbox creation is deferred until first access. The system must handle the case where sandbox creation fails at access time.
- Checkpoint pruning must keep the first and most recent checkpoints. Intermediate checkpoints are pruned oldest-first.
- Each plan's sandbox is independent. Cross-plan sandbox access is not permitted.
- The `require_checkpoints` plan flag, when enabled, rejects tools that declare `checkpointable: false`.

## Consequences

### Positive
- Sandboxed execution ensures that incomplete or failed work never contaminates real project resources.
- Lazy sandboxing avoids unnecessary resource copying for resources the plan does not touch.
- Tool-level checkpointing enables fine-grained rollback without re-executing entire phases.
- Five strategies cover the range of resource types from git repos to databases to APIs.
- Per-plan sandboxes prevent interference between concurrent plans.

### Negative
- Sandbox management adds complexity and resource overhead (disk space for copies/worktrees, checkpoint storage).
- Lazy sandboxing introduces a potential failure point mid-execution when the sandbox is first created.
- The `none` strategy creates a gap in isolation guarantees for resources that cannot be sandboxed.

### Risks
- Disk space exhaustion from sandbox copies and checkpoints, especially for large repositories or many concurrent plans.
- Git worktree creation may fail if the repository is in a conflicting state (e.g., another worktree exists for the same branch).
- Overlay filesystem may not be available on all platforms (requires kernel support).

## Alternatives Considered

**Eager sandboxing (sandbox all resources at plan start)** — Simpler but wastes resources. A plan targeting a project with 10 linked resources may only modify 2 of them. Lazy sandboxing avoids copying the other 8.

**No checkpointing (full rollback only)** — Simpler but coarse-grained. If step 47 of 50 fails, the entire sandbox must be reverted instead of just step 47.

## Compliance

- **Isolation tests**: Integration tests verify that sandbox modifications are invisible to the real project until Apply.
- **Strategy tests**: Each of the five strategies has tests for creation, modification, rollback, and cleanup.
- **Checkpoint tests**: Tests verify checkpoint creation, rollback to specific checkpoints, and pruning behavior.
- **Lazy sandbox tests**: Tests verify that sandbox creation is deferred until first resource access and handles creation failures gracefully.
- **Cleanup tests**: Tests verify that sandbox cleanup occurs at the correct lifecycle point (on_apply, on_terminal, manual).
