A CLI/TUI tool that automates the planbot → next-phase → summarise-plan loop. Queue work across multiple repos, let it run overnight, and pick up where Claude Code left off after session-limit resets — all without manual intervention.
- Claude Code (
claudeon your PATH) gitgh(GitHub CLI, for PR creation and release notes)- Linux (x64/arm64) or macOS (x64/arm64)
Linux/WSL2 — sandbox isolation (recommended): bubblewrap and socat are required for Claude's sandbox to work. cpe runs without them but sessions will be unsandboxed.
sudo apt-get install bubblewrap socat # Debian/Ubuntu/WSL2
sudo dnf install bubblewrap socat # Fedora/RHEL
sudo pacman -S bubblewrap socat # ArchOptional — RTK: reduces Claude token usage by 60–90% across all sessions. The install script will prompt you if it's not detected.
curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/master/install.sh | sh
rtk init -gDownloads the prebuilt binary for your OS and architecture from the latest GitHub release:
curl -fsSL https://github.com/richardbenson/claude-plan-executor/releases/latest/download/install.sh | bashThen ensure ~/.local/bin is on your PATH (add to ~/.bashrc or ~/.zshrc if needed):
export PATH="$HOME/.local/bin:$PATH"Verify the install:
cpe --versionRequires Bun.
git clone https://github.com/richardbenson/claude-plan-executor.git
cd claude-plan-executor
bash scripts/install-local.sh# Inside a repo you want to automate work in:
cpe plan "add dark mode support to the settings panel"
# cpe launches Claude Code with planbot to break the feature into phases,
# then offers to queue it when planning completes.
# Alternatively, queue a plan folder you've already created:
cpe queue docs/my-feature
# Start the TUI — this runs the queue and shows live progress:
cpe start| Command | Description |
|---|---|
cpe plan [details] |
Launch an interactive planning session in the current repo |
cpe queue [folder] |
Add a plan folder to the queue |
cpe start |
Start the TUI queue processor |
cpe status |
Print queue status (non-interactive, for scripting) |
cpe list |
List all runs |
cpe pause / cpe resume |
Pause or resume queue processing |
cpe remove <run-id> |
Remove a run from the queue |
cpe clean |
Remove worktrees for completed runs |
cpe bootstrap |
Set up per-repo bootstrap config (--detect, --stub, --edit) |
cpe provider list |
List configured providers and their assigned roles |
cpe provider add |
Add a provider interactively |
cpe provider remove <name> |
Remove a provider by name |
cpe provider test [name] |
Test health checks for all providers, or one by name |
The file cpe.config.json at the repo root controls how cpe behaves for that specific project. On first use cpe will prompt you to set it up; you can also run cpe bootstrap --edit to open it directly.
A fully annotated example:
{
"bootstrap": [
"pnpm install"
],
"sandbox": {
"allowedDomains": [
"registry.npmjs.org",
"my-internal-registry.example.com"
]
},
"dangerously_skip_permissions": false,
"providers": [
{
"name": "local-ollama",
"model": "claude-opus-4-5",
"anthropic_base_url": "http://localhost:11434/v1",
"health_check_url": "/health"
}
],
"provider_for_planning": "local-ollama",
"provider_for_phases": "local-ollama"
}| Field | Type | Description |
|---|---|---|
bootstrap |
string[] |
Shell commands run in the worktree before each phase (e.g. dependency installs) |
sandbox.allowedDomains |
string[] |
Additional network domains Claude's sandbox may reach |
sandbox.allowWrite |
string[] |
Additional filesystem paths the sandbox may write to |
dangerously_skip_permissions |
boolean |
Pass --dangerously-skip-permissions to every Claude session (see below) |
providers |
ProviderEntry[] |
Alternative Claude endpoints/models for this repo (overrides global config) |
provider_for_planning |
string |
Name of the preferred provider for interactive planning sessions |
provider_for_phases |
string |
Name of the preferred provider for headless phase and single-prompt runs |
When providers is set in cpe.config.json it fully replaces the global provider list for that repo. The provider_for_planning and provider_for_phases fields name the preferred provider for each role; if that provider fails its health check, cpe falls back through the list in order.
Run cpe bootstrap --detect to have Claude inspect the repo and propose bootstrap commands automatically.
Providers let you route cpe sessions through alternative Claude endpoints or models — a local Ollama proxy, an internal API gateway, or any service that speaks the Anthropic API.
| Field | Required | Description |
|---|---|---|
name |
yes | Identifier used to reference this provider |
model |
no | Passes --model <value> to every Claude spawn |
anthropic_base_url |
no | Sets ANTHROPIC_BASE_URL in the session environment |
anthropic_api_key |
no | Sets ANTHROPIC_API_KEY in the session environment |
anthropic_auth_token |
no | Sets ANTHROPIC_AUTH_TOKEN in the session environment |
health_check_url |
no | A full URL or a path relative to anthropic_base_url. cpe GETs this before each run (5 s timeout, must return 2xx). Providers without a health check are assumed always available. |
Before each Claude spawn, cpe picks a provider as follows:
- The preferred provider (from
provider_for_planningorprovider_for_phases) is tried first. - If it fails its health check,
cpetries the remaining providers in list order. - If no provider passes,
cpefalls back silently to bare Anthropic — no extra environment variables or--modelflag.
This means you can list a fast local provider first with a health check, and it will be used when available and skipped automatically when it isn't.
Providers can be configured globally in ~/.config/cpe/config.json:
{
"providers": [
{
"name": "my-proxy",
"anthropic_base_url": "https://proxy.example.com",
"anthropic_api_key": "sk-...",
"health_check_url": "/health"
}
],
"provider_for_planning": "my-proxy",
"provider_for_phases": "my-proxy"
}A repo's cpe.config.json can override this entirely by defining its own providers, provider_for_planning, and provider_for_phases fields. The repo-level list fully replaces the global list — there is no merging.
cpe provider list # Show all providers and their assigned roles
cpe provider add # Interactive wizard — name, model, URL, API key, health check
cpe provider remove my-proxy # Remove by name
cpe provider test # Run health checks for all providers
cpe provider test my-proxy # Run health check for one providercpe provider list shows a Roles column: P = used for planning, F = used for phases, P+F = both, — = not currently assigned to a role.
Each plan lives in a docs/<folder>/ directory with a PROGRESS.md and one PHASE_NN.prompt.md per phase (planbot output). cpe processes them sequentially:
- Creates a
git worktreefor the run so your main checkout is never touched - Runs each phase by spawning
claude -pwith the phase prompt - Detects Claude Code session-limit pauses and resumes automatically when the window reopens
- Commits after each phase, then raises a PR and summarises the plan when all phases complete
If your project uses a devcontainer, running cpe and claude inside the container is the right approach — not on the host. The container has your build toolchain, so Claude's bash commands work correctly, and all paths (worktrees, state, git registrations) stay in one consistent filesystem. The only thing that needs to come from the host is your Claude authentication and settings, via a bind mount of ~/.claude.
The exact changes needed depend on your specific devcontainer setup: whether you use a base image or a custom Dockerfile, which user the container runs as, and how your postCreateCommand is currently structured. Rather than a one-size-fits-all script, the most reliable way to configure this is to ask Claude to do it for you.
Prompt to configure your devcontainer for cpe
Copy and paste this into Claude Code (inside your project):
I want to configure my devcontainer to run cpe (Claude Plan Executor) inside the
container. Please make the following changes to my devcontainer configuration:
1. Add a bind mount of `~/.claude` from the host into the container user's home
directory (e.g. /home/vscode/.claude or /root/.claude depending on the user
this container runs as). This gives Claude Code inside the container access to
authentication credentials and hook settings (including RTK if installed on
the host).
2. Add install steps for the following tools if not already present:
- `claude` (Claude Code CLI): npm install -g @anthropic-ai/claude-code
- `cpe`: curl -fsSL https://github.com/richardbenson/claude-plan-executor/releases/latest/download/install.sh | bash
- `gh` (GitHub CLI): use the appropriate method for this container's base OS
- `bubblewrap` and `socat`: apt-get / dnf / pacman as appropriate for the OS
(needed for Claude sandbox isolation on Linux — cpe works without them but
sessions will be unsandboxed)
Install steps should go in `postCreateCommand` or as a `RUN` layer in the
Dockerfile, whichever is more appropriate given the existing setup. Prefer
`postCreateCommand` for user-scoped tools like `cpe` and `claude`.
3. Ensure `~/.local/bin` is on PATH inside the container (cpe installs there).
Please read my devcontainer.json and any referenced Dockerfile before making
changes, and handle the postCreateCommand correctly whether it is currently a
string, an array, or an object.
Standard devcontainers (and most Docker/Podman containers) do not support bubblewrap because bubblewrap requires Linux user namespaces (CLONE_NEWUSER), which Docker disables by default. Without bubblewrap, cpe cannot enable Claude's sandbox — and without the sandbox, Claude Code's autoAllowBashIfSandboxed setting does not apply, so Claude will show interactive permission prompts for every bash tool call.
cpe detects this situation and shows a warning banner in the TUI when it starts inside a container without bubblewrap available.
To suppress permission prompts in a container, set dangerously_skip_permissions: true. This passes --dangerously-skip-permissions to every Claude session, bypassing all permission checks. Only use this in environments you trust (your own devcontainer is fine; a shared or ephemeral CI environment is not).
You can set it globally or per-repo:
Global (~/.config/cpe/config.json):
{
"dangerously_skip_permissions": true
}Per-repo (cpe.config.json in your project root):
{
"bootstrap": ["pnpm install"],
"dangerously_skip_permissions": true
}When dangerously_skip_permissions is active, the TUI header shows ⚠ perms skipped and each affected run shows a ! badge in the queue pane.
MIT