v2.2.0
v2.2.0 — 2026-06-04
Highlights
CAO 2.2 introduces persistent agent memory — agents can now store and recall knowledge across sessions through memory_store / memory_recall / memory_forget MCP tools, with global / project / session / agent scoping, BM25 fallback retrieval over a SQLite index, file-lock-safe concurrent writes, per-scope caps, and stable project identity via git remote. Memories auto-inject as <cao-memory> context at session start. Plus a new external-tool integration path that lets CAO orchestrate non-CAO CLI agents (OpenClaw, Hermes Agent, etc.) as first-class workers, handoff terminals that auto-delete after completion with snapshot-based restore, eager inbox delivery for providers that buffer input mid-turn, --env forwarding through cao launch to supervisors and children, codex / claude_code profile fields (codexProfile, permission_mode), an official devcontainer feature, and a stack of TUI-detection, security, and dependency fixes.
Added
-
CAO memory (Phase 1 + 2 + 2.5 hardening) — Three-phase build of a persistent agent memory system. Phase 1 lays down the storage foundation:
memory_store/memory_recall/memory_forgetMCP tools, scope-based partitioning under~/.aws/cli-agent-orchestrator/memory/, and a CLI surface (cao memory list/show/delete/clear). Phase 2 adds SQLite metadata, BM25 fallback retrieval, and<cao-memory>context injection at session start via a context manager. Phase 2.5 hardens the system with per-scope caps (10 entries / 1000 chars), an ISO-8601 Z round-trip lock onindex.md, real-multiprocess flock contention tests, amemory.enabledshort-circuit on recall, and stable project identity via canonicalized git remote (with cwd-hash alias for repos without a remote). See docs/memory.md by @fanhongy in #245, #254, #262 -
External tool integration (OpenClaw, Hermes Agent) — A new external-tool-integration skill lets CAO orchestrate non-CAO CLI agents as first-class workers. Hermes Agent is shipped as a worked end-to-end example — see docs/external-tool-integration.md by @anilkmr-a2z and @haofeif in #241, #253
-
CAO operations MCP server (
cao-mcp-server) — Exposes CAO's session/terminal/launch operations to LLM agents as MCP tools, so a supervisor can drivecao launch,cao session list, etc. via tool calls instead of shell invocations by @patricka3125 in #166 -
Auto-delete handoff terminals with snapshot-based restore —
handoffworkers now self-delete on completion. The supervisor still sees the worker's final output through a captured snapshot, so cross-provider handoff results survive cleanup by @anilkmr-a2z in #233 -
Shell command tracking, flow recycling, inbox delivery reliability — Tracks shell commands per terminal for diagnostics; recycles flow records to avoid unbounded growth; and tightens inbox delivery so messages don't get stuck in PENDING when the receiver was briefly busy by @anilkmr-a2z in #230
-
Eager inbox delivery for buffering providers — Providers like Gemini CLI that buffer pasted input during processing now receive inbox messages eagerly the moment they reach a deliverable state, instead of waiting for a polling tick by @anilkmr-a2z in #251
-
cao launch --envforwarding to supervisor and child agents — Operators can now forward env vars throughcao launch --env; the values travel in the JSON request body (not the URL) so secrets don't land incao-serveraccess logs and propagate to every worker spawned in the session by @call-me-ram in #259 -
codexProfilefield on AgentProfile (codex provider) — OptionalcodexProfilefrontmatter key lets codex agent profiles select a named codex profile at launch by @kjanoudi in #250 -
permission_modefield on AgentProfile (claude_code provider) — Optionalpermission_modefrontmatter key for fine-grained Claude Code permission control beyond the universalallowedToolsvocabulary by @kjanoudi in #244 -
Official devcontainer feature — A reusable devcontainer feature for CAO so contributors can spin up a fully-provisioned dev environment with one click by @ThePlenkov in #260
-
Web UI: filtering, sorting, grouping, and session deletion — Dashboard home gains client-side filter/sort/group, plus a session-delete action so stale sessions can be cleaned up from the browser by @gutosantos82 in #200
-
OpenCode provider label in Web UI —
opencode_clinow appears in the Web UI's provider pickers and/agents/providersresponse, with a friendly "OpenCode" source label by @patricka3125 in #217 -
Auto-derive CORS origins from
cao-server --host/--port— CORS allowlist is now built from the bind address by default, so the Web UI works out of the box on remote hosts without manualCAO_CORS_ORIGINSconfiguration by @call-me-ram in #261
Fixed
-
Codex: detect v0.136+ TUI footer (
model · pathwithoutN% left) — codex 0.136 dropped theN% leftsegment from the status bar, soTUI_FOOTER_PATTERNnever matched andget_status()couldn't tell the suggestion-hint line apart from a real user message. Handoff and assign workers were pinning at IDLE forever. Pattern extended to anchor on the path component shared across v0.111 and v0.136 footers by @haofeif -
Codex: skip
• Called <tool>(...)MCP tool-call markers during last-message extraction — the extractor anchored on the first•after the user prompt, which can be a tool-call marker; the tool output that follows (e.g. thecao-worker-protocolsskill body containing[CAO Handoff]) leaked into the extracted response. The extractor now iterates•matches and skips MCP tool-call markers;ASSISTANT_PREFIX_PATTERNwas also tightened from\s*•to[^\S\n]*•so the match anchors on the bullet line itself, not a preceding blank line by @haofeif -
Kiro CLI: paste-into-boot-screen race that dropped the first message after launch — kiro shows a
M of N mcp servers initializedline before the idle prompt becomes interactive, so a paste arriving in this window was silently absorbed by the boot screen.TUI_INITIALIZING_PATTERNextended to match this line, and Check 3 (shell-baseline = IDLE) gated onself._initializedsoget_status()no longer returns IDLE while kiro is still exec'ing by @haofeif in #268 -
CI: stop TestPyPI squats breaking the release smoke test — the publish workflow's
--extra-index-urlto TestPyPI let a squattedFASTAPI 1.0package outrank realfastapiand break the build. The smoke test now installs our package from TestPyPI with--no-depsand resolves dependencies from PyPI alone, with a fail-fast chain by @haofeif in #270 -
Always honor
profile.providerat launch (yolo + allowed-tools paths) —resolve_providerpreviously lived inside one branch of the permission-resolution conditional inlaunch.py, so--yoloand--allowed-toolspaths silently dropped the profile'sprovider:frontmatter field. Cross-provider workflows where each profile pins a specific CLI now work in every launch path by @call-me-ram in #257 -
Resolve
profile.providerincreate_session()—POST /sessionspassed the caller-supplied provider straight through, so the Web UI and any HTTP client ignoredprofile.provider. The fix preserves explicit--providerover the profile (CLI flag wins) by @gutosantos82 in #198 -
MCP worker provider resolution + ops MCP profile provider — Two related fixes ensuring spawned MCP workers and ops MCP sessions honor the agent profile's declared provider instead of falling back to the supervisor's CLI by @patricka3125 in #224, #229
-
MCP: reject
send_messagewhenreceiver_idequals sender — Prevents an agent from accidentally messaging itself, which produced infinite forwarding loops on some providers by @call-me-ram in #263 -
Wait for IDLE before tmux attach (non-headless launch) — Non-headless
cao launchattached the moment the API returned, racing the provider's TUI init and silently dropping early keystrokes. Mirrors the headless path'swait_until_terminal_status(IDLE/COMPLETED)with a warn-and-attach fallback on timeout by @haofeif in #221 (resolves #220) -
Kiro CLI: false-IDLE during
Initializing...— The new TUI renders the idle-prompt placeholder before init completes; CAO matched the placeholder and dropped the first user message.TUI_INITIALIZING_PATTERNnow unconditionally returns PROCESSING during the init phase by @haofeif in #215 (resolves #211) -
Kiro CLI: SIGWINCH input death from attach-time tmux resize — kiro-cli 2.1.x dropped all input after the 80×24 → real-terminal resize that fired on
cao launchattach. Panes are now created at 220×50 so the attach-time resize is a no-op or small shrink that kiro repaints correctly by @haofeif in #218 (resolves #216) -
Kiro CLI: handoff hang for Q Developer Pro (no Credits marker) — Q Developer Pro doesn't emit the
▸ Credits:marker that CAO used as a completion sentinel in TUI mode. Detection now falls back to the idle-prompt-after-input rule with a separator-based response extractor by @joedarc in #238 -
Gemini CLI: isolate
GEMINI.mdper terminal in a dedicated workspace — Multiple Gemini terminals previously shared oneGEMINI.mdfile via the cwd, racing on writes. Each terminal now gets its own workspace directory by @haofeif in #227 -
OpenCode: poller drains stuck PENDING messages — Adds a periodic drain to OpenCode's inbox delivery path so messages that hit a transient PENDING state don't sit forever by @patricka3125 in #210
-
tmux: filter environment to prevent 'command too long' errors — Pane creation copied the full parent environment, occasionally exceeding tmux's command-line limit on hosts with verbose env. Filtered to a known-safe allowlist by @gutosantos82 in #246
-
API: default
TERMtoxterm-256colorfor tmux PTY attach — Some hosts haveTERM=dumbor unset, breaking color rendering and TUI providers on WebSocket attach. Forcexterm-256colorat the boundary by @call-me-ram in #256 (resolves #150) -
API: configurable network allowlists via env vars —
CAO_ALLOWED_HOSTSand related allowlists are now env-tunable, so deployments behind reverse proxies can opt in to additional Host headers without code changes by @call-me-ram in #255
Documentation
-
Reorganized README + control-plane overview — Split the long README into topic docs and added a control-plane diagram so newcomers can see how
cao-server, MCP, and the providers fit together by @haofeif in #225 -
Web UI build instructions + 404 troubleshooting — Updated the Web UI dev-loop docs and added a section on the most common 404 (built assets missing from the wheel) by @wahidzzz in #252
-
Install via PyPI in README — Documents the
pip install cli-agent-orchestratorpath now that the wheel is published by @fanhongy in #214
Security
-
CodeQL #66 — tmux name validation — Hardens session/window name validation against command injection on every entry point that builds a tmux command line, including a defence-in-depth re-validation at WebSocket attach by @haofeif in #258
-
Agent-name path traversal in profile lookup —
load_agent_profile()resolved user-supplied agent names against profile directories without a path-containment check, allowing../-style escapes that CodeQL flagged with 8 path-injection alerts by @haofeif in #228 -
Agent-profile install — SSRF + path injection —
cao agent install <url>is now hardened against SSRF (URL allowlist, redirect cap) and against profile-name path injection through the install flow by @haofeif in #226 -
Bump
idna3.10 → 3.15 by @dependabot in #247 -
Bump
authlib1.6.11 → 1.6.12 by @dependabot in #236 -
Bump
urllib32.6.3 → 2.7.0 by @dependabot in #234 -
Bump
python-multipart0.0.26 → 0.0.27 by @dependabot in #232 -
Bump
vitest3.2.4 → 4.1.0 in/web(devDependency) by @dependabot in #267
New Contributors
- @joedarc made their first contribution in #238
- @kjanoudi made their first contribution in #244
- @call-me-ram made their first contribution in #255
- @ThePlenkov made their first contribution in #260
Upgrade
uv tool install git+https://github.com/awslabs/cli-agent-orchestrator.git@v2.2.0 --upgradeOr via PyPI:
pip install --upgrade cli-agent-orchestrator==2.2.0No breaking changes to existing CLI invocations or agent profiles. Memory is opt-in per agent profile (memory.enabled) and inert when disabled. Existing handoff workflows continue to work — handoff workers now auto-delete on completion, and the supervisor sees the worker's final output through a snapshot.
Full Changelog: v2.1.1...v2.2.0