Skip to content

[feat] Non-interactive / headless mode for containerized deployments #152

@ThePlenkov

Description

@ThePlenkov

Problem

When running CAO inside a container (Docker, devcontainer, CI/CD), several agent CLIs require interactive first-run setup that blocks automated startup:

Agent Interactive Requirement What Blocks
Claude Code First-run onboarding wizard (theme picker, security notes, trust prompt) CAO provider startup handler cannot navigate the wizard
Codex Interactive workspace trust prompt Provider pattern matching fails on newer Codex versions
Devin CLI devin setup command in installer Blocks non-interactive container builds

Each of these requires a separate workaround:

Claude Code — Pre-write ~/.claude/.claude.json:

{"hasCompletedOnboarding": true, "lastOnboardingVersion": "2.1.84", "theme": "dark"}

Codex — Pre-write ~/.codex/config.toml:

[projects."/workspaces/my-project"]
trust_level = "trusted"

Devin CLI — Strip the devin setup line from the installer script during container build.

Proposed Solution

A --headless flag or CAO_HEADLESS=1 environment variable that:

  1. Auto-configures known agents to skip interactive wizards at provider initialization time (before launching the CLI process in tmux)
  2. Sets workspace trust for the current working directory automatically
  3. Documents the required config files/flags for each provider in a central location

Example behavior

# Container startup
CAO_HEADLESS=1 cao-server --host 0.0.0.0

On cao-server startup with CAO_HEADLESS=1:

  • Detect installed agent CLIs
  • For each known agent, write the minimum config needed to skip interactive prompts
  • Log what was configured

Provider-specific headless config

Each provider could implement a configure_headless(workspace: Path) method:

class ClaudeCodeProvider(BaseProvider):
    def configure_headless(self, workspace: Path) -> None:
        """Pre-configure Claude Code for non-interactive use."""
        claude_json = Path.home() / ".claude" / ".claude.json"
        # Write onboarding completion + theme
        ...

class CodexProvider(BaseProvider):
    def configure_headless(self, workspace: Path) -> None:
        """Pre-configure Codex to trust the workspace."""
        codex_config = Path.home() / ".codex" / "config.toml"
        # Write trust_level = "trusted" for workspace
        ...

Use Cases

  • Docker container deployments
  • Devcontainers (VS Code, GitHub Codespaces)
  • CI/CD pipelines running multi-agent workflows
  • Remote SSH environments
  • Any automated setup where no human is present at first launch

Workaround

We currently handle all of this in a custom entrypoint script (entrypoint.sh) that runs before cao-server starts, with ~70 lines of agent-specific config writing. This works but is fragile — each agent CLI update can change the required config format.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions