Date: 2026-03-26
Subject: ecc-tui v0.1.0 — Agentic IDE Control Plane
Total Lines: 4,417 across 15 .rs files
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 | 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) |
- 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).
| 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.
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.
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.
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.
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.
git2 = "0.20" was previously declared in Cargo.toml but the worktree module shells out to git CLI instead. The dependency adds ~30s to clean builds and increases binary size.
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.
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.
29 test functions across 12 test modules:
| Module | Tests | Coverage Focus |
|---|---|---|
config/mod.rs |
5 | Defaults, deserialization, legacy fallback |
session/mod.rs |
6 | State machine transitions |
session/store.rs |
10 | CRUD, migration, message ops |
session/output.rs |
4 | Ring buffer, broadcast |
observability/mod.rs |
4 | Risk scoring, tool assessment |
Missing test coverage:
dashboard.rs— 0 tests (1,273 lines, the largest module)manager.rs— 0 tests (680 lines, session lifecycle)runtime.rs— 0 tests (process output capture)daemon.rs— 0 tests (background monitoring)comms/mod.rs— 0 tests
The untested modules are the ones doing I/O (spawning processes, writing to SQLite, reading from stdout). These need integration tests with mockable boundaries.
- 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.
| 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 has been removed (it was unused — the worktree module shells out to git CLI). Several other dependencies are outdated; update before the next release.
- Add environment variable support to
Config::load()—ECC_DB_PATH,ECC_WORKTREE_ROOT,ECC_DEFAULT_AGENT. Standard practice for CLI tools.
- 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.
- Add integration tests for
manager.rsandruntime.rs— these modules do process spawning and I/O. Test with mock agents (/bin/echo,/bin/false). - 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/.
- Multi-agent support — make
agent_program()pluggable. Addcodex,opencode,customagent types. - Config validation — validate risk thresholds sum correctly, budget values are positive, paths exist.
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.
| 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.