feat(stats): introduce privacy-first gains tracking feature @hansipie#162
feat(stats): introduce privacy-first gains tracking feature @hansipie#162yoanbernabeu merged 12 commits intoyoanbernabeu:mainfrom
Conversation
Introduce a privacy-first gains tracking feature that automatically records token usage on every search/trace command and exposes a new `grepai stats` command to visualize savings vs grep-based workflows. All data is stored locally in .grepai/stats.json (NDJSON) and never leaves the machine. - New stats/ package: Entry, Recorder (flock-based append), ReadAll, Summarize, HistoryByDay, cross-platform file locking (Unix/Windows) - New cli/stats.go: `grepai stats [--json] [--history] [--limit N]` with lipgloss human-readable output and JSON mode - cli/search.go + cli/trace.go: fire-and-forget stats recording (100ms timeout goroutine, zero latency impact) - mcp/server.go: stats recording on all MCP tool calls + new grepai_stats MCP tool for agent integration - 13 unit tests, all passing with -race
On Windows, creating symlinks requires elevated privileges or Developer Mode. Skip the test gracefully on Windows; keep t.Fatalf on other platforms.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #162 +/- ##
===========================================
+ Coverage 27.16% 46.58% +19.41%
===========================================
Files 32 78 +46
Lines 3711 14680 +10969
===========================================
+ Hits 1008 6838 +5830
- Misses 2620 7153 +4533
- Partials 83 689 +606 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Thanks for the PR — I’m not a maintainer, but as a contributor/user I’m excited to see this merged. Quick question/idea (feel free to ignore if it’s out of scope): since Totally fine if you’d rather keep this PR focused and tackle any TUI alignment as a follow-up. |
The merge of main into 001-stats-gains produced a broken trace.go: - outputJSON referenced undefined os.Stdout and buf.String() - outputTOON and captureJSON were missing entirely Restore the capture/output pattern from the stats-gains branch: - captureJSON serializes to a buffer (testable, no stdout side-effect) - outputJSON delegates to captureJSON - outputTOON delegates to captureTOON
Introduce outputAndRecord() to centralize the repeated pattern of capturing output and recording trace stats across the three runTrace* functions (callers, callees, graph). Restores the recordTraceStats calls lost during the merge of main into 001-stats-gains.
Code Review —
|
- Move stats.json and stats.json.lock from project root to .grepai/ - Auto-create .grepai/ directory in recorder if it doesn't exist - Capture all text output in buf for accurate token estimation in runSearch - Add recordSearchStats call to runWorkspaceSearch (was untracked) - Remove dead code `_ = symStats` in mcp/server.go - Replace local trimSuffix with strings.TrimSuffix in cli/stats.go - Update stats_test.go to write test files in .grepai/ subdirectory
- Add --no-ui flag to stats command for plain text output - Add viewTokenSavings state to status TUI with keyboard nav (s key) - Add runStatsUI for interactive stats display - Add tui_stats.go with stats TUI implementation - Add tui_stats_test.go with tests
|
Thanks for the thorough review! All 5 points have been addressed:
Bonus — TUI implementation ... done! |
|
Hello |
Code Review — Updated AnalysisGreat work addressing all 5 points from the previous review, and the TUI integration bonus is a nice touch! I found one remaining issue: Bug:
|
| Output mode | runSearch |
runWorkspaceSearch |
|---|---|---|
| JSON | ✅ Line 300 | ❌ Missing (line 663: return nil without recording) |
| TOON | ✅ Line 317 | ❌ Missing (line 679: return nil without recording) |
| No results | ✅ Line 323 | ✅ Line 686 |
| Plain text | ✅ Line 361 | ✅ Line 725 |
Additionally, projectRoot is resolved at line 682, after the JSON/TOON branches (lines 650-679), so it's not available in those code paths. The fix is to move projectRoot, _ := config.FindProjectRoot() before the JSON output mode block, and add the recordSearchStats calls.
Everything else looks solid — the stats/ package architecture, cross-platform file locking, and Bubble Tea TUI are all well implemented.
Move projectRoot resolution before JSON/TOON branches so it is available in all output paths. Add recordSearchStats calls in the JSON and TOON branches of runWorkspaceSearch, which were previously skipped.
|
Hello Indeed ... it's done ! |
|
Thanks for this great contribution @hansipie! 🎉 The implementation is clean, well-tested, and integrates nicely across CLI, TUI, and MCP. Merging! |
Summary
This PR introduces a privacy-first gains monitoring system for grepai. Every
searchandtracecommand now automatically records token usage metrics locally, and a newgrepai statscommand lets users visualize how much they save compared to a traditional grep-based workflow.Motivation
Users had no visibility into the concrete value grepai brings over grep. This feature answers the question: "How many tokens (and dollars) have I actually saved by using grepai?"
What's new
New
stats/packageEntry— one record per search/trace command (timestamp, command type, output mode, result count, tokens consumed, grep-equivalent tokens)Recorder— appends entries as NDJSON to.grepai/stats.jsonusing a file lock (cross-platform:flockon Unix,LockFileExon Windows)ReadAll/Summarize/HistoryByDay— aggregation helpersGrepEquivalentTokens(n)— estimates what grep would have cost:n × 512 tokens × 3(expansion factor for context)nilfor local providers (Ollama, LM Studio)-race, all greenNew
grepai statscommand (cli/stats.go)--json— structured JSON output for scripting/agents--history— per-day breakdown table--limit N— max days shown (default: 30)Auto-recording in
searchandtraceStats are recorded fire-and-forget in a goroutine with a 100 ms timeout — zero impact on search/trace latency. Output is captured to a string (instead of writing directly to stdout) to enable token counting without stdout hijacking.
MCP integration (
mcp/server.go)Stats are recorded for all MCP tool calls:
grepai_search,grepai_trace_callers,grepai_trace_callees,grepai_trace_graph. A newgrepai_statsMCP tool allows AI agents to query savings programmatically.Example output
Testing
Type of Change
How Has This Been Tested?
Test Configuration:
Checklist
golangci-lint runand fixed any issuesScreenshots (if applicable)
Additional Notes
config_test:
On Windows, creating symlinks requires elevated privileges or Developer
Mode. Skip the test gracefully on Windows; keep t.Fatalf on other platforms.