10 KiB
ECC2 Codebase Research Report
Date: 2026-03-26
Subject: ecc-tui v0.1.0 — Agentic IDE Control Plane
Total Lines: 4,417 across 15 .rs files
1. Architecture Overview
ECC2 is a Rust TUI application that orchestrates AI coding agent sessions. It uses:
- ratatui 0.29 + crossterm 0.28 for terminal UI
- rusqlite 0.32 (bundled) for local state persistence
- tokio 1 (full) for async runtime
- clap 4 (derive) for CLI
Module Breakdown
| Module | Lines | Purpose |
|---|---|---|
session/ |
1,974 | Session lifecycle, persistence, runtime, output |
tui/ |
1,613 | Dashboard, app loop, custom widgets |
observability/ |
409 | Tool call risk scoring and logging |
config/ |
144 | Configuration (TOML file) |
main.rs |
142 | CLI entry point |
worktree/ |
99 | Git worktree management |
comms/ |
36 | Inter-agent messaging (send only) |
Key Architectural Patterns
- DbWriter thread in
session/runtime.rs— dedicated OS thread for SQLite writes from async context viampsc::unbounded_channelwith oneshot acknowledgements. Clean solution to the "SQLite from async" problem. - Session state machine with enforced transitions:
Pending → {Running, Failed, Stopped},Running → {Idle, Completed, Failed, Stopped}, etc. - Ring buffer for session output —
OUTPUT_BUFFER_LIMIT = 1000lines per session with automatic eviction. - Risk scoring on tool calls — 4-axis analysis (base tool risk, file sensitivity, blast radius, irreversibility) producing composite 0.0–1.0 scores with suggested actions (Allow/Review/RequireConfirmation/Block).
2. Code Quality Metrics
| Metric | Value |
|---|---|
| Total lines | 4,417 |
| Test functions | 29 |
unwrap() calls |
3 |
unsafe blocks |
0 |
| TODO/FIXME comments | 0 |
| Max file size | 1,273 lines (dashboard.rs) |
Assessment: The codebase is clean. Only 3 unwrap() calls (2 in tests, 1 in config default()), zero unsafe, and all modules use proper anyhow::Result error propagation. The dashboard.rs file at 1,273 lines exceeds the repo's 800-line max-file guideline, but it is still manageable at the current scope.
3. Identified Gaps
3.1 Comms Module — Send Without Receive
comms/mod.rs (36 lines) has send() but no receive(), poll(), inbox(), or subscribe(). The messages table exists in SQLite, but nothing reads from it. The inter-agent messaging story is half-built.
Impact: Agents cannot coordinate. The TaskHandoff, Query, Response, and Conflict message types are defined but unusable.
3.2 New Session Dialog — Stub
dashboard.rs:495 — new_session() logs "New session dialog requested" but does nothing. Users must use the CLI (ecc start --task "...") to create sessions; the TUI dashboard cannot.
3.3 Single Agent Support
session/manager.rs — agent_program() only supports "claude". The CLI accepts --agent but anything other than "claude" fails. No codex, opencode, or custom agent support.
3.4 Config — File-Only
Config::load() reads ~/.claude/ecc2.toml only. The implementation lacks environment variable overrides (e.g., ECC_DB_PATH, ECC_WORKTREE_ROOT) and CLI flags for configuration.
3.5 Legacy Dependency Candidate: git2
git2 = "0.20" is still declared in Cargo.toml, but the worktree module shells out to the git CLI instead. That makes git2 a strong removal candidate rather than an already-completed cleanup.
3.6 No Metrics Aggregation
SessionMetrics tracks tokens, cost, duration, tool_calls, files_changed per session. But there's no aggregate view: total cost across sessions, average duration, top tools by usage, etc. The Metrics pane in the dashboard shows per-session detail only.
3.7 Daemon — No Health Reporting
session/daemon.rs runs an infinite loop checking session timeouts. No health endpoint, no log rotation, no PID file, no signal handling for graceful shutdown. Ctrl+C during daemon mode kills the process uncleanly.
4. Test Coverage Analysis
34 test functions across 10 source modules:
| Module | Tests | Coverage Focus |
|---|---|---|
main.rs |
1 | CLI parsing |
config/mod.rs |
5 | Defaults, deserialization, legacy fallback |
observability/mod.rs |
5 | Risk scoring, persistence, pagination |
session/daemon.rs |
2 | Crash recovery / liveness handling |
session/manager.rs |
4 | Session lifecycle, resume, stop, latest status |
session/output.rs |
2 | Ring buffer, broadcast |
session/runtime.rs |
1 | Output capture persistence/events |
session/store.rs |
3 | Buffer window, migration, state transitions |
tui/dashboard.rs |
8 | Rendering, selection, pane navigation, scrolling |
tui/widgets.rs |
3 | Token meter rendering and thresholds |
Direct coverage gaps:
comms/mod.rs— 0 testsworktree/mod.rs— 0 tests
The core I/O-heavy paths are no longer completely untested: manager.rs, runtime.rs, and daemon.rs each have targeted tests. The remaining gap is breadth rather than total absence, especially around comms/, worktree/, and more adversarial process/worktree failure cases.
5. Security Observations
- No secrets in code. Config reads from TOML file, no hardcoded credentials.
- Process spawning uses
tokio::process::Commandwith explicitStdio::piped()— no shell injection vectors. - Risk scoring is a strong feature — catches
rm -rf,git push --force origin main, file access to.env/secrets. - No input sanitization on session task strings. The task string is passed directly to
claude --print. If the task contains shell metacharacters, it could be exploited depending on howCommandhandles argument quoting. Currently safe (arguments are not shell-interpreted), but worth auditing.
6. Dependency Health
| Crate | Version | Latest | Notes |
|---|---|---|---|
| ratatui | 0.29 | 0.30.0 | Update available |
| crossterm | 0.28 | 0.29.0 | Update available |
| rusqlite | 0.32 | 0.39.0 | Update available |
| tokio | 1 | 1.50.0 | Update available |
| serde | 1 | 1.0.228 | Update available |
| clap | 4 | 4.6.0 | Update available |
| chrono | 0.4 | 0.4.44 | Update available |
| uuid | 1 | 1.22.0 | Update available |
git2 is still present in Cargo.toml even though the worktree module shells out to the git CLI. Several other dependencies are outdated; either remove git2 or start using it before the next release.
7. Recommendations (Prioritized)
P0 — Quick Wins
- Add environment variable support to
Config::load()—ECC_DB_PATH,ECC_WORKTREE_ROOT,ECC_DEFAULT_AGENT. Standard practice for CLI tools.
P1 — Feature Completions
- Implement
comms::receive()/comms::poll()— read unread messages from themessagestable, optionally with abroadcastchannel for real-time delivery. Wire it into the dashboard. - Build the new-session dialog in the TUI — modal form with task input, agent selector, worktree toggle. Should call
session::manager::create_session(). - Add aggregate metrics — total cost, average session duration, tool call frequency, cost per session. Show in the Metrics pane.
P2 — Robustness
- Expand integration coverage for
manager.rs,runtime.rs, anddaemon.rs— the repo now has baseline tests here, but it still needs failure-path coverage around process crashes, timeouts, and cleanup edge cases. - Add first-party tests for
worktree/mod.rsandcomms/mod.rs— these are still uncovered and back important orchestration features. - Add daemon health reporting — PID file, structured logging, graceful shutdown via signal handler.
- Task string security audit — The session task uses
claude --printviatokio::process::Command. Verify arguments are never shell-interpreted. Checklist: confirmCommandarg usage, threat-model metacharacter injection, input validation/escaping strategy, logging of raw inputs, and automated tests. Re-audit if invocation code changes. - Break up
dashboard.rs— extract SessionsPane, OutputPane, MetricsPane, LogPane into separate files undertui/panes/.
P3 — Extensibility
- Multi-agent support — make
agent_program()pluggable. Addcodex,opencode,customagent types. - Config validation — validate risk thresholds sum correctly, budget values are positive, paths exist.
8. Comparison with Ratatui 0.29 Best Practices
The codebase follows ratatui conventions well:
- Uses
TableStatefor stateful selection (correct pattern) - Custom
Widgettrait implementation forTokenMeter(idiomatic) tick()method for periodic state sync (standard)broadcast::channelfor real-time output events (appropriate)
Minor deviations:
- The
Dashboardstruct directly holdsStateStore(SQLite connection). Ratatui best practice is to keep the state store behind anArc<Mutex<>>to allow background updates. Currently the TUI owns the DB exclusively, which blocks adding a background metrics refresh task. - No
Clearwidget usage when rendering the help overlay — could cause rendering artifacts on some terminals.
9. Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Dashboard file exceeds 1500 lines (projected) | High | Medium | At 1,273 lines currently (Section 2); extract panes into modules before it grows further |
| SQLite lock contention | Low | High | DbWriter pattern already handles this |
| No agent diversity | Medium | Medium | Pluggable agent support |
| Task-string handling assumptions drift over time | Medium | Medium | Keep Command argument handling shell-free, document the threat model, and add regression tests for metacharacter-heavy task input |
Bottom line: ECC2 is a well-structured Rust project with clean error handling, good separation of concerns, and strong security features (risk scoring). The main gaps are incomplete features (comms, new-session dialog, single agent) rather than architectural problems. The codebase is ready for feature work on top of the solid foundation.