Small libraries for calling coding CLIs from normal programs.
./run_all_tests.shThis runs every implementation's unit/build checks plus the cross-language contract and mock-harness checks, then prints a color-coded checklist:
PASS python: runner + prompt_spec
PASS rust: cargo test
PASS typescript: node --test
PASS c: make test
PASS go: go test
PASS ruby: test suite
PASS perl: prove
PASS cpp: cmake build + gtest
...
SKIP vbscript: test suite (Windows only)
PASS contract: ccc CLI behavior (legacy + @name matrix)
PASS harness: mock binary behavior (16 langs × 9 cases)
Total: 22 Passed: 21 Failed: 0 Skipped: 1
When working on a single language, use the targeted wrapper instead of the full repo sweep:
./test_impl.sh <language>Examples:
./test_impl.sh c
./test_impl.sh rust
./test_impl.sh typescriptThis runs that implementation's unit tests plus the targeted cross-language contract and mock harness checks for the same language only. Use ./run_all_tests.sh only when you intentionally want the whole repository run.
just buildThis builds the Rust binary and runs a Python compile check. Both Python and Rust read the repo-root VERSION file for ccc --version, so update that file when you want to bump the reported build version.
| Language | Command |
|---|---|
| Python | PYTHONPATH=python python3 -m unittest tests.test_runner tests.test_parser_config tests.test_json_output tests.test_run_artifacts |
| Rust | cd rust && cargo test |
| TypeScript | node --test typescript/tests/runner.test.mjs |
| C | cd c && make test |
| Go | cd go && go test ./... |
| Ruby | cd ruby && ruby -Ilib -Itest test/test_*.rb |
| Perl | cd perl && prove -v t/ |
| C++ | cmake -B cpp/build -S cpp && cmake --build cpp/build --target ccc_tests && ./cpp/build/tests/ccc_tests |
| Cross-language | PYTHONPATH=. python3 tests/test_ccc_contract_impl.py <language> -v && PYTHONPATH=. python3 tests/test_harness.py <language> -v |
- Python —
call_coding_clispackage, real-runner override env support - Rust —
call-coding-cliscrate, concurrent streaming, real-runner override env support - TypeScript — runner +
cccCLI with streaming,CCC_REAL_OPENCODEsupport - C — reusable runner library (
runner.c/runner.h) pluscccbinary - Go —
go/ccc.golibrary with goroutine-based streaming,cccCLI - Ruby —
CallCodingClismodule with runner/stream,cccCLI - Perl —
Call::Coding::Cliswith runner,cccCLI - C++ — C++17 with GoogleTest, cmake build,
cccCLI - Zig, D, F#, PHP, PureScript, x86-64 ASM, OCaml, Crystal, Haskell, Elixir, Nim —
cccimplementations covered by targeted contract/harness checks
Implementation-specific follow-up work is tracked in each language's PLAN.md. VBScript remains planned.
- OpenCode
- Claude / Claude Code
- Codex
- Kimi
- Gemini CLI
- Cursor Agent
- RooCode
- Crush
- Qwen Code
- Pi
- similar terminal-first coding agents
- start a CLI process with a prompt or stdin payload
- capture stdout/stderr and exit status
- expose a small streaming interface
- keep the abstraction subprocess-oriented and easy to mock in tests
- write a stable per-run artifact directory under the platform state root, with a client-prefixed run folder such as
opencode-<run-id>and a parseable stderr footer for scripts
- every language library should also bundle a CLI named
ccc - the
cccinterface should have the same shape across languages ccc "<Prompt>"must work everywhere; Python and Rust carry the reference extended CLI surface- library and CLI design should stay aligned so
precurlcan use the library layer while humans can use the same runner shape directly precurluses the Rust library layer for delegated LLM analysis — see the precurl SECURITY.md for threat model and prompt-injection mitigation details- Python and Rust also support free-order control tokens before the prompt,
--to force literal prompt text,--show-thinking/--no-show-thinking,--yolo/-y, and--fast/--no-fast -v/--versionprints the shared build version plus resolved client versions- Python and Rust runner tables in help, usage errors, and version output show the executable name (for example,
cursor-agent), version/status, and version-lookup time in aligned columns. Timings use milliseconds with one decimal place; lookups over 50 ms appear red when color is enabled. Missing executables shownot foundand-for timing. Color followsFORCE_COLOR/NO_COLOR, then the output stream's TTY status. - Runner discovery searches
PATHand resolves symlinks directly. Known installs read versions from package metadata, installer receipts, adjacent version files, or embedded build information instead of starting the CLI. Codex wrappers and npm/pnpm Pi launchers are followed through literal paths without evaluating shell code. See runner version discovery for supported layouts; unknown layouts retain the<cli> --versionfallback.
ccc "<Prompt>"- initial command shape maps to
opencode run "<Prompt>" - this is intentionally narrow and likely to grow later with explicit runner/model flags
- explicit shared behavior doc:
CCC_BEHAVIOR_CONTRACT.md
- Python and Rust currently accept control tokens in any order before the prompt:
- runner selectors such as
c,cx,cc,oc,k,cu,g,p,gb,rc,cr,codex,claude,opencode,kimi,cursor,gemini,pi,grok,roocode, andcrush +0..+6thinking levels (0none,1low,2medium,3high,4xhigh,5max,6ultra);+ultramaps to6,+maxto5, and+xhighto4. Codex maps each level to-c model_reasoning_effort=<none|low|medium|high|xhigh|max|ultra>and defaults tomedium; runners with fewer tiers clamp higher requests to their top tier:provider:modeland:model@namefor preset lookup; if no preset exists, runner names such as@kselect that runner before ordinary agent fallback; presets can also define a default prompt, and aliasprompt_mode = "prepend"|"append"can compose alias prompt text around an explicitly supplied prompt- alias
fallback_models = ["model-a", "glm-5.3"]retries once per listed model when the run fails with a capacity or overload error before any assistant output. Mapped models (glm-5.3,llmp-glm-5-3,glm-5.3-flash) are retried on grok; other models stay on the same runner. JSON and formatted output from that retry is parsed with the fallback runner's schema.cccsays which model ran on stderr and in the run transcript. Authentication errors and failures after output has started do not fall back. Claude runners are not retried, and MiniMax, Claude, or Astra model ids are skipped. Primary use of those models, including@astra, stays allowed. Cursor auto presets userunner = "cursor"andmodel = "auto"(@cursor,@cu-auto). help,-h, and--helpwin anywhere in argv and print help immediatelyccc --helplists configured aliases visible from the current directory and includes short agent tips for checking config, choosing aliases, and using--for literal prompt text- Python and Rust search project-local
.ccc.tomlfiles upward from the current directory and override the global config chain ccc configprints every existing config file path and raw contents in merge order:~/.config/ccc/config.toml,XDG_CONFIG_HOME/ccc/config.toml, then the nearest project-local.ccc.toml; an existingCCC_CONFIGfile overrides this chain for execution, aliases, help, and config displayccc config --editopens the selected config in$EDITOR; add--userto edit the XDG/home user config or--localto edit the nearest.ccc.toml(creating one in the current directory if none exists)ccc add [-g] <alias>starts a line-prompt wizard for writing[aliases.<name>]config; flags such as--runner,--model,--prompt, and--prompt-modecan prefill values, and--yeswrites non-interactivelyformatted,stream-formatted, andccc addmenu prompts honorFORCE_COLOR/NO_COLORbefore falling back to TTY detection- formatted modes always keep unhandled structured JSON lines in the run transcript;
CCC_FWD_UNKNOWN_JSONcontrols whether they are also forwarded to stderr and currently defaults on --print-configto print the canonical exampleconfig.toml--permission-mode safe|auto|yolo|plan--save-sessionto explicitly allow normal runner session persistence--cleanup-sessionto try post-run cleanup when a runner lacks a no-persist flag--output-log-path/--no-output-log-pathto enable or suppress the final stderr footer that points at the run artifact directory--show-thinking/--no-show-thinking--timeout-secs <N>kills the wrapped runner afterNseconds, printswarning: timed out after N seconds; killed runnerto stderr, and exits with status124--yolo/-y--service-tier <default|fast|priority|ultrafast>selects Codex service priority.--fast/--no-fastselectfast/default; other runners warn and ignore these controls. The last CLI tier control wins--standalone/--no-daemonrequests execution without the shared background daemon: Codex receivescodex --no-daemon exec, and OpenCode receivesopencode run --standalone.--no-standaloneallows upstream defaults. Config defaults and aliases can setstandalone = true|false; CLI overrides aliases, then defaults
- runner selectors such as
--forces the rest of argv to be treated as prompt text, even if it starts with control-like tokens- Python and Rust currently use
claude -p --no-session-persistence,codex exec --ephemeral,cursor-agent --print --trust,gemini --prompt,pi -p --no-session,grok --no-auto-update -p, andcrush runfor non-interactive invocation - By default Python and Rust avoid saved sessions where the selected CLI supports it; OpenCode, Kimi, Cursor, Gemini, Grok, Crush, and RooCode warn that the runner may save a session unless
--save-sessionor--cleanup-sessionis used ccc --print-configis the source of truth for the current canonical config schema:[defaults],[update],[abbreviations], and[aliases.<name>]- Python and Rust accept
service_tierin[defaults]and[aliases.<name>]. CLI tier controls override the alias, which overrides defaults. Omit the field to inherit Codex's own configuration;defaultexplicitly selects its standard tier. Fast and Ultrafast availability depends on the model and account - Python and Rust optionally check after each run whether a newer
cccis available (crates.io, GitHub releases fallback) and warn on stderr; set[update] check = falseorCCC_UPDATE_CHECK=0to disable, or[update] auto_update = true/CCC_AUTO_UPDATE=1to backgroundcargo install cccwhen the install is cargo-based ccc configis the source of truth for which config files currently resolve in the active shellccc config --edit [--user|--local]opens the selected config in$EDITOR; user config meansXDG_CONFIG_HOME/ccc/config.tomlwhen XDG is set, otherwise~/.config/ccc/config.toml, and local config means the nearest existing.ccc.tomlor a new.ccc.tomlin the current directoryccc add <alias>writes the active write target: project-local config when present, otherwise the effective global config; when no config exists it creates a new global config underXDG_CONFIG_HOME/ccc/config.tomlor~/.config/ccc/config.toml, and-gforces the effective global config instead of a project-local file
ccc c --service-tier ultrafast "Review these changes"
ccc c +ultra --service-tier ultrafast "Review these changes"
ccc c +ultra --service-tier ultrafast --standalone "Review these changes"
ccc @reviewer --no-fast "Review these changes"
ccc add quick --runner c --service-tier fast --yesThe alias wizard includes a service-tier menu with separate inherit and default choices. To remove a saved tier, run ccc add quick --unset service-tier --yes.
Codex ultra effort is +ultra / +6. Profiles use thinking = 6, and ccc add quick --thinking ultra --yes or the thinking menu can save it. Effort and service tier are independent controls.
cccwritesoutput.txtplus exactly one transcript file in each run directory:transcript.txtfor text and human transcript paths,transcript.jsonlfor JSON-oriented paths;textrequests that are upgraded into structured streaming still usetranscript.txt- each run directory is client-prefixed, for example
opencode-<run-id> cccprints a stable stderr footer in the form>> ccc:output-log >> /abs/path/to/run-dirunless--no-output-log-pathis set
- planned config support should eventually allow:
- broader multi-language rollout for the Python/Rust config surface
- multi-provider, multi-preset, and multi-alias routing policies
- broader multi-language rollout is still pending for the extended control-token surface
- import path:
call_coding_clis - current API:
CommandSpec,CompletedRun,Runner,render_example_config
- crate name:
call-coding-clis - library name:
call_coding_clis - current API:
CommandSpec,CompletedRun,Runner,render_example_config
- living backlog of unfinished work: TASKS.md
- implement remaining 12 languages (see
PLAN.mdin each directory) - parser and config design for planned alias, thinking, runner, and provider/model selectors:
CCC_PARSER_CONFIG_DESIGN.md - language scaffold doc:
ROADMAP_LANGUAGE_SCAFFOLDS.md - cross-language test harness design:
TEST_HARNESS_PLAN.md - broader rollout of expanded
ccctoken parsing for@name,+0..+6,:provider:model,:model, and runner selectors beyond Python/Rust - future advanced tool allow/deny design note: docs/clis/allow-deny-tool-plan.md
- shared model-thinking capability source of truth and refresh instructions: docs/clis/model-capabilities.json and docs/clis/updating-model-capabilities.md
- broader rollout of Python/Rust config-backed presets, runner abbreviations, agent defaults, and provider/model resolution
- richer stdin/cwd/env coverage and docs for every implementation
- v2: templated or user-customizable rendering for structured output
- v2: HTTP/HTTPS delivery of run artifacts and final output logs, tracked in TASKS.md
Unlicense — see UNLICENSE.