diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..57c981f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,100 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +npm install # install dependencies +npm run typecheck # tsc --noEmit (type check without build) +npm run build # compile TypeScript → dist/ (also copies schema.sql) +npm run dev # start daemon on http://127.0.0.1:4517 +npm test # run all tests (node --test via tsx) +tsx --test test/.test.ts # run a single test file +``` + +Worker processes can be run against TypeScript source directly (for dev/testing) via: +```bash +MAESTRO_WORKER_CMD="tsx src/executor/worker.ts" npm run dev +``` + +## Architecture + +Maestro is a local-first daemon that manages tasks across multiple git projects. It drives tasks through a complexity-based approval pipeline and auto-executes approved tasks via headless Claude Code agents. + +### Process Model (critical to understand) + +The system is split into two strictly separated process roles: + +**daemon** (`src/daemon/`) — the only DB writer. Responsible for: +- Serving REST + WebSocket API (`src/api/`) +- Running the orchestrator loop (tick = `ingest → reap → claim`) +- Spawning one worker OS process per task +- Ingesting worker output from `outbox.ndjson` into SQLite +- Reaping dead workers, managing retries/back-off, state transitions + +**worker** (`src/executor/worker.ts` + `src/executor/pipeline.ts`) — a dumb executor that never touches the DB. Each task gets its own `node dist/executor/worker.js `. It reads only `runs//job.json` and appends progress/results to `runs//outbox.ndjson`. The daemon ingests this file idempotently via a `lastSeq` cursor. + +Communication between daemon and worker is **file + signal only** (`job.json`, `outbox.ndjson`, `heartbeat`, `SIGTERM`). This makes execution survive daemon restarts. + +### Key Source Modules + +| Path | Purpose | +|---|---| +| `src/model/` | Types (`types.ts`), state machine (`status.ts`), complexity levels (`complexity.ts`), score scheduling algorithm (`scoring.ts`) | +| `src/store/` | SQLite access layer (`store.ts`), schema (`schema.sql`), state-machine guards, mappers | +| `src/daemon/orchestrator.ts` | Score-based task scheduling loop: `ingest → reap → claim` | +| `src/daemon/ingest.ts` | Reads worker outbox.ndjson, writes DB events, triggers WS push | +| `src/executor/protocol.ts` | File protocol definitions + heartbeat/liveness helpers | +| `src/executor/pipeline.ts` | Worker execution pipeline: worktree setup → agent run → verify → dual review → output | +| `src/executor/cc.ts` | Claude Agent SDK wrapper for headless CC runs | +| `src/executor/reviewer.ts` | Code review + security audit agent runs | +| `src/executor/merge.ts` | `--no-ff` auto-merge logic on exec_review accept | +| `src/api/server.ts` | Fastify REST + WebSocket server | +| `src/mcp/` | MCP server tools exposed to Claude Code sessions | +| `src/sync/` | One-way sync from legacy `todo.json` files | +| `web/` | Dashboard SPA (multi-project, real-time WS, inline approve/reject) | + +### Task Lifecycle + +``` +init → [Hard: analyzing → plan_review] → [Medium: speccing → spec_review] → ready + → queued → executing → exec_review → done +``` + +- **Hard**: planner agent produces analysis + task decomposition; requires `plan_review` approval +- **Medium**: agent writes a spec (what + why); requires `spec_review` approval +- **Easy**: agent writes operations record; goes directly to `ready` +- All tasks with code changes pass through `exec_review` (dual review: code-review + security audit) +- `accept` at `exec_review` triggers automatic `--no-ff` merge; `merge:false` skips merge + +### Score Scheduling + +``` +score = P(self) + Σ P(completed deps) + Σ P(tasks blocked by self) +``` +`P0=3, P1=2, P2=1`. Higher score → picked first. No preemption. + +### Model Tier Assignment + +| Role | Easy | Medium | Hard | +|---|---|---|---| +| executor | claude-sonnet-4-6 | claude-opus-4-8 | claude-fable-5 | +| reviewer | claude-sonnet-4-6 | claude-opus-4-8 | claude-opus-4-8 | + +Project-level `model` setting overrides env vars; env vars override built-in defaults. + +### Data Directory + +Default `~/.maestro/` — contains SQLite DB, `runs//` directories (job.json, outbox.ndjson, heartbeat, sandbox.sb, transcripts), and git worktrees. + +### Key Env Vars + +| Var | Default | Note | +|---|---|---| +| `MAESTRO_PORT` | `4517` | daemon listen port | +| `MAESTRO_DATA_DIR` | `~/.maestro` | SQLite + worktree root | +| `MAESTRO_ORCH_INTERVAL` | `15` | orchestrator tick seconds; `0` disables | +| `MAESTRO_WORKER_CMD` | `node dist/executor/worker.js` | override for tsx dev | +| `MAESTRO_NOTIFY` | on | set `0` to disable macOS notifications | +| `MAESTRO_SANDBOX` | off | set `on` for OS-level write fence + ulimits on workers |