---
title: Slot Pool Architecture
read_when:
  - "understanding slot pool design"
  - "implementing slot-related features"
  - "debugging slot assignment issues"
last_audited: "2026-02-16 14:20 PT"
audit_result: clean
---

# Slot Pool Architecture

The worktree slot pool is a reusable pool of pre-allocated git worktrees for fast branch switching. Instead of creating and destroying worktrees on demand, erk maintains a fixed-size pool of worktree directories that can be reassigned to different branches.

## Core Concepts

### Pool Basics

- **Pool size**: Default 4 slots, configurable via `[pool] max_slots` in `.erk/config.toml`
- **Slot names**: `erk-slot-NN` format (e.g., `erk-slot-01`, `erk-slot-02`)
- **Placeholder branches**: `__erk-slot-NN-br-stub__` for unassigned slots
- **Pool persistence**: `~/.erk/repos/{repo_name}/pool.json`

### Why a Pool?

Creating git worktrees is relatively slow (file system operations, git setup). The pool enables:

1. **Fast branch switching**: Reuse existing worktrees instead of creating new ones
2. **Resource bounds**: Limit disk usage to a fixed number of worktrees
3. **Automatic eviction**: LRU eviction when pool is full

## Data Structures

### Data Model (`src/erk/core/worktree_pool.py`)

**`PoolState`** — Top-level container with `version`, `pool_size`, `slots`, and `assignments` fields.
**`SlotInfo`** — Slot metadata (just a `name` field).
**`SlotAssignment`** — Maps a branch to a slot with `slot_name`, `branch_name`, `assigned_at`, and `worktree_path`.

See `src/erk/core/worktree_pool.py` for full definitions.

## Slot Allocation Algorithm

The `allocate_slot_for_branch()` function in `src/erk/cli/commands/slot/common.py` implements the unified allocation strategy:

### Step 1: Check Existing Assignment

If the branch is already assigned to a slot, return that assignment immediately (idempotent).

### Step 2: Fast Path - Reuse Inactive Slot

`find_inactive_slot()` searches for worktrees that:

- Exist in git's worktree registry
- Are not currently assigned to any branch
- Have no uncommitted changes

This is the fast path because it reuses an existing worktree directory.

### Step 3: Slow Path - Create New Slot

`find_next_available_slot()` finds a slot number that:

- Is within pool_size bounds
- Is not assigned to a branch
- Is not already initialized as a worktree
- Does not have an orphaned directory on disk

### Step 4: Pool Full - Eviction

If no slots are available, `handle_pool_full_interactive()` handles eviction:

- **With `--force`**: Auto-evict oldest assignment (by `assigned_at` timestamp)
- **Interactive (TTY)**: Prompt user to confirm eviction
- **Non-interactive**: Error with instructions

## Naming Conventions

| Component           | Pattern                               | Example                           |
| ------------------- | ------------------------------------- | --------------------------------- |
| Slot name           | `erk-slot-NN`                         | `erk-slot-01`                     |
| Placeholder branch  | `__erk-slot-NN-br-stub__`             | `__erk-slot-01-br-stub__`         |
| Pool state file     | `pool.json`                           | `~/.erk/repos/my-repo/pool.json`  |
| Worktrees directory | `~/.erk/repos/{repo-name}/worktrees/` | `~/.erk/repos/my-repo/worktrees/` |

## Artifact Cleanup

When reusing a slot, `cleanup_worktree_artifacts()` removes stale data:

- `.erk/impl-context/` - Previous implementation plans
- `.erk/scratch/` - Session-specific scratch data

These directories are in `.gitignore` so they persist across branch switches without cleanup.

## Transparent State Correction

The pool treats manual `git checkout` and `gt create` operations in pool slots as valid. When a user changes branches directly inside a worktree slot, the pool silently corrects its state on the next allocation call rather than raising an error.

<!-- Source: src/erk/cli/commands/slot/common.py:223-287, sync_pool_assignments -->

`sync_pool_assignments()` runs before every allocation decision. It compares each assignment's recorded branch against the actual git branch in the worktree and updates `pool.json` when mismatches are detected. If no corrections are needed, it skips the disk write entirely (preserving file mtime).

Edge cases handled:

- **Missing worktree directory** — assignment preserved (may be temporarily unmounted)
- **Detached HEAD** — assignment preserved (user may be mid-operation)
- **Placeholder branches** — assignment preserved (don't record stub branch names)
- **Branch changed** — assignment updated with actual branch, original `assigned_at` preserved for LRU ordering

For full details on the sync algorithm, see [Slot Pool State Sync](../architecture/slot-pool-state-sync.md).

## Diagnostics & Repair

### Sync Issues (`src/erk/cli/commands/slot/diagnostics.py`)

The diagnostic system detects inconsistencies between:

- Pool state (`pool.json`)
- Git worktree registry (`git worktree list`)
- Filesystem directories

| Issue Code             | Description                                      |
| ---------------------- | ------------------------------------------------ |
| `orphan-state`         | Assignment exists but worktree directory missing |
| `orphan-dir`           | Directory exists but not in pool state           |
| `missing-branch`       | Assigned branch no longer exists in git          |
| `branch-mismatch`      | Worktree on different branch than pool says      |
| `git-registry-missing` | Pool assignment not in git worktree registry     |
| `untracked-worktree`   | Git worktree exists but not erk-managed          |
| `closed-pr`            | PR for assigned branch is closed or merged       |

### Repair (`src/erk/cli/commands/slot/repair_cmd.py`)

`erk slot repair` auto-fixes by removing stale assignments:

- `orphan-state` - Remove assignment (worktree gone)
- `missing-branch` - Remove assignment (branch deleted)
- `branch-mismatch` - Remove assignment (let user re-assign)
- `git-registry-missing` - Remove assignment (not a valid worktree)
- `closed-pr` - Remove assignment (PR closed/merged)

## Entry Points

Commands that allocate slots via `allocate_slot_for_branch()`:

| Command               | Description                          |
| --------------------- | ------------------------------------ |
| `erk branch create`   | Creates branch and assigns to slot   |
| `erk branch checkout` | Checks out existing branch into slot |
| `erk slot assign`     | Assigns existing branch to slot      |
| `erk pr checkout`     | Assigns branch when checking out PR  |

### The `--new-slot` Flag

<!-- Source: src/erk/cli/commands/branch/create_cmd.py -->

`erk branch create --new-slot` forces allocation of a new slot instead of stacking in the current slot. Without this flag, `branch create` checks if the current worktree is an assigned slot and stacks the new branch in place.

**Trunk-aware behavior**: When running from trunk (master/main), the command implicitly behaves like `--new-slot` since stacking in the root worktree is not supported. The flag is mutually exclusive with `--no-slot`.

## Configuration

In `.erk/config.toml` (local config):

```toml
[pool]
max_slots = 6  # Override default of 4
```

## Key Source Files

- [`src/erk/core/worktree_pool.py`](../../../src/erk/core/worktree_pool.py) - Data structures and persistence
- [`src/erk/cli/commands/slot/common.py`](../../../src/erk/cli/commands/slot/common.py) - Allocation algorithm
- [`src/erk/cli/commands/slot/diagnostics.py`](../../../src/erk/cli/commands/slot/diagnostics.py) - Health checks
- [`src/erk/cli/commands/slot/repair_cmd.py`](../../../src/erk/cli/commands/slot/repair_cmd.py) - Auto-repair

## Related Topics

- [Branch Cleanup](branch-cleanup.md) - Cleaning up branches and worktrees
- Load `gt-graphite` skill for worktree stack mental model
