CC-Manager is a multi-agent orchestrator that runs parallel coding agents in isolated git worktrees. It coordinates task scheduling, agent execution, result merging, and persistence through a layered architecture.
types.ts ← Pure types and factory functions (no imports)
↓
logger.ts ← Structured JSON logger (no imports)
↓
store.ts ← SQLite persistence (imports: types, logger)
↓
worktree-pool.ts ← Git worktree lifecycle (imports: types, logger)
↓
agent-runner.ts ← Multi-agent CLI spawning (imports: types, logger)
↓
scheduler.ts ← Task queue + orchestration (imports: types, logger, store, worktree-pool, agent-runner)
↓
server.ts ← HTTP API + SSE (imports: types, logger, scheduler, store, worktree-pool)
↓
index.ts ← CLI entry point (imports: all modules)
Dependency rule: arrows point downward only. No reverse imports.
Shared TypeScript types and the createTask() factory function. Zero dependencies — every other module imports from here.
Key types: Task, TaskStatus, TaskPriority, TaskEvent, WorkerInfo, Stats, EvolutionEntry, HarnessConfig, RoundSummary.
Structured JSON logger with level filtering (debug, info, warn, error). Errors route to stderr, everything else to stdout. Configured via setLogLevel().
SQLite persistence using better-sqlite3 in WAL mode. Manages the tasks and evolution_log tables with automatic schema migration.
Key operations: saveTask(), getTask(), getTasks(), searchTasks(), getDailyStats(), getPerformanceMetrics(), saveEvolution().
Database file: .cc-manager.db in the repository root (gitignored).
Manages git worktree lifecycle. On init, creates .worktrees/worker-{N} directories each on a worker/worker-{N} branch.
Key operations:
init()— parallel worktree creation viagit worktree addacquire()— claim an idle worktree, hard-reset tomainrelease()— free a worktree back to the poolmerge()—git merge --no-editfrom worker branch to main (conflict-safe)
Spawns coding agents as child processes and parses their output. Supports three dispatch modes:
| Agent | CLI | Output format |
|---|---|---|
claude |
claude -p --output-format stream-json |
stream-json events |
codex |
codex exec --json |
JSON result |
| Generic | Any command with prompt as arg | Raw stdout |
Also provides:
buildSystemPrompt()— context-aware prompt with CLAUDE.md injection, tsc checks, scope hintsreviewDiff()— heuristic code review scoringestimateCost()— token-based cost calculationverifyBuild()— post-execution tsc compilation check
Priority-based task queue with dispatch loop. Coordinates between the pool, runner, and store.
Flow:
submit()→ validate, enqueue by priority, persist to storeloop()→ await idle worker, dequeue highest-priority taskexecuteTask()→ acquire worktree, spawn agent, stream events- On completion → merge branch, update store, fire SSE events
Features: retry logic (up to maxRetries), stale worker recovery (60s interval), total budget enforcement, dependency resolution (dependsOn), webhook notifications.
Hono-based HTTP server with 20+ REST endpoints and SSE streaming. Includes rate limiting (30 req/min per IP) and CORS.
Routes map directly to scheduler and store operations. SSE clients receive task_queued, task_started, task_progress, and task_final events.
Commander.js CLI entry point. Parses flags, validates inputs, wires modules together, and handles graceful shutdown (SIGINT/SIGTERM).
Single-file vanilla HTML/JS dashboard. Dark/light theme, SSE-based real-time updates, task submission form, cost charts, daily stats. XSS-hardened with escaping on all interpolated values.
Client → POST /api/tasks → server.ts → scheduler.submit()
→ store.saveTask() → queue.push() → SSE: task_queued
scheduler.loop() → pool.acquire(worker) → runner.run(task, cwd)
→ spawn(agent CLI) → parse stdout → SSE: task_progress
→ runner.verifyBuild() → pool.merge(worker, main)
→ store.saveTask() → SSE: task_final
scheduler.recoverStaleWorkers() [every 60s]
→ check for workers busy > task.timeout × 2
→ force release worker, mark task failed
- Worker pool: Fixed-size array of worktrees, each exclusively locked during task execution
- Task queue: In-memory array sorted by priority, persisted to SQLite on every state change
- Agent processes: Each task gets one
child_process.spawn, killed on timeout viaAbortController - SSE: Fan-out broadcast to all connected clients via
Set<callback> - SQLite: WAL mode handles concurrent reads; writes are serialized by Node.js event loop
- XSS: All user-controlled values escaped before innerHTML insertion (esc() with &, <, >, ", ')
- Rate limiting: 30 requests/minute per IP on mutation endpoints
- Input validation: Prompt length, timeout bounds, budget caps, port range
- Agent isolation: Each agent runs in a separate worktree with its own branch
- Claude nesting prevention:
CLAUDECODEandCLAUDE_CODE_*env vars cleared when spawning