chore: initial commit
This commit is contained in:
commit
63f3199076
9 files changed
+567
No files matched your search
@@ -0,0 +1,185 @@
|
||||
# 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](#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`](https://github.com/realiti4/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.
|
||||
Reference in new issue
Block a user