# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. Also check `~/.claude/CLAUDE.md` for user-level development standards (TDD workflow, git practices, session state management, etc.) that apply globally across all projects. ## Canonical Repository **The canonical source of truth is `/workspace/claudomator`.** All development must happen here. Do not work in any other directory unless explicitly instructed. Do not explore `/site/doot.terst.org/` for source files. ## Build & Test Commands ```bash # Build go build ./... # Run all tests go test ./... # Run a single package's tests go test ./internal/executor/... # Run a single test by name go test ./internal/api/ -run TestServer_CreateTask_MissingName # Run with race detector (important for executor/pool tests) go test -race ./... # Build the binary go build -o claudomator ./cmd/claudomator/ ``` > **Note:** `go-sqlite3` uses CGo. A C compiler (`gcc`) must be present for builds and tests. ## Running the Server ```bash # Initialize data directory ./claudomator init # Start API server (default :8484) ./claudomator serve # Run a task file directly (bypasses server) ./claudomator run ./test/fixtures/tasks/simple-task.yaml # List tasks via CLI ./claudomator list ``` Config defaults to `~/.claudomator/config.toml`. Data is stored in `~/.claudomator/` (SQLite DB + execution logs). ## Architecture **Pipeline:** CLI/API → `executor.Pool` → `executor.ClaudeRunner` → `claude -p` subprocess → SQLite + log files ### Packages | Package | Role | |---|---| | `internal/task` | `Task` struct, YAML parsing, state machine, validation | | `internal/executor` | `Pool` (bounded goroutine pool) + `ClaudeRunner` (subprocess manager) | | `internal/storage` | SQLite wrapper; stores tasks and execution records | | `internal/api` | HTTP server (REST + WebSocket via `internal/api.Hub`) | | `internal/reporter` | Formats and emits execution results | | `internal/config` | TOML config + data dir layout | | `internal/cli` | Cobra CLI commands (`run`, `serve`, `list`, `status`, `init`) | ### Key Data Flows **Task execution:** 1. Task created via `POST /api/tasks` or YAML file (`task.ParseFile`) 2. `POST /api/tasks/{id}/run` → `executor.Pool.Submit()` → goroutine in pool 3. `ClaudeRunner.Run()` invokes `claude -p --output-format stream-json` 4. stdout streamed to `~/.claudomator/executions//stdout.log`; cost parsed from stream-json 5. Execution result written to SQLite; broadcast via WebSocket to connected clients **State machine** (`task.ValidTransition`): `PENDING` → `QUEUED` → `RUNNING` → `COMPLETED | FAILED | TIMED_OUT | CANCELLED | BUDGET_EXCEEDED` Failed tasks can retry: `FAILED` → `QUEUED` **WebSocket:** `Hub` fans out task completion events to all connected clients. `Server.StartHub()` must be called after creating the server. ### Task YAML Format ```yaml name: "My Task" claude: model: "sonnet" instructions: | Do something useful. working_dir: "/path/to/project" max_budget_usd: 1.00 permission_mode: "default" allowed_tools: ["Bash", "Read"] timeout: "15m" priority: "normal" # high | normal | low tags: ["ci"] ``` Batch files wrap multiple tasks under a `tasks:` key. ### Storage Schema Two tables: `tasks` (with `config_json`, `retry_json`, `tags_json`, `depends_on_json` as JSON blobs) and `executions` (with paths to log files). Schema is auto-migrated on `storage.Open()`. ## ADRs See `docs/adr/001-language-and-architecture.md` for the Go + SQLite + WebSocket rationale.