Repository navigation
v2.5.0
Highlights
CAO 2.5 ships the Rust cao tui front door, makes script-tier workflows durable
and replayable, adds three providers, and closes a wave of API and install
security findings.
cao tuiis now a Rust front door, with a semantic colour layer, folded
pickers, and reveal-before-run. The bundled binary is built at install time
rather than only at release, and the wheel is now tagged per platform so pip
refuses an incompatible one instead of installing a TUI that cannot execute
(#321, #547, #561, #564).- Script-tier workflows become durable and replayable. Async run submit,
run discovery, and live event following (#525); a durable run journal with
event log and playback (#526); deterministic Python replay (#628); and a
frozen execution manifest with plan approval and frozen run memory (#650). - Three new providers: the official xAI Grok CLI (#596), Oh My Pi (#572),
and MiniMax Code (#625) — each with isolated per-terminal MCP configuration,
lifecycle detection, and supervisor/worker orchestration coverage. - Worktree-isolated delegation arrives as Phase 1 of #100: a
worktree_serviceplususe_worktreeonhandoffandassign(#495). - The profile and terminal API surface grows: frontmatter validation and
schema endpoints (#575), scope-guarded profile write endpoints (#585), and
terminal group/metadata fields with alist_siblingsdiscovery tool (#433). - Security hardening across the HTTP and WebSocket API, plus the
coordinatedcao installpath-traversal fix — see Security.
Added
- xAI Grok CLI (
grok_cli) provider, with isolated per-terminal MCP
configuration, native hard tool restrictions, multi-turn TUI support, and
orchestration e2e coverage (#596). - Oh My Pi (
omp) provider, with additive native configuration, profile MCP
extension wiring, and lifecycle detection (#572). - MiniMax Code (
mcode) provider, with per-terminal authentication and profile
isolation, model and MCP configuration, and supervisor/worker E2E coverage
(#625). - Rust rewrite of the
cao tuifront door (#547). worktree_service.pyanduse_worktreeonhandoff/assign(#495).- Terminal group and metadata fields, plus the
list_siblingsdiscovery tool
(#433). - Workflow async run submit, discovery, and live event following (#525).
- Workflow durable run journal with event log and playback (#526).
- Deterministic Python workflow replay (#628).
- Workflow frozen execution manifest, plan approval, and frozen run memory
(#650). - Profile frontmatter validation and schema endpoints (#575).
- Scope-guarded profile write endpoints (#585).
- Per-agent reasoning effort for Claude Code via
claudeConfig(#283). - Resume a prior Claude Code conversation in the supervisor (#666).
cao-session-livenessskill for verifying session state (#646).- Tool-restrictions example demonstrating per-role access (#635).
ops-mcpexample for external session management (#647).- The new CAO logo across the docs site, READMEs, and dashboard (#686), and a
contributor blog on the documentation site (#685).
Improved
- Claude Code
initialize()no longer blocks the shared event loop (#451). - Codex status detection now reads the rendered screen (#579), recognises the
runtime approval prompt codex 0.147.0 actually renders (#567), and recognises
the 0.149 idle composer (#655). - Memory plugins route through the backend abstraction, fixing a silent no-op on
herdr (#554); Hermes and status likewise route through the backend (#678). - tmux panes support mouse scrolling, and copy mode is cancelled before
orchestrated input so a scrolled pane no longer swallows it (#676). - The Trivy gate is now legible and blocking rather than advisory (#569), and the
docs-site deploy is gated off by default on forks (#574). - The documented unit-test command no longer selects e2e tests (#679); the README
clarifies the Oh My Pi CLI reference (#631). - Test hygiene: the profile truncation lookahead boundary is pinned (#660), tmux
teardown tests wait for the server to exit before asserting absence (#683), and
the suite is isolated from persisted CAO settings (#684). _origin_authorityis retired as a wrapper, with the scheme guard's
applicability documented at the call site (#669).
Fixed
- tmux listing parse failures are retried once and reported as a distinct
TmuxLookupErrorinstead of surfacing as a bareValueErrorthat reads like
"session not found" one layer up. libtmux 0.53.1+ zipsparse_output's fields
withstrict=True, so any short row raised
ValueError: zip() argument 2 is shorter than argument 1, which blocked
launches outright and left the pipe-liveness watchdog unable to tell a
genuinely-gone session from a transient parse failure. A failed
create_sessionno longer leaves an orphaned tmux session that blocks
relaunching the same name (#555). - Session teardown is now atomic, so tmux and the terminal registry can no longer
diverge into an orphaned session or ghost rows that later misattribute a reused
session name (#498). See Notes for the error-contract change. list_sessionssurfacesworking_directoryandagent_profile, persists the
effective canonical launch directory, stays stable after a panecd, and
purges stale terminal rows before same-name relaunches (#497).- Codex handoff extraction skips native TUI activity cells without relying on an
English verb allowlist, including when the model's reply starts with prose
(#545). - Codex no longer inlines
developer_instructions, using a temp file plus
command substitution instead (#540). - Claude Code no longer tears down a session over an unrecognised startup prompt
(#539). - Kiro auto-answers the
--trust-all-toolsstartup consent dialog (#557). agent-stepcleans up the terminal when output extraction fails (#613), and
output-extraction failures are reported as HTTP 500 rather than 404 (#630).- A prompt the OpenCode handoff worker never received is now re-delivered (#670).
- The probe-throws-because-gone FIFO liveness storm is bounded (#598).
- The social card no longer carries the repo URL (#688).
Security
- Path traversal in
cao install(GHSA-6m35-gcf5-xm75, CWE-22/CWE-73, high;
affects 2.2.0–2.4.1).cao installderived the shared context-copy filename
— and the per-provider agent-file names — from a profile's resolved
frontmattername:. That value is not covered by the install source-handle
validation and is attacker-controlled for URL installs, so a profile whose
name:contained a../traversal or an absolute path could overwrite an
arbitrary.mdfile the invoking user can write. Because.mdis the
trusted-instruction format across this ecosystem, reachable targets included
the user's own agent profiles and global agent-instruction files, after which
an agent run would follow attacker-authored instructions with that agent's tool
permissions. Reachable from the CLI and fromPOST /agents/profiles/install.
The resolved name is now validated as a single path segment via the shared
utils/path_validation.validate_path_component, the write is confined to
AGENT_CONTEXT_DIRand opened withO_NOFOLLOW(POSIX), and the context copy
is created mode0o600. The provider agent-file sinks flatten both/and\
via a sharedflatten_path_separatorshelper, closing the class on Windows as
well (#695). See Notes for the behavior change. - Prevented YAML frontmatter injection in flow creation, which was reachable as
remote code execution (#604). - Blocked cross-origin state-changing HTTP requests (CSRF) (#605), and made the
origin check total against a malformedOrigin(#656) and scheme-aware (#658). - Required a bearer token on the terminal WebSocket when auth is enabled (#608).
- Required read scope on sensitive read endpoints when auth is enabled (#606).
- Replaced vulnerable
js-yamlwith 4.3.1 (#568, #569), forcednanoidto
3.3.18 via npm overrides for CVE-2026-67213 (#576), and replaced the vulnerable
image-sizedependency in the docs site withimage-size-safe(#622). - Declared a direct
cryptography>=50.0.0floor to keep the transitive resolution
off the two HIGH advisories affecting 48.0.1 — GHSA-g6cj-pr64-35w5
(CVE-2026-69247, PKCS#7 Bleichenbacher oracle) and GHSA-jwv3-5hgf-82ww
(CVE-2026-69249, exponential certificate path-building). Neither reaches this
codebase's own call path, but the Trivy gate is repo-wide and now blocking
(#547).
Contributors
Thank you to everyone who contributed to this release:
@anilkmr-a2z, @atirna, @brettinternet, @call-me-ram, @fanhongy, @guojing1217,
@gutosantos82, @haofeif, @harshitwandhare, @hetaoBackend, @klabulan,
@NorethSea, @plauzy, @shpalac, @sujoydc, @tarikermis, @tedswinyar,
@thuanlm215, @TiantianFlow, @vincentqb, @vinhnguyenthanhdn, @vprudnikoff,
@w3lld1, @wbsmolen, and @wearepleh.
Upgrade
Using uv:
uv tool install --force "cli-agent-orchestrator==2.5.0"Using pip:
pip install --upgrade "cli-agent-orchestrator==2.5.0"Verify:
cao --versionNotes
- Behavior change — profile names. A profile whose frontmatter
name:
contains a path separator is no longer installable. Such names only ever worked
when the intermediate context directory happened to already exist, and
permitting them is what allowed the traversal. Rename the profile to a plain
identifier ([A-Za-z0-9._-]) to install it. All 50 profile names in this
repository pass the validator. - Error-contract change — session teardown. A teardown whose tmux kill cannot
be confirmed now raises, surfaced as HTTP 500 onDELETE /sessions/{name},
instead of reporting success. The registry rows are left intact and the
operation is safe to re-run, which reconciles the survivor. Backend authors:
TerminalBackend.kill_sessionmust not return True for a merely-dispatched
kill. - Origin and scope enforcement. The CSRF, WebSocket-token, and read-scope
guards apply when auth is enabled. Existing browser or API clients that issued
state-changing requests without a same-originOrigin, or read sensitive
endpoints without a read scope, will now be rejected. - Per-platform wheels. With the Rust TUI bundled, the wheel is tagged per
platform: macOS arm64, macOS x86_64, Linux x86_64, and Windows AMD64.
musllinux (Alpine) is deliberately not built — an Alpine operator gets a clean
"no matching distribution" from pip rather than a wheel whose binary is linked
against glibc. The macOS x86_64 wheel is cross-compiled and therefore built but
not executed in CI; it is recorded as an explicitly unverified platform. libtmuxis capped at<0.53.1. 0.53.0 is the last release that zips
parse_outputnon-strict; every release from 0.53.1 through 0.62.0 raises on a
short row.clients/tmux.pyhandles the failure regardless — the cap keeps the
broken releases from arriving silently on another machine.psutil>=7.0.0is a new runtime dependency, introduced by the Grok CLI
provider (#596).- Self-learning and AG-UI remain opt-in.
Dependency patch
No Dependabot pull requests landed in this window; the dependency work was
hand-rolled alongside the security fixes.
- fix(security): bump js-yaml to 4.3.1 and make the Trivy gate legible by
@fanhongy in #569 - fix(security): bump nanoid to 3.3.18 (CVE-2026-67213) by @plauzy in
#576 - fix(docs): replace vulnerable image-size dependency by @fanhongy in
#622 - Declared a direct
cryptography>=50.0.0floor (CVE-2026-69247,
CVE-2026-69249) in #547 - Capped
libtmux>=0.51.0,<0.53.1in
#555 - Added
psutil>=7.0.0as a runtime dependency in
#596
Full Changelog: v2.4.1...v2.5.0