CLI Agent Orchestrator Codebase

July 1, 2026 · View on GitHub

Architecture Overview

┌─────────────────────────────────────────────────────────────────────┐
│                         Entry Points                                │
├─────────────────────────────┬───────────────────────────────────────┤
│       CLI Commands          │         MCP Server                    │
│       (cao launch)          │    (handoff, send_message)            │
└──────────────┬──────────────┴──────────────┬────────────────────────┘
               │                             │
               └─────────────┬───────────────┘

                      ┌──────▼──────┐
                      │  FastAPI    │
                      │  HTTP API   │
                      │  (:9889)    │
                      └──────┬──────┘

                      ┌──────▼──────┐
                      │  Services   │
                      │  Layer      │
                      ├─────────────┤
                      │ • session   │
                      │ • terminal  │
                      │ • inbox     │
                      │ • flow      │
                      └──────┬──────┘

                ┌────────────┴────────────┐
                │                         │
           ┌────▼────┐               ┌────▼─────┐
           │ Clients │               │Providers │
           ├─────────┤               ├──────────┤
           │ • tmux  │               │ • kiro   │
           │ • db    │               │   _cli   │
           └────┬────┘               │ • claude │
                │                    │   _code  │
         ┌──────┴──────┐             │ • codex  │
         │             │             │          │
    ┌────▼────┐  ┌─────▼─────┐      │          │
    │  Tmux   │  │  SQLite   │      │          │
    │ Sessions│  │  Database │      │          │
    └─────────┘  └───────────┘      └────┬─────┘

                                   ┌─────▼──────┐
                                   │ CLI Tools  │
                                   │• Kiro CLI  │
                                   │  (default) │
                                   │• Claude    │
                                   │  Code      │
                                   │• Codex CLI │
                                   └────────────┘

Directory Structure

src/cli_agent_orchestrator/
├── cli/commands/          # Entry Point: CLI commands
│   ├── launch.py          # Creates terminals with agent profiles (workspace trust confirmation, --yolo flag)
│   ├── info.py            # Show session info (cao info)
│   ├── mcp_server.py      # Start MCP server (cao mcp-server)
│   └── init.py            # Initializes database
├── mcp_server/            # Entry Point: MCP server
│   ├── server.py          # Handoff & send_message tools
│   └── models.py          # HandoffResult model
├── api/                   # Entry Point: HTTP API
│   └── main.py            # FastAPI endpoints (port 9889)
├── services/              # Service Layer: Business logic
│   ├── event_bus.py       # Pub/sub event routing with wildcard topic matching
│   ├── fifo_reader.py     # Publisher: terminal.{id}.output (FIFO → event bus)
│   ├── status_monitor.py  # Consumer: terminal.{id}.output → Publisher: terminal.{id}.status
│   ├── log_writer.py      # Consumer: terminal.{id}.output (writes debug logs)
│   ├── inbox_service.py   # Consumer: terminal.{id}.status (delivers queued messages)
│   ├── session_service.py # List, get, delete sessions
│   ├── terminal_service.py# Create, get, send input, get output, delete terminals
│   └── flow_service.py    # Scheduled flow execution
├── clients/               # Client Layer: External systems
│   ├── tmux.py            # Tmux operations (sets CAO_TERMINAL_ID, send_keys, send_keys_via_paste for bracketed paste)
│   └── database.py        # SQLite with terminals & inbox_messages tables
├── providers/             # Provider Layer: CLI tool integration
│   ├── base.py            # Abstract provider interface (mark_input_received hook)
│   ├── manager.py         # Maps terminal_id → provider
│   ├── kiro_cli.py        # Kiro CLI provider (kiro_cli) - default
│   ├── claude_code.py     # Claude Code provider (claude_code, ❯ prompt, trust prompt handling)
│   └── codex.py           # Codex/ChatGPT CLI provider (codex, developer_instructions, › prompt + • bullet detection, trust prompt handling)
├── models/                # Data models
│   ├── terminal.py        # Terminal, TerminalStatus
│   ├── session.py         # Session model
│   ├── inbox.py           # InboxMessage, MessageStatus
│   ├── flow.py            # Flow model
│   └── agent_profile.py   # AgentProfile model
├── utils/                 # Utilities
│   ├── terminal.py        # Generate IDs, wait for shell/status
│   ├── logging.py         # File-based logging
│   ├── agent_profiles.py  # Load agent profiles
│   └── template.py        # Template rendering
├── agent_store/           # Agent profile definitions (.md files)
│   ├── developer.md
│   ├── reviewer.md
│   └── code_supervisor.md
└── constants.py           # Application constants

Data Flow Examples

Terminal Creation Flow

cao launch --agents code_sup

terminal_service.create_terminal()

tmux_client.create_session(terminal_id)  # Sets CAO_TERMINAL_ID

database.create_terminal()

provider_manager.create_provider()

provider.initialize()  # Waits for shell (all providers), sends command, waits for IDLE

fifo_manager.create_reader(terminal_id)  # Starts FIFO reader thread

Returns Terminal model

Inbox Message Flow

MCP: send_message(receiver_id, message)

API: POST /terminals/{receiver_id}/inbox/messages

database.create_inbox_message()  # Status: PENDING

inbox_service.deliver_pending(receiver_id)  # immediate attempt on POST

If receiver IDLE/COMPLETED → send immediately (mark DELIVERED first, #164)
If receiver busy → message stays PENDING

FIFO output → StatusMonitor publishes terminal.{id}.status on change

InboxService (consumes terminal.*.status) calls deliver_pending() on IDLE/COMPLETED

Update message status: DELIVERED

Handoff Flow

MCP: handoff(agent_profile, message)

API: POST /sessions/{session}/terminals

Wait for terminal IDLE

API: POST /terminals/{id}/input

Poll until status = COMPLETED

API: GET /terminals/{id}/output?mode=last

API: POST /terminals/{id}/exit

Return output to caller