Whim is an autonomous AI development system that transforms GitHub issues into pull requests.
┌─────────────────────────────────────────────────────────────────────────────┐
│ │
│ GitHub │
│ ┌──────┐ │
│ │Issues│ ◄─────────────────────────────────────────────────┐ │
│ └──┬───┘ │ │
│ │ polls (whim label) │ creates │
│ ▼ │ │
│ ┌──────────┐ ┌──────────────┐ ┌────────┐ │ │
│ │ Intake │────────►│ Orchestrator │────────►│ Worker │──┘ │
│ └──────────┘ queue └──────────────┘ spawn └────────┘ │
│ │ ▲ │ │
│ HTTP │ │ heartbeat │ runs │
│ ▼ │ ▼ │
│ ┌────────────┐ ┌─────────┐ │
│ │ PostgreSQL │ │ Ralph │ │
│ │ + Redis │ │ (Claude)│ │
│ └────────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
- Polls GitHub for issues labeled
whim - Generates structured specs from issue descriptions using Claude
- Queues work items with the orchestrator
- Central brain managing the work queue and worker lifecycle
- Queue Manager: Priority-based work queue with PostgreSQL persistence
- Worker Manager: Spawns Docker containers, tracks heartbeats, handles failures
- Rate Limiter: Enforces max workers, cooldowns, daily iteration budgets
- Conflict Detector: File-level locking to prevent concurrent edits
- Runs inside Docker container with isolated environment
- Clones target repo, writes SPEC.md
- Spawns Ralph (Claude Code in autonomous mode)
- Reports progress via heartbeats, creates PR on completion
- Verification worker validates PRs after creation
- Abstraction layer for AI execution (Claude Code, Codex, OpenCode)
- Common interface for spawning and streaming events
- Handles timeouts and error normalization
- Issue Detection: Intake polls GitHub, finds labeled issues
- Spec Generation: Claude converts issue to structured SPEC.md checklist
- Queueing: Work item added to PostgreSQL queue with priority
- Scheduling: Orchestrator checks capacity, assigns next queued item
- Execution: Docker container spawns, worker clones repo and runs Ralph
- Progress: Worker sends heartbeats on each Claude tool call
- Completion: Worker creates PR, reports success, container exits
- Cleanup: Orchestrator releases locks, updates metrics
- Isolation: Each task runs in clean environment
- Security: Limited access to host, resource limits enforced
- Reproducibility: Same image, same behavior
- Cleanup: Container exit = full cleanup
- ACID: Transactions ensure work items aren't lost or duplicated
- FOR UPDATE SKIP LOCKED: Safe concurrent access without lock contention
- Persistence: Survives orchestrator restarts
- Queryable: Easy monitoring and debugging
- Atomic operations: INCR/DECR for counters
- Fast: Sub-millisecond latency
- TTL: Automatic expiration for cooldowns
- Note: Active worker count is derived from PostgreSQL (source of truth)
- Liveness: Detect stuck/crashed workers
- Progress: Track iteration count
- Conflict detection: File locks tied to active workers
API_KEYenvironment variable enables authenticationX-API-Keyheader orAuthorization: Bearer <key>- Health endpoint exempt (for load balancers)
- Worker endpoints exempt (use WORKER_ID)
The orchestrator needs Docker access to spawn worker containers. Instead of mounting the Docker socket directly (which grants root-equivalent host access), we use a Docker Socket Proxy.
How it works:
Orchestrator ──TCP:2375──► Docker Socket Proxy ──socket──► Docker Daemon
(whitelisted API only)
Security benefits:
- API whitelisting - Only container operations allowed (create, start, stop, logs)
- Read-only socket - Proxy mounts socket as read-only
- No direct access - Orchestrator cannot exec into containers, manage volumes, etc.
- Network isolation - Proxy only accessible within
whim-network
Blocked operations (denied by proxy):
exec- Cannot run commands in existing containersvolumes- Cannot mount host pathsnetworks- Cannot create/modify networksbuild- Cannot build imagessystem- Cannot access system infoswarm,secrets,configs- Cluster operations blocked
Configuration (docker-compose.yml):
docker-proxy:
image: tecnativa/docker-socket-proxy
environment:
CONTAINERS: 1 # Allow container operations
IMAGES: 1 # Allow image listing
POST: 1 # Allow POST requests
# All else denied by default- Resource limits: 4GB memory, 2 CPU cores, 256 PIDs
- Non-root user inside container
- Network isolation via
whim-network - No host volume mounts (except workspace)
- Repo format validated:
owner/repopattern - Length limits on repo, branch, spec
- Request body size limit: 1MB
- Heartbeat timeout: Worker killed, work item requeued with backoff
- Container crash: Detected by health check, same as timeout
- Max iterations: Work item marked failed after 3 retries
- Restart: Picks up where it left off (queue in PostgreSQL)
- Stale workers: Health check finds and kills them
- Connection pool with timeouts
- Spawn rollback on failure (delete worker, reset work item)
| Limit | Default | Purpose |
|---|---|---|
| Max Workers | 2 | Concurrent workers |
| Cooldown | 60s | Seconds between spawns |
| Daily Budget | 200 | Max iterations per day |
| Max Retries | 3 | Retries before permanent failure |
Exponential backoff: 1 min → 5 min → 30 min
packages/
├── orchestrator/ # Central coordinator
│ └── src/
│ ├── index.ts # Main loop
│ ├── server.ts # Express API
│ ├── queue.ts # Work queue
│ ├── workers.ts # Worker lifecycle
│ ├── rate-limits.ts # Rate limiting
│ └── conflicts.ts # File locks
├── worker/ # Task executor (runs Ralph/Claude)
│ └── src/
│ ├── index.ts # Execution worker entry
│ ├── verification-worker.ts # Verification worker entry
│ ├── ralph.ts # Claude runner
│ └── setup.ts # Repo setup, PR creation
├── intake/ # GitHub issue poller
├── harness/ # AI harness abstraction (Claude, Codex, OpenCode)
├── shared/ # Shared types and utilities
└── cli/ # Terminal dashboard and commands
POST /api/work- Add work itemGET /api/work/:id- Get work itemPOST /api/work/:id/cancel- Cancel work itemPOST /api/work/:id/requeue- Requeue failed/completed itemGET /api/work/:id/verification- Get linked verification itemGET /api/queue- List queue with stats
POST /api/worker/register- Worker self-registrationPOST /api/worker/:id/heartbeat- Progress updatePOST /api/worker/:id/lock- Acquire file locksPOST /api/worker/:id/unlock- Release file locksPOST /api/worker/:id/complete- Report successPOST /api/worker/:id/fail- Report failurePOST /api/worker/:id/stuck- Report stuck state
GET /health- Health checkGET /api/status- System status overviewGET /api/workers- List workersGET /api/metrics- System metricsGET /api/learnings- Browse learnings