Skip to content

v2.5.0

Choose a tag to compare

@github-actions github-actions released this 28 Aug 04:36
· 311 commits to main since this release
a5ccbe2

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 tui is 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_service plus use_worktree on handoff and assign (#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 a list_siblings discovery tool (#433).
  • Security hardening across the HTTP and WebSocket API, plus the
    coordinated cao install path-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 tui front door (#547).
  • worktree_service.py and use_worktree on handoff/assign (#495).
  • Terminal group and metadata fields, plus the list_siblings discovery 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-liveness skill for verifying session state (#646).
  • Tool-restrictions example demonstrating per-role access (#635).
  • ops-mcp example 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_authority is 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
    TmuxLookupError instead of surfacing as a bare ValueError that reads like
    "session not found" one layer up. libtmux 0.53.1+ zips parse_output's fields
    with strict=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_session no 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_sessions surfaces working_directory and agent_profile, persists the
    effective canonical launch directory, stays stable after a pane cd, 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-tools startup consent dialog (#557).
  • agent-step cleans 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 install derived the shared context-copy filename
    — and the per-provider agent-file names — from a profile's resolved
    frontmatter name:. 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 .md file the invoking user can write. Because .md is 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 from POST /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_DIR and opened with O_NOFOLLOW (POSIX), and the context copy
    is created mode 0o600. The provider agent-file sinks flatten both / and \
    via a shared flatten_path_separators helper, 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 malformed Origin (#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-yaml with 4.3.1 (#568, #569), forced nanoid to
    3.3.18 via npm overrides for CVE-2026-67213 (#576), and replaced the vulnerable
    image-size dependency in the docs site with image-size-safe (#622).
  • Declared a direct cryptography>=50.0.0 floor 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 --version

Notes

  • 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 on DELETE /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_session must 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-origin Origin, 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.
  • libtmux is capped at <0.53.1. 0.53.0 is the last release that zips
    parse_output non-strict; every release from 0.53.1 through 0.62.0 raises on a
    short row. clients/tmux.py handles the failure regardless — the cap keeps the
    broken releases from arriving silently on another machine.
  • psutil>=7.0.0 is 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.

Full Changelog: v2.4.1...v2.5.0