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>
165 lines
4.6 KiB
Markdown
165 lines
4.6 KiB
Markdown
# 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_sqlite` provides clean RAII semantics
|
|
- Statement caching for performance
|
|
- Proper NULL handling via Option types
|
|
- WAL mode works correctly with multiple connections
|
|
|
|
**CLI Generation:**
|
|
- `cligen` generates CLI from proc signatures
|
|
- Help text from doc comments
|
|
- Type-safe argument parsing
|
|
- Subcommands via `dispatchMulti`
|
|
|
|
Example:
|
|
```nim
|
|
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
|
|
|
|
```nim
|
|
# 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:
|
|
```bash
|
|
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
|
|
- `cligen` reduces 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
|
|
|
|
## References
|
|
|
|
- [Nim Manual](https://nim-lang.org/docs/manual.html)
|
|
- [tiny_sqlite](https://github.com/GULPF/tiny_sqlite)
|
|
- [cligen](https://github.com/c-blake/cligen)
|
|
- [ORC Memory Management](https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc-in-nim.html)
|