Restructure milestones from M1-M11 to M1-M15: - M3: Security Firewall (secret scanner, incognito mode) - M4: Router Foundation (arm registry, pools, task classifier) - M5: TUI with full 6 permission modes - M6: Full compaction (truncate + LLM summarization) - M9: Router Advanced (bandit learning, ensemble strategies) - M11: Task Learning (pattern detection, persistent tasks) Add ADR-007 through ADR-012 for security-as-core, router split, Thompson Sampling, MCP replaceability, task learning, incognito. Add risks R-010 through R-015 for router, security, feedback, task learning, ensemble quality, shell parser. Update architecture dependency graph with security, router, elf, hook, skill, mcp, plugin, tasklearn packages. Update domain model with Router, Arm, LimitPool, Firewall entities.
5.5 KiB
5.5 KiB
essential, status, last_updated, project, depends_on
| essential | status | last_updated | project | depends_on | |
|---|---|---|---|---|---|
| constraints | complete | 2026-04-02 | gnoma |
|
Constraints & Trade-offs
Non-Functional Requirements
| Constraint | Target | Measurement |
|---|---|---|
| First token latency | Dominated by provider, not gnoma overhead | Time from Submit() to first EventTextDelta |
| Binary size | < 20 MB (static, no CGO) | ls -lh bin/gnoma |
| Memory per session | < 50 MB baseline (excluding context window) | runtime.MemStats |
| Startup time | < 200ms to TUI ready | Wall clock from exec to first render |
| Provider support | 5+ providers from M2 | Count of passing provider integration tests |
| Context window | Up to 200k tokens managed | Token tracker reports |
Trade-offs
Single binary over daemon architecture
- Chose: Single Go binary, goroutines + channels for all communication
- Over: Client-server split with gRPC IPC (gnoma + gnomad)
- Because: Simpler deployment, no daemon lifecycle, no protobuf codegen. Go's goroutine model provides sufficient isolation.
- Consequence: True process isolation for tool sandboxing requires future work. Multi-client scenarios (IDE + TUI) need serve mode added later.
Pull-based stream over channels or iter.Seq
- Chose:
Next() / Current() / Err() / Close()interface - Over: Channel-based streaming or Go 1.23+
iter.Seqrange functions - Because: Matches 3 of 4 SDKs natively (zero-overhead adapter). Supports explicit resource cleanup via
Close(). Consumer controls backpressure. - Consequence: Google's range-based SDK needs a goroutine bridge. Slightly more verbose than range-based iteration.
json.RawMessage passthrough over typed schemas
- Chose: Tool parameters and arguments as
json.RawMessage - Over: Typed JSON Schema library or code-generated types
- Because: Zero-cost passthrough — no serialize/deserialize between provider and tool. No JSON Schema library as a core dependency.
- Consequence: Schema validation happens at tool boundaries, not centrally. Type safety relies on tool implementations parsing their own args.
Sequential tool execution (MVP) over parallel
- Chose: Execute tools one at a time in the agentic loop
- Over: Parallel execution via errgroup with read/write partitioning
- Because: Simpler to test, debug, and implement permission prompts. Parallel execution adds complexity around error collection and ordering.
- Consequence: Multiple tool calls in a single turn execute sequentially. Performance impact is minimal for most workloads. Parallel execution planned for post-MVP.
Discriminated union structs over interface hierarchies
- Chose: Struct with Type discriminant field for Content and Event types
- Over: Interface-based variant types (e.g.,
TextContent,ToolCallContentimplementingContent) - Because: Zero allocation, cache-friendly, works with switch exhaustiveness. Go interfaces for data variants incur boxing overhead.
- Consequence: Adding a new content type requires updating switch statements. Acceptable for a small, stable set of variants.
Mistral as M1 reference provider over Anthropic
- Chose: Implement Mistral adapter first as the reference
- Over: Starting with Anthropic (richest content model)
- Because: User maintains the Mistral Go SDK, knows its internals. Good baseline — similar to OpenAI's API shape. Anthropic's unique features (thinking blocks, cache tokens) are better added as an M2 extension.
- Consequence: Thinking block support tested later. Cache token tracking added with Anthropic provider.
Security as core over plugin
- Chose: Security firewall baked into gnoma core (
internal/security/) - Over: MCP-based security server (optional plugin)
- Because: Default-off security is no security. Every user should get secret scanning, unicode sanitization, and incognito mode out of the box.
- Consequence: Core binary is larger. False positives affect all users. Mitigated by configurable sensitivity and warn-first mode.
Proper shell parsing over regex decomposition
- Chose:
mvdan.cc/sh(Go POSIX shell parser) for compound command decomposition - Over: Regex-based
splitCommand()(CC approach, caps at 50 subcommands) - Because: AST-based parsing is accurate for nested structures, doesn't need arbitrary caps, handles edge cases CC's regex misses.
- Consequence: Additional dependency. But
mvdan.cc/shis well-maintained and widely used in the Go ecosystem.
Full 6 permission modes over simplified 3
- Chose: All 6 CC permission modes (default, acceptEdits, bypass, deny, plan, auto)
- Over: Simplified 3-mode system (allow, deny, prompt)
- Because: Users need fine-grained control.
acceptEditsis crucial for trusting file tools while verifying bash.planmode enables read-only exploration.automode uses router signals for smart defaults. - Consequence: More complex permission system. Testing matrix is larger (6 modes × rule types × tool types).
Router split over monolithic
- Chose: Router in two milestones: M4 (heuristic) + M9 (bandit learning)
- Over: Full router in one milestone
- Because: Engine needs routing abstraction early (M4). Bandit learning needs elf feedback (M7) that doesn't exist yet. Building everything at once blocks other milestones.
- Consequence: Two integration points. Heuristic → bandit migration must be seamless.
Changelog
- 2026-04-02: Initial version
- 2026-04-03: Added trade-offs for security-as-core, shell parsing, 6 permission modes, router split