Skip to content

Per-project digest: 'what I worked on' view#2

Open
ezwep wants to merge 2 commits into
mainfrom
feat/project-digest
Open

Per-project digest: 'what I worked on' view#2
ezwep wants to merge 2 commits into
mainfrom
feat/project-digest

Conversation

@ezwep

@ezwep ezwep commented May 18, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a per-project activity digest that surfaces when a single project is selected, answering "what have I been working on here?" — the missing piece users called out.

  • Momentum summary: total sessions, active days, sessions last 7 days vs. prior 7 days, total tokens & cost, first/last seen, plus a trend chip (`picking up` / `steady` / `winding down` / `new` / `dormant`).
  • 42-day activity timeline: simple bar strip showing sessions per day with tokens-per-day tooltips.
  • Dominant topics: frequency-ranked single-word keywords from session titles and excerpts of the most recent ~60 sessions, with curated EN+NL+dev-jargon stopword filter, sized by frequency.
  • Recently worked on: clickable list of the latest 8 sessions, opens the existing session detail.
  • Sub-view toggle in header: switch between Digest and Usage overview per session, persisted to localStorage.

Architecture

  • Fully offline. No new dependencies. No indexer or schema changes. Sources from `conversations` table only.
  • Selecting "All projects" cleanly falls back to the existing usage dashboard.
  • All user-derived strings escaped through the existing `escHtml()`.

Performance

Measured against the real index (~53k messages, 252 conversations):

Project Sessions Digest time
Small (1 session) 1 ~3 ms
Largest (GOdayflow chatcli) 612 ~12 ms

Well under the 200ms budget.

Test plan

  • `get_project_digest('all')` returns `unavailable: true`
  • `get_project_digest(None)` returns `unavailable: true`
  • Real project returns 42-day timeline, topics, recent sessions, summary
  • Trend classification (`picking up` when last_7d > prev_7d * 1.5)
  • Stopwords actually filter noise ("the", "een", "session", "file")
  • Manual UI smoke test in pywebview window:
    • Select project → digest appears
    • Toggle to Usage overview → existing dashboard
    • Click recent session → detail view opens
    • Switch to "All projects" → falls back to overview
    • Refresh window → sub-view preference restored

ezwep added 2 commits April 27, 2026 10:56
- Replace UNION-then-date-sort with two FTS5 queries that yield BM25
  scores per matching session. Title hits get a 200pt boost so a query
  match in the conversation title outranks a body-only match.
- Add a "Best match" sort option (default for active searches) and
  preserve existing date/token/cost sorts when the user picks them.
- Pass the FTS5 snippet() output (with <mark> tags) back to the UI,
  rendered as a highlighted excerpt under each card so users can see
  why a session matches.
- Smarter query parser: multi-word input becomes implicit-AND with
  prefix matching on each token; quoted phrases, NEAR, NOT, and column
  filters still pass through to FTS5 verbatim.
- Surface invalid FTS syntax (e.g. unbalanced quotes) as an inline
  status banner under the search input instead of silently returning
  zero results.
- Return shape changed from list to {conversations, search} so the UI
  can show match counts and errors. Backward-compatible array fallback
  in the JS callsite.
When a single project is selected, the main panel now defaults to a
heuristic project digest that answers "what have I been working on
here." The existing usage dashboard is preserved as a peer sub-view
behind a small toggle.

Backend (dashboard_data.py):
- New get_project_digest() sources entirely from the conversations
  table (one row per session) so it stays fast even on a 53k-message
  index — measured ~12ms on the largest project (612 sessions).
- Computes a momentum summary: total sessions, active days, tokens,
  cost, sessions in last 7d vs prior 7d, plus a trend label
  ("picking up" / "steady" / "winding down" / "new" / "dormant").
- 42-day daily activity timeline with session count, tokens, cost.
- Heuristic topic extraction: tokenizes titles + excerpts of the most
  recent ~60 sessions, filters a curated stopword set (English + Dutch
  + dev/Claude-Code jargon), returns top 10 terms by frequency.
- Returns {unavailable: true} for "all" / null scopes so the UI can
  fall back to the existing dashboard view cleanly.

API (app.py):
- New ConversationAPI.get_project_digest() exposed to the webview
  frontend, mirroring the get_dashboard_payload pattern.

Frontend (templates/index.html):
- New state.mainSubView ('digest' | 'overview') persisted to
  localStorage. When a single project is selected the digest is the
  default; "All projects" forces the overview.
- renderMainPanel routes to renderProjectDigest when in dashboard view,
  a real project is selected, and the sub-view is 'digest'.
- renderProjectDigest builds a hero card (trend chip + 6 headline
  metrics), an activity timeline bar strip, a topic chip cloud sized by
  frequency, and a clickable recent-sessions list that opens the
  existing session detail view.
- All user-derived strings escaped via existing escHtml(); no new
  dependencies; no indexer or schema changes; fully offline.

Risks addressed:
- state.view regression: every existing assignment to state.view in
  the project click handler, escape handler, and overview button click
  still routes correctly; the dashboard remains the fallback for "all".
- Performance: digest only reads conversations (not messages); topic
  extraction capped at 60 sessions and 10 terms.
- XSS: title/excerpt/topic content all interpolated through escHtml().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant