Documents rationale for using Nim with ORC for the worker coordination CLI: fast startup, single binary, Python-like syntax, excellent SQLite support via tiny_sqlite, CLI generation via cligen. Closes skills-q40 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
ADR-006: Nim for Worker Coordination CLI
Status
Accepted
Context
The multi-agent orchestration system needs a CLI tool (worker) for:
- Spawning worker workspaces with git worktrees
- State machine transitions (ASSIGNED → WORKING → IN_REVIEW → APPROVED → COMPLETED)
- Heartbeat monitoring for stuck agent detection
- SQLite-based message bus for coordination
- Review-gate integration for quality enforcement
Requirements:
- Fast startup (<10ms) for CLI commands run frequently
- Single static binary for deployment simplicity
- SQLite with WAL mode for concurrent access
- Background thread for heartbeat without shared state complexity
- Easy iteration during development
Decision
Use Nim with ORC memory management for the worker CLI.
Core Dependencies
| Package | Purpose |
|---|---|
tiny_sqlite |
SQLite wrapper with RAII, statement caching |
cligen |
Auto-generates CLI from proc signatures |
std/json |
JSON parsing for context files |
Why Nim
Performance:
- ~1ms startup time (vs ~50ms Python, ~20ms Go)
- Compiles to native binary via C backend
- No runtime initialization overhead
Developer Experience:
- Python-like syntax, low learning curve
- REPL available for prototyping (
nim secret) - Compile-time checks catch errors early
- Excellent error messages
Memory Management:
- ORC (Ownership + Reference Counting) handles cycles automatically
- No manual memory management needed
- Deterministic cleanup via destructors
- Thread-safe without shared state via channels
SQLite Integration:
tiny_sqliteprovides clean RAII semantics- Statement caching for performance
- Proper NULL handling via Option types
- WAL mode works correctly with multiple connections
CLI Generation:
cligengenerates CLI from proc signatures- Help text from doc comments
- Type-safe argument parsing
- Subcommands via
dispatchMulti
Example:
proc spawn(taskId: string, description = "", fromBranch = "origin/integration") =
## Create a new worker workspace
...
when isMainModule:
dispatchMulti(
[spawn, help = {"taskId": "Task identifier"}]
)
Alternatives Considered
Python:
- Slow startup (~50ms) unacceptable for frequent CLI calls
- Packaging complexity (venv, dependencies)
- Would work for prototype but not production
Go:
- Faster startup than Python (~20ms) but still slower than Nim
- More verbose syntax
- Good SQLite support via mattn/go-sqlite3
- Reasonable choice but Nim is more pleasant to write
Rust:
- Excellent performance and safety
- Steep learning curve slows iteration
- Borrow checker friction for exploratory code
- Good for later rewrite if needed
Bash:
- Used for review-gate (simpler requirements)
- Inadequate for state machine and SQLite operations
- Error handling is painful
Build Configuration
# config.nims
switch("mm", "orc") # Memory management
switch("threads", "on") # Background heartbeat thread
switch("d", "release") # Optimizations
switch("opt", "size") # Smaller binary
switch("passL", "-lsqlite3") # Link SQLite
Build command:
nim c -d:release src/worker.nim
Architecture
src/
├── worker.nim # CLI dispatch, command implementations
└── worker/
├── types.nim # Shared types, constants, error types
├── db.nim # SQLite operations, message bus
├── state.nim # State machine transitions
├── git.nim # Worktree operations
├── context.nim # Worker context file handling
├── heartbeat.nim # Background heartbeat thread
├── review.nim # Review-gate integration
└── utils.nim # Common helpers
Consequences
Positive
- Sub-millisecond startup enables responsive CLI
- Single binary simplifies deployment
- ORC eliminates memory management burden
cligenreduces CLI boilerplate to near-zero- Python-like syntax enables fast iteration
- Type safety catches bugs at compile time
Negative
- Smaller ecosystem than Python/Go/Rust
- Fewer developers familiar with Nim
- Some library quality variance
- Compiler occasionally has edge case bugs
Mitigations
- Pin Nim version (2.2.x) for stability
- Use well-maintained libraries (tiny_sqlite, cligen)
- Keep modules small and focused for maintainability
- Document patterns for future contributors