ccbridge-cli
v0.1.11
Published
Bridge Claude Code and Codex through a planner-critic-executor-reviewer loop.
Downloads
918
Maintainers
Readme
ccbridge
ccbridge is an open-source CLI orchestrator for cooperative multi-agent analysis and coding loops:
planner -> critic -> executor -> reviewer
The default pairing is:
Claude Codefor planning and implementationCodexfor plan validation and code review
ccbridge is for people who want more structure than "let one agent run wild", but less ceremony than a full platform. It gives you:
- explicit planning rounds
- structured critique instead of vague back-and-forth
- analysis-only runs before you commit to implementation
- human handoff when requirements are unclear
- a repair loop after review
- run artifacts you can inspect and debug
- visible terminal progress while agents are working
Status
ccbridge is usable, but still early.
It has been tested on real claude and codex CLI runs, including:
- analysis-only runs with follow-up questions
- planner questions that require human clarification
- multi-round planning and critique
- execution plus post-review repair rounds
- final review pass with saved artifacts
Expect sharp edges. If you use it, use it in a repo you understand.
Safety
This project can edit files and run shell commands in your workspace.
The default balanced preset uses a Claude executor with bypassed permission checks so it can complete work and run validation commands like npm test or npm run build without interactive approval prompts.
That is intentional for automation, but it means:
- use
ccbridgeonly in repos you trust - read the task you give it carefully
- understand the role config before widening permissions further
More details are in SECURITY.md.
Quick Start
Requirements:
- Node.js 20+
- local
claudeCLI installed and authenticated if you wantclaude-cli - local
codexCLI installed and authenticated if you wantcodex-cli
Install From npm
Install globally with:
npm install -g ccbridge-cliThen verify:
ccbridge --version
ccbridge --help
ccbridge doctorThe npm package name is ccbridge-cli, but the installed shell command remains ccbridge.
When ccbridge is installed globally from npm, interactive terminals check for a newer npm release at most once per day. You can update immediately from that prompt or continue on the currently installed version. Set CCBRIDGE_SKIP_UPDATE_CHECK=1 to suppress those prompts.
If you use zsh or bash and want command completion, the easiest setup is:
ccbridge setup zsh
# or
ccbridge setup bashThis writes the completion file and updates your shell rc file automatically. Then reload your shell.
If you prefer to wire it up manually for zsh, you can still use:
mkdir -p ~/.zsh/completions
ccbridge completion zsh > ~/.zsh/completions/_ccbridgeAfter reloading the shell, ccbridge <Tab> completes commands, --preset <Tab> completes preset names, path-like options complete files or directories, and --task @<Tab> completes files.
You have two supported ways to use ccbridge.
Option A: No PATH Setup
If you just want to run the project from this repo, use:
npm start -- <command>Examples:
npm start -- doctor
npm start -- presets
npm start -- run --preset balanced --workspace /absolute/path/to/repo --task @./task.mdOption B: Add ccbridge As A Shell Command
If you want ccbridge available directly in your shell, run this once from the repo root:
npm linkThen verify it:
command -v ccbridge
ccbridge --helpIf ccbridge is still not found on macOS or Linux, your global npm bin directory is probably not on PATH.
Check the npm prefix:
npm config get prefixThen add its bin directory to your shell startup file, for example in ~/.zshrc:
export PATH="$(npm config get prefix)/bin:$PATH"Reload your shell:
source ~/.zshrcIf you do not want to change your PATH, keep using npm start -- ....
Check the environment first:
ccbridge doctorOr without npm link:
npm start -- doctorRun against a target repo:
ccbridge run \
--preset balanced \
--workspace /absolute/path/to/repo \
--task @./task.mdOr without npm link:
npm start -- run \
--preset balanced \
--workspace /absolute/path/to/repo \
--task @./task.md--task-file still works. --task @path/to/file.md is just a shorter alias for file-backed tasks.
Analysis-First Workflow
If you want to diagnose a problem before editing code, start with:
ccbridge analyze \
--preset balanced \
--workspace /absolute/path/to/repo \
--task @./bug-analysis.mdanalyze uses the planner and critic roles cooperatively, writes artifacts to .runs/<runId>/, and never invokes the executor or edits workspace files.
If you want to continue the same topic later, ask a follow-up question against that saved analysis run:
ccbridge ask \
--run <runId> \
--question "Does the same reasoning apply to the compare view?"When you are ready to implement, reuse that analysis as planning context:
ccbridge run \
--preset balanced \
--from-analysis <runId> \
--task @./fix-task.mdrun --from-analysis does not skip planning or critique. It feeds the saved analysis into the next implementation run as extra context, and the agents still validate scope against the current repository state.
Docs
Additional documentation:
What A Run Looks Like
- The planner proposes a structured plan.
- The critic either approves it or returns blocking issues.
- If required, the planner revises the plan until approval or
maxPlanRounds. - The executor implements the approved plan.
- The reviewer checks the result and can request a repair pass.
- If repair rounds are exhausted, you can explicitly continue from the latest review without restarting the whole run.
- The run ends as
completed,plan_rejected, orreview_changes_requested.
Every run is saved to .runs/<timestamp>/.
What An Analysis Looks Like
- The planner produces a structured analysis.
- The critic challenges weak assumptions, gaps, or scope drift.
- If needed, the planner revises the analysis until approval or
maxPlanRounds. - The run ends as
completed,analysis_rejected, orwaiting_for_user. - Follow-up questions can extend the same analysis later with
ccbridge ask --run <runId>.
Analysis runs save artifacts such as:
analysis.round-N.jsonchallenge.round-N.jsonsummary.jsonstate.json
Presets
Built-in presets:
balanced: Claude plans and implements, Codex validates and reviewscodex-exec: Claude plans, Codex validates and implements, Claude reviewscodex-leads: Codex plans and implements, Claude critiques and reviews
List them locally:
ccbridge presetsHuman Handoff
If an agent cannot proceed safely without a user decision, ccbridge pauses and requests structured input instead of letting the model guess.
In a normal interactive terminal, ccbridge run automatically opens the question step.
If the run happened in a non-interactive environment, or you want to answer later:
ccbridge answer --run <runId>For automation you can still answer with JSON:
ccbridge answer \
--run <runId> \
--answers '{"question_id":"value"}'Supported answer shapes:
text:"question_id": "free-form answer"single_select:"question_id": "option_id"multi_select:"question_id": ["option_a", "option_b"]
If a run was interrupted after input was already recorded:
ccbridge resume --run <runId>If a run stopped because the reviewer still wants changes after the allowed repair passes:
ccbridge continue --run <runId>If you want to continue a completed analysis without implementing anything yet:
ccbridge ask --run <runId> --question "What should we verify next?"For machine-readable final output instead of the human summary:
ccbridge run ... --jsonFor a more detailed human summary, including the role-to-agent mapping and artifact file paths:
ccbridge run ... --verboseCurrent behavior is human handoff only. ccbridge does not let one agent invent product decisions on behalf of the user.
Terminal UX
Long-running agent calls are noisy on purpose. ccbridge prints:
- the current stage
- which role and agent are running, for example
Planner (Claude)orReviewer (Codex) - a live spinner/status line in interactive terminals
- heartbeat lines every 10 seconds in non-interactive terminals
- a completion line with elapsed time
- a short stage summary after plan, critique, execute, and review
At the end of a run, ccbridge prints a human-readable summary by default, including total duration, per-agent timing, and changed files. Use --json for machine-readable output or --verbose for extra detail such as role-to-agent mapping and artifact file paths.
That feedback is there so the terminal does not look frozen during long claude or codex calls.
Configuration
The default live config is ccbridge.config.json.
If ccbridge.config.json is missing, ccbridge falls back to the balanced preset automatically.
There is also a mock config for local smoke tests without real agent CLIs.
Example config:
{
"workspaceDir": ".",
"artifactsDir": ".runs",
"maxPlanRounds": 3,
"maxReviewRounds": 1,
"maxAgentCallMs": 900000,
"roles": {
"planner": {
"provider": "claude-cli",
"model": "sonnet",
"permissionMode": "dontAsk"
},
"critic": {
"provider": "codex-cli",
"sandbox": "read-only",
"approvalPolicy": "never",
"skipGitRepoCheck": true
},
"executor": {
"provider": "claude-cli",
"model": "sonnet",
"permissionMode": "bypassPermissions",
"dangerouslySkipPermissions": true
},
"reviewer": {
"provider": "codex-cli",
"sandbox": "read-only",
"approvalPolicy": "never",
"skipGitRepoCheck": true
}
}
}Notes:
plannerandcriticexchange structured JSON, not free-form prose.- blocking issues are meant to be rare and reserved for material execution risk
executoris the only role that should edit the workspacereviewerchecks the result after implementation and can trigger a repair passrunperforms preflight checks forclaudeandcodexauth before startingskipGitRepoCheckis useful when a target workspace is not a git repomaxAgentCallMslimits a single planner / critic / executor / reviewer call beforeccbridgetimes it out. The default is 15 minutes, because real agent runs and repair attempts can take a while.mockexists only for local smoke tests
Contributing
Open source contributions are welcome.
Start with CONTRIBUTING.md.
If you plan to change prompts, schema contracts, or provider behavior, please keep those three areas aligned in the same PR whenever possible.
Security
Read SECURITY.md before using ccbridge in a sensitive repository.
This matters more here than in a typical CLI, because ccbridge may:
- edit files
- run shell commands
- execute with bypassed permissions in trusted-repo setups
License
This project is released under the MIT License.
Troubleshooting
Reading doctor output
npm run doctor prints one line per provider in this format:
[OK|FAIL] <provider> version=<X> auth=<ready|missing> <message>OK means the binary was found and auth is confirmed. FAIL means at least one check did not pass. The message field contains the specific reason or a remediation hint.
Checking raw logs after a failed run
Every run writes artifacts to <artifactsDir>/<timestamp>/ (default: .runs/<timestamp>/). Key files:
| File | When written |
|---|---|
| task.txt | Always |
| plan.round-N.json | Each plan revision |
| critique.round-N.json | Each critique round |
| plan.approved.json | Once the critic approves |
| execution.round-N.json | Each execution attempt |
| execution.json | Latest execution (overwritten each round) |
| review.round-N.json | Each review round |
| review.json | Latest review (overwritten each round) |
| pending-input.json | Only while the run is waiting for user input |
| input-N.request.json | Each structured input request from an agent |
| input-N.answer.json | Each answer captured by ccbridge answer |
| summary.json | On plan rejection or after review loop completes (not written on provider command failures) |
The raw/ subdirectory holds per-agent CLI logs. Two categories:
Universal (written for every provider):
<role>-<operation>.stdout.log<role>-<operation>.stderr.log
Codex-only structured artifacts:
<role>-<operation>.schema.json— JSON schema passed tocodex --output-schema<role>-<operation>.result.json— structured output written bycodex --output-last-message
Claude runs do not create .schema.json or .result.json files.
Run stopped with waiting_for_user
This means an agent returned a structured input request instead of trying to use an interactive terminal prompt. Inspect:
cat .runs/<runId>/pending-input.jsonThen answer it with:
ccbridge answer --run <runId>If you already answered the questions and the process was interrupted, continue with:
ccbridge resume --run <runId>Run stopped with review_changes_requested
This means the latest review still found a blocking issue after the currently allowed repair rounds. To grant one more executor -> reviewer cycle without restarting planning:
ccbridge continue --run <runId>Binary not found (ENOENT)
When doctor shows binary unavailable: spawn <cli> ENOENT, the CLI is not on your PATH. Install the respective CLI from its official documentation and ensure the binary is reachable from your shell before running the orchestrator.
ccbridge: command not found
If your shell cannot find ccbridge, either:
- use
npm start -- ...from the repo root, or - run
npm linkfrom the repo root and verify with:
command -v ccbridgeIf npm link succeeds but the command is still missing, add the npm global bin directory to your shell PATH:
export PATH="$(npm config get prefix)/bin:$PATH"Then reload your shell, for example:
source ~/.zshrcAuth not configured
When doctor shows auth=missing, the binary was found but authentication is not set up. Run the remediation command shown in the doctor output:
- claude-cli:
claude auth login - codex-cli:
codex login
Then re-run npm run doctor to confirm auth=ready before starting a run.
To debug a false-negative auth=missing, run the same checks the doctor performs internally:
# Claude — expects JSON with loggedIn: true
claude auth status
# Codex — expects "logged in" in combined stdout/stderr
codex login statusCodex: WARNING lines in version output
When running codex -V manually you may see a WARNING: banner before the version string. This is normal. The doctor strips that banner automatically when parsing the version, so it does not cause a check failure.
Non-git workspace
codex exits non-zero when the target workspace is not a git repository, which causes the run to fail. Set "skipGitRepoCheck": true in the role config to suppress this check:
"critic": {
"provider": "codex-cli",
"skipGitRepoCheck": true
}Command failed / non-zero exit code
When a run fails with a message like:
Command failed: claude --print --output-format json ...
Exit code: 1
<up to 1200 chars of stderr or stdout>the CLI process exited with a non-zero code. The truncated output is a snapshot; the full logs are in:
<artifactsDir>/<timestamp>/raw/<role>-<operation>.stderr.logStart with the .stderr.log file — it typically contains the CLI's own error message (authentication failure, unknown flag, network error, etc.).
Claude Code: --output-format json not recognised
The orchestrator passes --output-format json and --json-schema <schema> to every claude invocation. If the claude binary does not support these flags, the command fails immediately with unknown flag or similar in stderr.
Fix: upgrade your claude CLI to the latest version.
claude --version # verify which version is installedCodex: output-last-message issues
The orchestrator passes --output-schema <path> and --output-last-message <path> to every codex invocation. Two distinct failure modes can occur:
Case A — non-zero exit code: codex exits non-zero and the orchestrator throws immediately. The .result.json file is irrelevant here. Check the stderr log for the root cause (auth error, unrecognised flag, network failure, etc.):
<artifactsDir>/<timestamp>/raw/<role>-<operation>.stderr.logCase B — zero exit but missing or unreadable .result.json: The provider falls back to raw stdout and calls parseStructuredOutput() on it. The run may then fail with Agent returned an empty response or Could not parse structured JSON. This can happen with older codex builds that ignore --output-last-message and write to stdout instead of the file. Confirm codex is up to date and check the raw stdout log:
<artifactsDir>/<timestamp>/raw/<role>-<operation>.stdout.logStructured JSON parse error
When a run fails with Could not parse structured JSON from agent output, the agent returned free-form text instead of valid JSON. The full raw output is in:
<artifactsDir>/<timestamp>/raw/<role>-<operation>.stdout.logTo isolate whether the issue is in the prompt or the CLI, switch the failing role to "provider": "mock" and re-run. If the mock provider succeeds, the prompt is fine and the problem is with the CLI response.
Bypassing preflight for debugging
Pass --skip-preflight to skip the auth and binary checks entirely:
npm start -- run --skip-preflight --task "..."Use this only during debugging when you know a check would fail for a transient reason (for example, a flaky codex login status call). Do not use it to permanently bypass a missing auth configuration.
Test
npm test