2026-09-16 12:37:50 +02:00
2026-09-16 12:37:50 +02:00
2026-09-16 12:37:50 +02:00
2026-09-16 12:37:50 +02:00
2026-09-16 12:37:50 +02:00
2026-09-16 12:37:50 +02:00

ddev-codex-claude-cli

ddev-codex-claude-cli is a DDEV add-on that runs Codex CLI and Claude Code CLI inside the DDEV web container while keeping runtime state under the project's .ddev directory on the host (bind-mounted into the container).

What it does

  • exposes ddev codex
  • exposes ddev claude
  • optionally exposes ddev claude-swap for juggling multiple Claude accounts (opt-in; see Multiple Claude accounts)
  • installs Codex CLI lazily the first time you run ddev codex (or whenever the persisted binary is missing) by downloading the latest release from GitHub: curl -fsSL https://github.com/openai/codex/releases/latest/download/install.sh | sh
  • installs Claude Code CLI during ddev start when the persisted binary is missing or broken by downloading the stable native build: curl -fsSL https://claude.ai/install.sh | bash -s stable
  • keeps normal ddev start fast by skipping Claude Code installation when the persisted binary is already runnable
  • persists each CLI's binary, HOME, and XDG paths under project-local storage so each DDEV project has its own profiles
  • seeds the project-local HOME from the container home on first bootstrap for .gitignore_global when present
  • always runs Codex with --sandbox danger-full-access --ask-for-approval untrusted

Runtime storage

Inside the web container, Codex CLI state lives under:

${DDEV_APPROOT}/.ddev/codex-cli

Claude Code CLI state lives under:

${DDEV_APPROOT}/.ddev/claude-code

On the host, those are your project's .ddev/codex-cli/ and .ddev/claude-code/ directories. They survive ddev restart, ddev stop, and ddev poweroff like any other project file. The same directories hold the add-on's install scripts (managed files) alongside runtime data created after the first start.

Codex layout:

Path Role
.ddev/codex-cli/install.sh Codex install script
.ddev/codex-cli/bin/codex Codex CLI binary
.ddev/codex-cli/home HOME
.ddev/codex-cli/config XDG_CONFIG_HOME
.ddev/codex-cli/data XDG_DATA_HOME
.ddev/codex-cli/state XDG_STATE_HOME

Claude Code layout:

Path Role
.ddev/claude-code/install.sh Claude Code install script
.ddev/claude-code/home/.local/bin/claude Claude Code CLI binary
.ddev/claude-code/home HOME
.ddev/claude-code/config XDG_CONFIG_HOME
.ddev/claude-code/data XDG_DATA_HOME
.ddev/claude-code/state XDG_STATE_HOME

Authentication and settings are per project: sign in once per project; they persist across container restarts.

Install

From a DDEV project root:

ddev add-on get /path/to/ddev-codex-claude-cli

Then restart:

ddev restart

Usage

ddev codex

ddev codex --version

ddev claude

ddev claude --version

ddev claude update

ddev claude-swap list              # opt-in; see "Multiple Claude accounts"

Updates

Codex CLI is installed lazily when ddev codex runs and the persisted binary is missing or broken.

Claude Code CLI is installed automatically on ddev start only when the persisted binary is missing or broken. Later starts run a fast health check and skip installation when Claude is already runnable.

To check for and install a newer Claude Code stable release, run:

ddev claude update

Multiple Claude accounts

The add-on can integrate claude-swap (cswap) so one project can hold several Claude accounts and swap between them — mainly to keep working past a 5-hour or weekly rate limit. It is opt-in: nothing is installed during ddev start; the first ddev claude-swap call (or first ddev claude --account …) installs uv and claude-swap into the project-local Claude profile under .ddev/claude-code/.

Accounts are stored per project, next to the rest of the Claude state:

.ddev/claude-code/data/claude-swap/

They persist across restarts and are deleted when the add-on is removed. Back them up first with ddev claude-swap export backup.cswap if you need to keep them.

Swapping accounts without losing your session

A running ddev claude conversation is not tied to the auth token, and Claude Code re-reads its credentials file whenever it changes. So:

  1. Terminal 1: you are in ddev claude, working, and hit (or approach) the limit.
  2. Terminal 2 (on the host): ddev claude-swap switch <n|email|alias> (or ddev claude-swap switch --strategy best).
  3. Back in terminal 1: send the next message — it goes out on the new account, in the same session with all its context. If a request just failed with the limit error, resend it.

To automate step 2, run ddev claude-swap auto in a spare terminal (or an ddev ssh shell); it watches usage and switches around 90%.

One-time setup

ddev claude                     # sign in as your first account
ddev claude-swap add --alias a  # capture it
ddev claude                     # /login inside Claude Code as the next account, then exit
ddev claude-swap add --alias b  # capture it
ddev claude-swap list           # all accounts with usage and reset times
ddev claude-swap status         # currently active account

ddev claude-swap forwards every argument straight to cswap, so any cswap subcommand works (switch, run, map, disable, export, import, tui, …). ddev claude-swap upgrade updates claude-swap to the latest release.

Starting a session pinned to an account

Separately from the hot-swap flow, you can launch a session bound to one account (with its own per-account chat history):

ddev claude --account b
ddev claude --account b --resume    # remaining args pass straight to Claude Code

Set a project default so plain ddev claude always uses it:

echo b > .ddev/claude-code/claude-swap-account
# or export DDEV_CLAUDE_SWAP_ACCOUNT=b

Remove the file (or unset the variable) to go back to the normal single-account launch.

Requirements

The first install needs outbound network access to astral.sh, pypi.org, files.pythonhosted.org, and github.com (for the uv-managed Python 3.12). claude-swap captures whichever account is signed in at cswap add time, so the initial multi-account setup is a few manual /login round-trips.

Installed managed files

.ddev/config.codex-cli.yaml
.ddev/config.claude-code.yaml
.ddev/commands/web/codex
.ddev/commands/web/claude
.ddev/commands/web/claude-swap
.ddev/codex-cli/install.sh
.ddev/claude-code/install.sh
.ddev/claude-code/install-swap.sh

Notes

  • the first ddev codex in a project can take some time because it downloads the Codex CLI binary; later runs reuse .ddev/codex-cli/bin/codex

  • the first ddev start after installing the add-on can take some time because it downloads Claude Code; later starts reuse .ddev/claude-code/home/.local/bin/claude

  • if the container home has .gitignore_global (typically from host ~/.ddev/homeadditions/.gitignore_global), it is copied into each project-local CLI HOME on first bootstrap; git's core.excludesfile is pointed at that project-local copy

  • if you do not want add-on or CLI runtime files in your repository, ignore them in git, for example:

    /.ddev/addon-metadata/ddev-codex-claude-cli
    /.ddev/config.codex-cli.yaml
    /.ddev/config.claude-code.yaml
    /.ddev/commands/web/codex
    /.ddev/commands/web/claude
    /.ddev/commands/web/claude-swap
    /.ddev/codex-cli/
    /.ddev/claude-code/
    

Removing the add-on deletes .ddev/codex-cli/ and .ddev/claude-code/ as well (local auth, config, and CLI binaries). Back up those directories first if you need to keep them.

macOS / Linux / WSL2

This add-on runs Codex CLI and Claude Code CLI in the DDEV container, so host OS differences are minimized as long as DDEV works normally.

S
Description
No description provided
Readme
87 KiB
0 Stars 1 Watchers 0 Forks
Languages
Shell 100%