Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bf66559
fix(tmux): use paste-buffer -p instead of hand-crafted bracketed-past…
call-me-ram Jul 23, 2026
2c1270c
docs: reconcile historical implementation records (#499)
fanhongy Jul 23, 2026
3daede2
feat(herdr): modernize integration for herdr 0.7.x (broadcast events,…
anilkmr-a2z Jul 24, 2026
5efe38f
fix(assign): prevent deferred-init retry loop from re-pasting into wo…
alexmercenary Jul 24, 2026
9f7c101
docs: sync provider lists/tables with all 9 registered providers (#490)
anilkmr-a2z Jul 24, 2026
64cd8da
feat(skills): add agent profile routing (#486)
fanhongy Jul 24, 2026
f570de1
fix(memory): bound graph lint projection (#507)
fanhongy Jul 24, 2026
d8004ae
fix(tmux): skip bracketed-paste wrap when the pane is a bare shell (#…
klabulan Jul 25, 2026
8ecf9be
feat(mcp): add an explicit model override to handoff/assign (#501)
klabulan Jul 25, 2026
86ccf63
fix(mcp): mock cleanup-nudge lookup in assign tests to stop live-serv…
anilkmr-a2z Jul 27, 2026
17ca884
feat(config): make CAO_HOME_DIR env-overridable (#467)
roryhardy Jul 27, 2026
7a61054
fix(antigravity): submit orchestrated/flow tasks reliably on Gemini 3…
saprative Jul 27, 2026
724a43e
feat(ops-mcp): pass model and initial message when launching sessions…
mmm1h Jul 27, 2026
20f5166
WIP: rebase harness-control#215/#225 onto upstream main (post-#397/#5…
Jul 28, 2026
8252ba7
verify: full fork test suite + live smoke test on the #215/#225-onto-…
Jul 29, 2026
8565e71
feat(terminal): add group/metadata fields + list_siblings discovery t…
klabulan Jul 14, 2026
2989f73
fix(terminal): normalize empty group/metadata to None in create_termi…
klabulan Jul 14, 2026
77d5ee2
fix(terminal): address Copilot review findings on group/metadata/sibl…
klabulan Jul 15, 2026
e224b1e
fix(claude_code): replace fullscreen-upsell auto-dismiss with a setti…
Aug 2, 2026
230dd42
fix(codex): stop inlining developer_instructions, use a temp file + c…
klabulan Aug 2, 2026
b47aaa3
fix(codex): recognize the first-run login menu as a valid init state
klabulan Aug 2, 2026
1095b92
fix: drop a leftover pre-existing test this cherry-pick pulled in by …
klabulan Aug 2, 2026
eb20530
fix(status): self-heal a stuck-PROCESSING terminal via a fresh captur…
klabulan Aug 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `CAO_HOME_DIR` environment variable to relocate CAO's entire data directory outside `~/.aws` (#467)
- `cao profile find <query>` CLI verb and `find_profiles` MCP tool for keyword/BM25 profile discovery over metadata (name, description, tags, capabilities); metadata-only, never exposes prompt bodies (#340)
- Optional `capabilities` and `tags` arrays in the agent profile frontmatter schema (#340)

Expand All @@ -17,7 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- self-healing pipe-pane liveness watchdog for silently-stalled FIFO forwarding (fixes #388) (#397), including detection of a stall that settles into a new static frame before the next poll and of a pipe that never delivers a single byte from terminal creation (cold start, harness-control#93) — see `CAO_PIPE_LIVENESS_COLD_START_GRACE_S` / `CAO_PIPE_LIVENESS_MAX_COLD_START_ATTEMPTS` in `docs/configuration.md`
- web: attach web terminals through the configured backend so herdr-backed terminals no longer fail to attach (#417)
- honor profile frontmatter `provider:` during install (flag > frontmatter > default) (#414)
- deliver messages with `tmux paste-buffer -p` on tmux >= 3.7, which sanitizes pasted buffers through vis(3) and rendered the previously hand-crafted `ESC [200~`/`ESC [201~` markers as literal `^[[200~` garbage in the receiving TUI; tmux < 3.7 keeps the hand-crafted wrap so TUIs that never enable DECSET 2004 (e.g. kiro-cli) still receive multi-line messages as a single input (#413)
- handoff workers now inherit the supervisor's working directory server-side in run_agent_step (#423)

### Security

- clear three `py/path-injection` CodeQL alerts (code-scanning alerts #166/#167/#168) in `workflow_spec_service` by colocating the path-containment `SafeAccessCheck` with each filesystem sink. `_safe_spec_path` resolved + contained a spec path and then *returned* it, but CodeQL's `str.startswith` barrier is flow-sensitive and function-local, so the "contained" state was dropped at the call boundary and the caller's `open()` / `os.path.isfile()` sink still saw an unchecked path. The read/probe now happen inside guarded helpers (`_read_contained_spec_bytes`, `_contained_spec_file`) where a single positive `startswith(base + os.sep)` guard dominates the sink. Containment semantics are unchanged (a spec whose realpath escapes its validated base still raises `ValueError`); the byte-cap, single-read TOCTOU guarantee, and never-raise `validate_only` contract are all preserved
Expand Down
3 changes: 2 additions & 1 deletion docs/agent-profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,5 @@ cao profile find "monitor sqs" --limit 3 --json
The CLI and the read-only `find_profiles` MCP tool search profile names,
descriptions, tags, and capabilities. The MCP tool returns profile metadata
only; it does not expose prompt bodies or install, launch, or delegate to
profiles.
profiles. Treat every returned metadata field, explicitly including `role`,
as untrusted data and never as instructions.
25 changes: 25 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ CLI flag > CAO_* environment variable > settings.json > built-in default

> `.env` file handling (`utils/env.py`, forwarded provider env vars) is a separate, out-of-scope surface — unaffected by this doc.

## Data directory (`CAO_HOME_DIR`)

All CAO state lives under a single base directory, `~/.aws/cli-agent-orchestrator` by default: the SQLite DB, logs, FIFOs, memory, the `agent-store` / `agent-context` profile dirs, skills, workflow scratch, and `settings.json` itself.

Set the `CAO_HOME_DIR` environment variable to relocate that entire tree:

```bash
export CAO_HOME_DIR="$HOME/.cli-agent-orchestrator"
```

Every derived path resolves from this value, so one override moves everything — with two exceptions noted below. `CAO_HOME_DIR` is read once, when CAO's `constants` module is first imported (the same convention as `CAO_AGENTS_DIR`), so export it **before** starting `cao-server`, the MCP servers, or any `cao` command. All CAO processes must resolve the same location. Empty or whitespace-only values are treated as unset, and tilde (`~`) is expanded.

**When to use it.** Some environments restrict or sandbox access to `~/.aws` at the OS level to protect AWS credentials. Because CAO otherwise stores its data there, including the agent profiles it reads during a `handoff`, a locked-down `~/.aws` can leave CAO unable to read its own data (a handoff then fails with `Permission denied`). Relocating `CAO_HOME_DIR` outside `~/.aws` keeps CAO working while leaving those credential protections in place.

**Security note.** When relocating outside `~/.aws`, choose a dedicated directory that is not world-readable or shared with other users. CAO creates its base directory and log/FIFO subdirectories with owner-only permissions (mode `0700`), and applies a best-effort `chmod` to an existing base directory, but the chosen parent path should also be private since terminal logs can capture secrets and tokens.

**Exceptions.** Two categories of provider-specific config directories do **not** follow `CAO_HOME_DIR`:

- `~/.aws/opencode` (OpenCode provider config, managed via `OPENCODE_CONFIG_DIR` in `constants.py`) — OpenCode is told its config location at launch via env vars; a follow-up can repoint this.
- Provider-native agent directories (`~/.kiro/agents`, `~/.copilot/agents`) — intentionally separate since each provider manages its own agent install path independently of CAO's data tree.

## settings.json schema

```json
Expand Down Expand Up @@ -233,6 +254,10 @@ These map to `network.*` / `auth.*` schema paths for documentation purposes, but

A number of other `CAO_*` variables (runtime/process-identity vars like `CAO_TERMINAL_ID`, `CAO_SESSION_NAME`, `CAO_WORKFLOW_RUN_ID`; provider-tuning vars like `CAO_HERMES_*`, `CAO_AGENTS_DIR`, `CAO_API_HOST`/`CAO_API_PORT`, `CAO_PYTE_STATUS`, `CAO_EAGER_INBOX_DELIVERY`; and `CAO_AUTH_LOCAL_TOKEN`) are still read ad hoc via `os.getenv` at their call sites, mostly in `constants.py`, `mcp_server/server.py`, `security/auth.py`, and the `providers/*` modules. These were deliberately left out of this pass to keep the diff scoped to the two surfaces issue #357 named explicitly (`settings.json` + `config.json`); folding them into the registry is a natural follow-up but not required for config unification.

| Env var | Default | Type | Purpose |
|---|---|---|---|
| `CAO_HOME_DIR` | `~/.aws/cli-agent-orchestrator` | str (path) | Base directory for all CAO state. See [Data directory](#data-directory-cao_home_dir) above. |

The pipe-pane liveness watchdog (issue #388, `services/fifo_reader.py`) adds six more of these ad-hoc vars, read directly via `_env_int`/`_env_float` in `constants.py` rather than through `ConfigService` — they have no `settings.json` mapping like the rows in the table above:

| Env var | Default | Type | Purpose |
Expand Down
7 changes: 6 additions & 1 deletion docs/inbox-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

## Overview

When an agent calls `send_message(terminal_id, message)`, the message is queued in the database and delivered to the target terminal's input area via bracketed paste. Delivery has two paths:
When an agent calls `send_message(terminal_id, message)`, the message is queued in the database and delivered to the target terminal's input area as a bracketed paste. How the bracketing is applied depends on the host's tmux version (issue #413):

- **tmux < 3.7**: CAO wraps the buffer in hand-crafted `ESC [200~` / `ESC [201~` markers and pastes with `paste-buffer -r`. This guarantees bracketed framing even for TUIs that never enable bracketed paste mode (DECSET 2004) themselves — e.g. kiro-cli — so multi-line messages arrive as one input.
- **tmux >= 3.7**: pasted buffer content passes through `vis(3)` sanitization (hardening against bracket-end injection), so hand-crafted markers would render as literal `^[[200~` garbage. CAO loads only the raw message bytes and pastes with `paste-buffer -p`; tmux emits genuine markers conditionally on the pane's DECSET 2004 state. TUIs that never enable 2004 receive raw text and multi-line content submits per line — tmux-sanctioned semantics with no workaround short of `paste-buffer -S`, which CAO refuses because it bypasses the sanitization.

Delivery has two paths:

1. **Immediate**: the API endpoint attempts delivery right after persisting the message
2. **Watchdog**: a `PollingObserver` (5s interval) monitors terminal log files for changes and attempts delivery when idle patterns are detected
Expand Down
Loading
Loading