37 KiB
Feature: Agent Work Orders Docker Integration (MVP)
Feature Description
Containerize the Agent Work Orders (AWO) system as a Docker service integrated into Archon's docker-compose architecture. This MVP focuses on getting AWO running reliably in Docker with Claude Code CLI executing inside the container, persistent storage for repositories, and proper authentication for GitHub and Anthropic services.
The scope is deliberately minimal: Docker integration, Claude CLI setup, and persistent volumes. Advanced features like Supabase state persistence, Settings UI integration, and automated cleanup are deferred to future phases per the PRD.
User Story
As an Archon developer I want the Agent Work Orders system to run as a Docker container alongside other Archon services So that I can develop and deploy AWO with the same tooling as the rest of Archon, with persistent repository storage and reliable Claude Code CLI execution
Problem Statement
Agent Work Orders currently runs standalone outside Docker, creating deployment and development friction:
Current State:
- Manual startup:
cd python && uv run uvicorn src.agent_work_orders.main:app --port 8888 - Not in
docker-compose.yml- separate from Archon's architecture - Repositories cloned to
/tmp/agent-work-orders/- lost on reboot - Claude Code CLI runs on host machine, not in container
- No integration with
make devormake dev-docker - Configuration scattered across environment variables
Critical Issue - Claude CLI Execution: The biggest problem: if AWO runs in Docker, but Claude Code CLI executes on the host, you get:
- Path mismatches (container paths vs host paths)
- File access issues (container can't access host files easily)
- Authentication complexity (credentials in two places)
- Deployment failures (production servers won't have Claude CLI installed)
Example Failure Scenario:
1. AWO (in Docker) clones repo to /var/lib/archon-awo/repositories/wo-123/repo
2. AWO calls: `claude --print "implement feature" /var/lib/archon-awo/...`
3. Claude CLI (on host) can't access /var/lib/archon-awo/ (it's inside Docker!)
4. Execution fails
Solution Statement
Create a self-contained Docker service that runs AWO with Claude Code CLI installed and executing inside the same container:
Architecture:
┌─────────────────────────────────────────┐
│ archon-awo (Docker Container) │
│ │
│ ┌────────────────────────────────────┐ │
│ │ AWO FastAPI Server (port 8888) │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Claude Code CLI (installed) │ │
│ │ gh CLI (installed) │ │
│ │ git (installed) │ │
│ └────────────────────────────────────┘ │
│ │
│ Volume: /var/lib/archon-awo/ │
│ ├── repositories/{work-order-id}/ │
│ ├── outputs/{work-order-id}/ │
│ └── logs/ │
└─────────────────────────────────────────┘
Key Principles:
- Everything executes inside container (no host dependencies)
- Single Docker volume for all persistent data
- Standard Linux paths (
/var/lib/archon-awo/) - Opt-in Docker profile (like agents service)
- Keep in-memory state (defer Supabase to Phase 2)
- Simple environment variable configuration
Relevant Files
Use these files to implement the feature:
Docker Configuration:
docker-compose.yml:182 - Addarchon-awoservice definition afterarchon-agents- Define service with opt-in profile
- Single volume mount for persistent data
- Environment variables for authentication
- Dependency on archon-server for shared config
AWO Configuration:
python/src/agent_work_orders/config.py:17-62 - Update paths for Docker- Change from
/tmp/agent-work-orders/to/var/lib/archon-awo/ - Support both Docker and local development paths
- Add Claude API key configuration
- Change from
Sandbox Manager:
python/src/agent_work_orders/sandbox_manager/git_branch_sandbox.py:30-32 - Update repository clone path- Use new
/var/lib/archon-awo/repositories/location - Ensure directories created before clone
- Use new
Environment:
.env.example:69 - Add AWO environment variablesARCHON_AWO_PORT=8888GITHUB_TOKEN=(for gh CLI)ANTHROPIC_API_KEY=(for Claude Code CLI)AWO_DATA_DIR=/var/lib/archon-awo
Makefile:
Makefile:24 - Add AWO development commandsmake dev-awo- Start backend + AWOmake awo-logs- View AWO logsmake awo-restart- Restart AWO service
New Files
python/Dockerfile.awo- Dockerfile for AWO service- Install Claude Code CLI, gh CLI, git
- Set up Python environment
- Configure authentication
- Create data directories
Implementation Plan
Phase 1: Foundation - Dockerfile and Claude CLI Setup
Create the Dockerfile with all required dependencies including Claude Code CLI. This is the critical foundation - getting Claude CLI to run inside the container.
Phase 2: Core Implementation - Docker Compose Integration
Add AWO service to docker-compose.yml with volume configuration, environment variables, and proper dependencies.
Phase 3: Configuration - Path Updates and Authentication
Update AWO code to use container paths and handle authentication for GitHub and Anthropic services.
Step by Step Tasks
IMPORTANT: Execute every step in order, top to bottom.
Research Claude Code CLI Installation
- Check Claude Code documentation: https://docs.claude.com/claude-code
- Determine installation method (npm, binary, or other)
- Test installation locally:
claude --version - Document authentication method (API key, config file, etc.)
- Test headless execution:
claude --print "test" --output-format=stream-json - Verify it works without interactive prompts
Create Dockerfile for AWO Service
- Create
python/Dockerfile.awo - Use Python 3.12 slim base image for consistency with other services
- Install system dependencies:
FROM python:3.12-slim WORKDIR /app # Install system dependencies RUN apt-get update && apt-get install -y \ git \ curl \ ca-certificates \ gnupg \ && rm -rf /var/lib/apt/lists/* - Install gh CLI (GitHub CLI):
# Install gh CLI RUN mkdir -p /etc/apt/keyrings && \ curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ -o /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg && \ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ > /etc/apt/sources.list.d/github-cli.list && \ apt-get update && \ apt-get install -y gh - Install Node.js (needed for Claude Code CLI if npm-based):
# Install Node.js 20 LTS RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ apt-get install -y nodejs - Install Claude Code CLI (adjust based on research):
# Install Claude Code CLI # Option 1: If npm package RUN npm install -g @anthropic-ai/claude-code-cli # Option 2: If binary download # RUN curl -L https://github.com/anthropics/claude-code/releases/download/v1.0.0/claude-linux-x64 \ # -o /usr/local/bin/claude && chmod +x /usr/local/bin/claude - Install Python dependencies with uv:
# Install uv RUN pip install --no-cache-dir uv # Copy dependency files COPY pyproject.toml uv.lock* ./ # Install AWO dependencies RUN uv pip install --system --no-cache . - Copy AWO source code:
# Copy AWO source COPY src/agent_work_orders/ src/agent_work_orders/ COPY src/__init__.py src/ - Create data directory:
# Create data directory with proper permissions RUN mkdir -p /var/lib/archon-awo/repositories \ /var/lib/archon-awo/outputs \ /var/lib/archon-awo/logs && \ chmod -R 755 /var/lib/archon-awo - Set environment variables:
ENV PYTHONPATH=/app ENV PYTHONUNBUFFERED=1 ENV AWO_DATA_DIR=/var/lib/archon-awo ENV ARCHON_AWO_PORT=8888 - Configure entry point:
# Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:${ARCHON_AWO_PORT}/health || exit 1 # Run server CMD ["sh", "-c", "uvicorn src.agent_work_orders.main:app --host 0.0.0.0 --port ${ARCHON_AWO_PORT}"] - Save file
Test Dockerfile Build Locally
- Build the image:
cd /Users/rasmus/Projects/cole/archon docker build -f python/Dockerfile.awo -t archon-awo:test ./python - Verify build succeeds without errors
- Check installed tools:
docker run --rm archon-awo:test claude --version docker run --rm archon-awo:test gh --version docker run --rm archon-awo:test git --version docker run --rm archon-awo:test python --version - Inspect image size:
docker images archon-awo:test - Document any issues and fix before proceeding
Add AWO Service to Docker Compose
- Open
docker-compose.yml - Add service after
archon-agentsservice (around line 182):# Agent Work Orders Service archon-awo: profiles: - awo # Opt-in profile build: context: ./python dockerfile: Dockerfile.awo args: BUILDKIT_INLINE_CACHE: 1 container_name: archon-awo ports: - "${ARCHON_AWO_PORT:-8888}:${ARCHON_AWO_PORT:-8888}" environment: # Core configuration - ARCHON_AWO_PORT=${ARCHON_AWO_PORT:-8888} - AWO_DATA_DIR=/var/lib/archon-awo - LOG_LEVEL=${LOG_LEVEL:-INFO} # Authentication - GITHUB_TOKEN=${GITHUB_TOKEN} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} # Claude CLI configuration - CLAUDE_CLI_PATH=claude - GH_CLI_PATH=gh # Optional: Supabase for future use - SUPABASE_URL=${SUPABASE_URL:-} - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY:-} networks: - app-network volumes: # Single volume for all persistent data - awo-data:/var/lib/archon-awo # Hot reload for development (source code) - ./python/src/agent_work_orders:/app/src/agent_work_orders # Command files - ./python/.claude/commands/agent-work-orders:/app/.claude/commands/agent-work-orders depends_on: archon-server: condition: service_healthy extra_hosts: - "host.docker.internal:host-gateway" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:${ARCHON_AWO_PORT:-8888}/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s - Add volume definition at bottom of file (in volumes section):
volumes: awo-data: # Single volume for AWO data - Save file
Update Environment Configuration
- Open
.env.example - Add new section after existing port configuration (around line 37):
# Agent Work Orders Configuration (Optional - requires --profile awo) ARCHON_AWO_PORT=8888 # GitHub Personal Access Token (for cloning private repos and creating PRs) # Get from: https://github.com/settings/tokens # Required scopes: repo, workflow GITHUB_TOKEN= # Anthropic API Key (for Claude Code CLI) # Get from: https://console.anthropic.com/settings/keys ANTHROPIC_API_KEY= # AWO Data Directory (inside Docker container) AWO_DATA_DIR=/var/lib/archon-awo - Add comment explaining the profile:
# To enable AWO: docker compose --profile awo up -d - Save file
Update AWO Configuration Class
- Open
python/src/agent_work_orders/config.py - Replace the
AgentWorkOrdersConfigclass:class AgentWorkOrdersConfig: """Configuration for Agent Work Orders service""" # ============================================================================ # Storage Paths - Docker-aware with local development fallback # ============================================================================ # Base data directory # Docker: /var/lib/archon-awo # Local dev: ./tmp/agent-work-orders AWO_DATA_DIR: str = os.getenv( "AWO_DATA_DIR", str(Path.cwd() / "tmp" / "agent-work-orders") ) @classmethod def repository_dir(cls) -> Path: """Directory for cloned repositories""" return Path(cls.AWO_DATA_DIR) / "repositories" @classmethod def output_dir(cls) -> Path: """Directory for command outputs and artifacts""" return Path(cls.AWO_DATA_DIR) / "outputs" @classmethod def log_dir(cls) -> Path: """Directory for execution logs""" return Path(cls.AWO_DATA_DIR) / "logs" # ============================================================================ # CLI Tool Paths # ============================================================================ CLAUDE_CLI_PATH: str = os.getenv("CLAUDE_CLI_PATH", "claude") GH_CLI_PATH: str = os.getenv("GH_CLI_PATH", "gh") # ============================================================================ # Authentication # ============================================================================ GITHUB_TOKEN: str | None = os.getenv("GITHUB_TOKEN") ANTHROPIC_API_KEY: str | None = os.getenv("ANTHROPIC_API_KEY") # ============================================================================ # Execution Settings # ============================================================================ EXECUTION_TIMEOUT: int = int(os.getenv("AGENT_WORK_ORDER_TIMEOUT", "3600")) LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") # ============================================================================ # Command Files Directory # ============================================================================ _python_root = Path(__file__).parent.parent.parent _default_commands_dir = str(_python_root / ".claude" / "commands" / "agent-work-orders") COMMANDS_DIRECTORY: str = os.getenv("AGENT_WORK_ORDER_COMMANDS_DIR", _default_commands_dir) # ============================================================================ # Claude CLI Flags # ============================================================================ CLAUDE_CLI_VERBOSE: bool = os.getenv("CLAUDE_CLI_VERBOSE", "true").lower() == "true" _max_turns_env = os.getenv("CLAUDE_CLI_MAX_TURNS") CLAUDE_CLI_MAX_TURNS: int | None = int(_max_turns_env) if _max_turns_env else None CLAUDE_CLI_MODEL: str = os.getenv("CLAUDE_CLI_MODEL", "sonnet") CLAUDE_CLI_SKIP_PERMISSIONS: bool = os.getenv("CLAUDE_CLI_SKIP_PERMISSIONS", "true").lower() == "true" # ============================================================================ # Artifact Logging # ============================================================================ ENABLE_PROMPT_LOGGING: bool = os.getenv("ENABLE_PROMPT_LOGGING", "true").lower() == "true" ENABLE_OUTPUT_ARTIFACTS: bool = os.getenv("ENABLE_OUTPUT_ARTIFACTS", "true").lower() == "true" # ============================================================================ # Deprecated - Backward Compatibility # ============================================================================ TEMP_DIR_BASE: str = AWO_DATA_DIR # Old name, keep for compatibility @classmethod def ensure_directories(cls) -> None: """Ensure all required directories exist""" for directory in [cls.repository_dir(), cls.output_dir(), cls.log_dir()]: directory.mkdir(parents=True, exist_ok=True) - Update any references to
ensure_temp_dir()to useensure_directories() - Save file
Update Sandbox Manager Paths
- Open
python/src/agent_work_orders/sandbox_manager/git_branch_sandbox.py - Update
__init__method (around line 27):def __init__(self, repository_url: str, sandbox_identifier: str): self.repository_url = repository_url self.sandbox_identifier = sandbox_identifier # Ensure directories exist config.ensure_directories() # Use configurable repository directory self.working_dir = str(config.repository_dir() / sandbox_identifier) self._logger = logger.bind( sandbox_identifier=sandbox_identifier, repository_url=repository_url, working_dir=self.working_dir, ) - Save file
Update Agent Executor for Container Environment
- Open
python/src/agent_work_orders/agent_executor/agent_cli_executor.py - Verify Claude CLI path is configurable (should already use
config.CLAUDE_CLI_PATH) - Ensure all file operations use absolute paths from config
- Add logging for CLI tool versions on first use:
# In __init__ or first execution self._logger.info( "cli_tools_configured", claude_cli_path=config.CLAUDE_CLI_PATH, gh_cli_path=config.GH_CLI_PATH, ) - Save file
Update Makefile with AWO Commands
- Open
Makefile - Add new commands after line 24 (after
checktarget):# Agent Work Orders development dev-awo: check @echo "Starting development with Agent Work Orders..." @echo "Backend + AWO: Docker | Frontend: Local with hot reload" @$(COMPOSE) --profile awo up -d --build @set -a; [ -f .env ] && . ./.env; set +a; \ echo "Backend running at http://$${HOST:-localhost}:$${ARCHON_SERVER_PORT:-8181}"; \ echo "AWO running at http://$${HOST:-localhost}:$${ARCHON_AWO_PORT:-8888}" @echo "Starting frontend..." @cd archon-ui-main && \ VITE_ARCHON_SERVER_PORT=$${ARCHON_SERVER_PORT:-8181} \ npm run dev # View AWO logs awo-logs: @echo "Viewing AWO logs (Ctrl+C to exit)..." @$(COMPOSE) logs -f archon-awo # Restart AWO service awo-restart: @echo "Restarting AWO service..." @$(COMPOSE) restart archon-awo @echo "✓ AWO restarted" # Shell into AWO container awo-shell: @echo "Opening shell in AWO container..." @$(COMPOSE) exec archon-awo /bin/bash - Update help text:
help: @echo "Archon Development Commands" @echo "===========================" @echo " make dev - Backend in Docker, frontend local (recommended)" @echo " make dev-awo - Backend + AWO in Docker, frontend local" @echo " make dev-docker - Everything in Docker" @echo " make awo-logs - View Agent Work Orders logs" @echo " make awo-restart - Restart AWO service" @echo " make awo-shell - Shell into AWO container" @echo " make stop - Stop all services" # ... rest of help - Update
stoptarget to include awo profile:stop: @echo "Stopping all services..." @$(COMPOSE) --profile backend --profile frontend --profile full --profile awo down @echo "✓ Services stopped" - Save file
Create Local .env File
- Copy example:
cp .env.example .env - Add your actual credentials:
GITHUB_TOKEN=ghp_...(your actual token)ANTHROPIC_API_KEY=sk-ant-...(your actual key)
- Verify ports don't conflict:
lsof -i :8888 # If in use, change ARCHON_AWO_PORT in .env - Save file
Test Docker Build End-to-End
- Build with docker-compose:
docker compose --profile awo build archon-awo - Verify build completes without errors
- Check build output for any warnings
- Inspect final image:
docker images | grep archon-awo - Expected size: ~500MB-1GB (depending on Node.js + Claude CLI)
Test AWO Container Startup
- Start AWO service:
docker compose --profile awo up -d archon-awo - Watch startup logs:
docker compose logs -f archon-awo - Verify container is running:
docker compose ps archon-awo - Test health endpoint:
curl http://localhost:8888/health | jq - Expected output:
{"status": "healthy", "service": "agent-work-orders", "version": "0.1.0"}
Verify Claude CLI Inside Container
- Shell into container:
docker compose exec archon-awo /bin/bash - Check Claude CLI:
claude --version which claude - Check gh CLI:
gh --version which gh - Check git:
git --version - Test Claude CLI authentication:
# Test simple execution echo "test prompt" > /tmp/test.txt claude --print /tmp/test.txt --output-format=stream-json 2>&1 | head -20 - Exit container:
exit
Verify Volume Persistence
- Check volume created:
docker volume ls | grep awo-data - Inspect volume:
docker volume inspect archon_awo-data - Check directory structure inside container:
docker compose exec archon-awo ls -la /var/lib/archon-awo/ - Expected:
repositories/,outputs/,logs/directories - Create test file in volume:
docker compose exec archon-awo touch /var/lib/archon-awo/test-persistence.txt - Restart container:
docker compose restart archon-awo - Verify file persists:
docker compose exec archon-awo ls /var/lib/archon-awo/test-persistence.txt
Test Work Order Execution
- Create a test work order via API:
curl -X POST http://localhost:8888/agent-work-orders \ -H "Content-Type: application/json" \ -d '{ "repository_url": "https://github.com/Wirasm/dylan.git", "sandbox_type": "git_branch", "workflow_type": "agent_workflow_plan", "user_request": "Test Docker integration - add a simple README file" }' | jq - Note the
agent_work_order_idfrom response - Monitor logs:
docker compose logs -f archon-awo - Check repository was cloned:
docker compose exec archon-awo ls -la /var/lib/archon-awo/repositories/ - Should see directory for work order ID
- Check inside repository:
docker compose exec archon-awo ls -la /var/lib/archon-awo/repositories/sandbox-wo-{ID}/ - Should see cloned repository contents
Test Hot Reload in Development
- Make a simple change to AWO code:
- Edit
python/src/agent_work_orders/main.py - Change version in health endpoint:
"version": "0.1.1-test"
- Edit
- Wait a few seconds for uvicorn to reload
- Check logs for reload message:
docker compose logs archon-awo | grep -i reload - Test updated endpoint:
curl http://localhost:8888/health | jq - Should see new version number
- Revert change back to
"0.1.0"
Test with make Commands
- Stop current container:
docker compose --profile awo down - Test
make dev-awo:make dev-awo - Verify AWO starts with backend
- Frontend should start and show Vite dev server
- Test
make awo-logs(in new terminal):make awo-logs - Test
make awo-restart:make awo-restart - Test
make stop:make stop - All services should stop cleanly
Write Integration Tests
- Create
python/tests/agent_work_orders/test_docker_integration.py:"""Docker integration tests for AWO Tests Docker-specific functionality like paths, volumes, and CLI tools. """ import pytest from pathlib import Path from src.agent_work_orders.config import config def test_data_directory_configured(): """Test that AWO_DATA_DIR is configured""" assert config.AWO_DATA_DIR assert isinstance(config.AWO_DATA_DIR, str) def test_repository_directory_path(): """Test repository directory path construction""" repo_dir = config.repository_dir() assert isinstance(repo_dir, Path) assert repo_dir.name == "repositories" def test_output_directory_path(): """Test output directory path construction""" output_dir = config.output_dir() assert isinstance(output_dir, Path) assert output_dir.name == "outputs" def test_log_directory_path(): """Test log directory path construction""" log_dir = config.log_dir() assert isinstance(log_dir, Path) assert log_dir.name == "logs" def test_directories_can_be_created(): """Test that ensure_directories creates all required directories""" config.ensure_directories() assert config.repository_dir().exists() assert config.output_dir().exists() assert config.log_dir().exists() def test_cli_tools_configured(): """Test that CLI tools are configured""" assert config.CLAUDE_CLI_PATH assert config.GH_CLI_PATH # Should have sensible defaults assert config.CLAUDE_CLI_PATH in ["claude", "/usr/local/bin/claude"] assert config.GH_CLI_PATH in ["gh", "/usr/local/bin/gh"] def test_authentication_optional(): """Test that authentication is optional (not required for tests)""" # These can be None in test environment assert config.GITHUB_TOKEN is None or isinstance(config.GITHUB_TOKEN, str) assert config.ANTHROPIC_API_KEY is None or isinstance(config.ANTHROPIC_API_KEY, str) - Save file
- Run tests:
cd python && uv run pytest tests/agent_work_orders/test_docker_integration.py -v - Verify all tests pass
Run Full Test Suite
- Run all AWO tests:
cd python && uv run pytest tests/agent_work_orders/ -v - Verify no regressions
- Check for any test failures related to path changes
- Fix any failing tests
- Run with coverage:
cd python && uv run pytest tests/agent_work_orders/ --cov=src/agent_work_orders --cov-report=term-missing - Target: >80% coverage maintained
Update Documentation
-
Update
README.mdto include AWO Docker instructions:- Add section under "What's Included" about Agent Work Orders
- Document
--profile awoflag - Add to Quick Test section
- Document required environment variables
-
Create brief AWO quickstart in README:
## Agent Work Orders (Optional) Enable AI-driven development workflows with GitHub integration: ```bash # Add to .env: GITHUB_TOKEN=ghp_your_token_here ANTHROPIC_API_KEY=sk-ant_your_key_here # Start with AWO enabled: docker compose --profile awo up -d # Or using make: make dev-awoAccess API at http://localhost:8888/docs
-
Save README changes
Create Troubleshooting Guide
-
Create
docs/agent-work-orders-docker.md:# Agent Work Orders Docker Guide ## Quick Start 1. Add credentials to `.env`: ```bash GITHUB_TOKEN=ghp_... ANTHROPIC_API_KEY=sk-ant-...-
Start AWO:
docker compose --profile awo up -d -
Verify:
curl http://localhost:8888/health
Troubleshooting
Container won't start
Check logs:
docker compose logs archon-awoClaude CLI not working
Verify installation:
docker compose exec archon-awo claude --versionCheck API key:
docker compose exec archon-awo env | grep ANTHROPIC_API_KEYRepository clone fails
Check GitHub token:
docker compose exec archon-awo gh auth statusVolume permission errors
Check ownership:
docker compose exec archon-awo ls -la /var/lib/archon-awo/Development
- Hot reload: Edit files in
python/src/agent_work_orders/ - View logs:
make awo-logs - Restart:
make awo-restart - Shell access:
make awo-shell
Volume Management
View volume:
docker volume inspect archon_awo-dataBackup volume:
docker run --rm -v archon_awo-data:/data -v $(pwd):/backup \ alpine tar czf /backup/awo-backup.tar.gz /dataRestore volume:
docker run --rm -v archon_awo-data:/data -v $(pwd):/backup \ alpine tar xzf /backup/awo-backup.tar.gz -C / -
-
Save file
Final Validation
Execute every validation command to ensure everything works:
# Build and start
docker compose --profile awo up -d --build
# Health check
curl http://localhost:8888/health | jq
# Check Claude CLI
docker compose exec archon-awo claude --version
# Check gh CLI
docker compose exec archon-awo gh --version
# Check volumes
docker volume ls | grep awo
docker volume inspect archon_awo-data | jq
# Check directory structure
docker compose exec archon-awo ls -la /var/lib/archon-awo/
# Run tests
cd python && uv run pytest tests/agent_work_orders/ -v
# Test hot reload (change version in main.py, verify)
curl http://localhost:8888/health | jq .version
# Test work order creation
curl -X POST http://localhost:8888/agent-work-orders \
-H "Content-Type: application/json" \
-d '{"repository_url":"https://github.com/Wirasm/dylan.git","sandbox_type":"git_branch","workflow_type":"agent_workflow_plan","user_request":"Test"}' | jq
# Check logs
docker compose logs archon-awo --tail=50
# Verify make commands
make awo-logs
make awo-restart
make stop
# Cleanup
docker compose --profile awo down
Testing Strategy
Unit Tests
Configuration Tests:
- Test config loads from environment variables
- Test default values for local development
- Test Docker paths vs local paths
- Test directory creation methods
Path Tests:
- Test repository_dir() returns correct Path
- Test output_dir() returns correct Path
- Test log_dir() returns correct Path
- Test ensure_directories() creates all directories
Integration Tests
Docker Container Tests:
- Test container starts successfully
- Test health check endpoint responds
- Test Claude CLI is accessible in container
- Test gh CLI is accessible in container
- Test git is accessible in container
Volume Tests:
- Test volume is created
- Test data persists across container restarts
- Test directory structure is correct
- Test file permissions are correct
Authentication Tests:
- Test GITHUB_TOKEN is available in container
- Test ANTHROPIC_API_KEY is available in container
- Test gh CLI can authenticate
- Test Claude CLI can authenticate
Edge Cases
Missing Dependencies:
- Claude CLI not installed (build should fail)
- gh CLI not installed (build should fail)
- git not installed (build should fail)
Missing Authentication:
- No GITHUB_TOKEN (should fail when accessing private repos)
- No ANTHROPIC_API_KEY (Claude CLI should fail)
- Invalid tokens (should give clear error messages)
Volume Issues:
- Volume full (should fail gracefully)
- Volume permission denied (should fail with clear error)
- Volume not mounted (should detect and error)
Path Issues:
- Working directory doesn't exist (should create)
- Permission denied on directory creation (should fail)
- Paths exceed maximum length (should handle gracefully)
Acceptance Criteria
Docker Integration:
- ✅ AWO service defined in docker-compose.yml with
--profile awo - ✅ Dockerfile.awo builds successfully
- ✅ Container starts and passes health checks
- ✅ Service accessible at http://localhost:8888
- ✅ Depends on archon-server properly
Claude Code CLI:
- ✅ Claude CLI installed in container
- ✅ Claude CLI executes successfully inside container
- ✅ Claude CLI authenticated with ANTHROPIC_API_KEY
- ✅ Claude CLI can access files in /var/lib/archon-awo/
- ✅ JSONL output parsing works correctly
Git Integration:
- ✅ git CLI installed in container
- ✅ gh CLI installed in container
- ✅ gh CLI authenticated with GITHUB_TOKEN
- ✅ Can clone public repositories
- ✅ Can clone private repositories (with token)
Volume Persistence:
- ✅ Single volume
awo-datacreated - ✅ Volume mounted at /var/lib/archon-awo/
- ✅ Repositories persist across container restarts
- ✅ Outputs persist across container restarts
- ✅ Logs persist across container restarts
Configuration:
- ✅ Config loads from environment variables
- ✅ Paths work in both Docker and local development
- ✅ Authentication configured via .env
- ✅ All required env vars documented in .env.example
Developer Experience:
- ✅
make dev-awostarts AWO with backend - ✅
make awo-logsshows logs - ✅
make awo-restartrestarts service - ✅
make awo-shellprovides container access - ✅ Hot reload works in development mode
- ✅
make stopstops AWO service
Testing:
- ✅ All existing tests pass
- ✅ New Docker integration tests pass
- ✅ Test coverage >80% maintained
- ✅ Manual end-to-end test passes
Documentation:
- ✅ README updated with AWO instructions
- ✅ .env.example has all AWO variables
- ✅ Troubleshooting guide created
- ✅ Docker-specific docs written
Validation Commands
Execute every command to validate the feature works correctly with zero regressions.
# Build image
docker build -f python/Dockerfile.awo -t archon-awo:test ./python
# Verify CLI tools installed
docker run --rm archon-awo:test claude --version
docker run --rm archon-awo:test gh --version
docker run --rm archon-awo:test git --version
# Start with docker-compose
docker compose --profile awo up -d --build
# Health check
curl http://localhost:8888/health | jq
# Verify volume
docker volume ls | grep awo-data
docker volume inspect archon_awo-data | jq
# Check directory structure
docker compose exec archon-awo ls -la /var/lib/archon-awo/
# Verify environment variables
docker compose exec archon-awo env | grep -E "(GITHUB_TOKEN|ANTHROPIC_API_KEY|AWO_DATA_DIR)"
# Test CLI tools in container
docker compose exec archon-awo claude --version
docker compose exec archon-awo gh --version
# Create test work order
curl -X POST http://localhost:8888/agent-work-orders \
-H "Content-Type: application/json" \
-d '{"repository_url":"https://github.com/Wirasm/dylan.git","sandbox_type":"git_branch","workflow_type":"agent_workflow_plan","user_request":"Add README"}' | jq
# View logs
docker compose logs archon-awo --tail=100
# Test persistence (restart and verify volume)
docker compose restart archon-awo
sleep 5
docker compose exec archon-awo ls /var/lib/archon-awo/repositories/
# Run tests
cd python && uv run pytest tests/agent_work_orders/ -v
cd python && uv run pytest tests/agent_work_orders/test_docker_integration.py -v
# Test make commands
make awo-logs
make awo-restart
make awo-shell
make stop
# Resource usage
docker stats archon-awo --no-stream
# Cleanup
docker compose --profile awo down
docker volume rm archon_awo-data
Notes
Critical Decision: Claude CLI Installation Method
Need to verify:
- Is Claude Code CLI distributed as npm package or binary?
- What's the official installation command?
- Does it require Node.js?
- How does authentication work in headless mode?
Action: Research Claude Code CLI docs before implementing Dockerfile.
Docker Volume vs Bind Mount
Using Named Volume (awo-data):
- ✅ Docker-managed, portable
- ✅ Better performance on Mac/Windows
- ✅ Easier backup with Docker commands
- ❌ Not easily accessible from host filesystem
Alternative - Bind Mount:
volumes:
- ./data/agent-work-orders:/var/lib/archon-awo
- ✅ Easy to inspect from host
- ❌ Permission issues on Linux
- ❌ Slower on Mac/Windows
Decision: Use named volume for production-ready approach.
Authentication Handling
GitHub Token:
- Passed via environment variable
- gh CLI uses:
gh auth login --with-token < token - Or:
GITHUB_TOKENenv var (simpler)
Anthropic API Key:
- Passed via environment variable
- Claude CLI likely uses:
ANTHROPIC_API_KEYenv var - Or config file at
~/.claude/config.json
Best Practice: Environment variables for both (simpler, more secure in Docker).
Why Keep In-Memory State for MVP
In-Memory (Current):
- ✅ Simple, no database setup required
- ✅ Fast for MVP
- ✅ PRD says "Phase 2+" for Supabase
- ❌ Lost on container restart
- ❌ Can't scale horizontally
Supabase (Future):
- ✅ Persistent across restarts
- ✅ Multi-instance support
- ✅ Better for production
- ❌ More complex setup
- ❌ Not needed for MVP testing
Decision: In-memory for MVP, Supabase in Phase 2.
Future Enhancements (Not MVP)
Phase 2:
- Migrate state to Supabase
- Add proper work order persistence
- Step history in database
Phase 3:
- Settings UI integration
- Encrypted credential storage
- Web-based work order monitoring
Phase 4:
- Automated cleanup jobs
- Repository caching
- Multi-instance coordination
Resource Requirements
Estimated Container Size:
- Base Python image: ~150MB
- Node.js (if needed): ~200MB
- Claude CLI: ~50-100MB
- Dependencies: ~100MB
- Total: ~500-600MB
Runtime Memory:
- Idle: ~100MB
- Active work order: ~500MB-1GB
- Claude CLI execution: +500MB
Disk Space (Volume):
- Average repository: 50-500MB
- Plan for: 10GB minimum
- Production: 50GB recommended
Security Considerations
Container Security:
- TODO: Run as non-root user
- TODO: Drop unnecessary capabilities
- TODO: Read-only root filesystem where possible
Secret Management:
- Tokens in environment variables (acceptable for MVP)
- Future: Use Docker secrets or vault
- Never commit tokens to git
Network Isolation:
- Container in app-network (isolated)
- Only exposes port 8888
- No direct host access needed