Daily Activity Summaries view#2
Open
paump wants to merge 26 commits into
Open
Conversation
10 TDD-shaped tasks covering the new summarizer module, scanner table, cli eager pass, dashboard endpoint, UI, and v0.3.0-launchmetrics.1 tag. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move `import time` to the top of the file with other module-level
imports, remove the two inline `import scanner, time` duplicates, and
fix the f-string in `_seed_jsonl_for_cell` to use `{i:02d}` so minute
values are always two digits (prevents malformed timestamps for i>=10).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Stub threading.Thread in both cmd_dashboard tests so the browser-open daemon thread never actually runs during test execution - Assert projects_dirs is passed correctly to run_eager_pass - Add docstring + assert progress format (1 / 3, no \\r) to the stderr-progress test - Add comment explaining the done % 5 == 0 magic number in cli.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Returns cached summaries for a given date and lazily summarizes any (date, cwd) cell with activity but no cached summary via summarize_cell. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ate HTTP path Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…CSS tokens Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the existing scan_meta _table_exists guard pattern. Protects the rare case where the dashboard is started against a usage.db that predates v0.3.0 without first running a scan. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude Code's per-project JSONL directories under ~/.claude/projects/ encode every "/", "." and whitespace in the cwd as "-". Our _encoded_dirname only replaced "/", so for any cwd containing dots (e.g. "/Users/pau.montero/...") or spaces (e.g. ".../AIpril retrospectives"), collect_prompts walked into a non-existent dir and returned no prompts. The dashboard then surfaced "Summary unavailable: no_prompts" for every cell. Add a regression test for the encoding and an end-to-end test that seeds a dotted-cwd dir and verifies collect_prompts finds it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
User-type JSONL records contain a lot of non-prompt text that Claude Code captures from the input stream: slash-command wrappers (<command-name>...), bash invocations and stdout/stderr blocks, local-command artefacts, task-notifications and system-reminders that land in user records, the [Request interrupted by user] marker, and the auto-context-continuation prelude. Inferring activities from this material wastes tokens and produces nonsense. Add a NOISE_PREFIXES tuple and skip any user prompt whose stripped text starts with one of those tags. Real prose still falls through. Verified against the live JSONL: collected prompts went from 4 KB of mixed garbage to 1.7 KB of legitimate user messages (real questions, design discussion, task hand-offs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Expanding a day was hanging on a single "Summarizing…" spinner for 2-5 minutes because /api/daily-summaries ran summarize_cell synchronously for every uncached (date, cwd) before sending the response — sequential 30-60 s claude -p calls add up fast. Split the API: /api/daily-summaries now returns the cell list instantly with pending=true on uncached cells. The new /api/cell-summary?date=&cwd= endpoint runs summarize_cell for one cell. The frontend fires these in parallel and replaces each pending block as its summary arrives, so summaries stream in instead of all or nothing. Side benefit: the user sees structure (which projects worked that day) immediately, even before any summary completes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Claude Code CLI returns an empty "result" field when invoked with
--json-schema (verified against the live CLI: result="", stop_reason
="end_turn", output_tokens=1317), which made every lazy summary fail
with parse_error.
Switch to instructing JSON output via the system prompt and parse the
result string ourselves, stripping optional ``` fences and falling
back to the first balanced {...} span. Also wrap the collected prompts
in a <prompts> block so Haiku treats them as data instead of
answering the last user message.
New error code "empty_result" to distinguish a CLI that returned no
content from a malformed payload.
Verified end-to-end: a 2.3 KB real prompt set now yields four
coherent activity bullets in ~25 s.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
renderDailyList rebuilt the entire <details> list on every 30 s auto-refresh, which collapsed any expanded day and abandoned the in-flight /api/cell-summary requests for its cells. The visible result was "day closes itself after a while" plus stale "No activities inferred" labels for cells whose summarization never got to land. Make the renderer idempotent: update <summary> metadata on existing rows in place, only build fresh DOM for genuinely new dates, and remove rows for dates that fell out of the range. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The daily list header used session.last_date attribution, which credits an entire session to whatever day it ended on. Cells in the expanded view use per-turn timestamps. For long-running sessions that span multiple days, this made the day header much higher than the sum of cells underneath — the user saw \$120.92 in the header against \$26.32 of cells. Switch the header cost to use the existing turn-grouped daily_by_model data so it matches the per-cell sum exactly. Project count keeps using sessions (it's a per-day count of distinct projects, not a cost figure). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per user feedback: "if you are able to click a date and it works, this is enough." The eager pass added a 30-60 s blocking step at dashboard startup that pre-summarized the top-20% cost cells, then duplicated work the lazy on-click endpoint already does. Worse, on slower days users sat staring at "Generating activity summaries…" before the dashboard even came up. Lazy summarization is fast enough on its own: clicking a day fans out one /api/cell-summary request per project in parallel and the sha256 cache makes re-clicks instant. Drop the eager machinery, the SUMMARY_MAX_CELLS env var, the rank_cells_by_cost ranking, and the ★ "pre-summarized" UI marker that was only meaningful when both passes coexisted. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Recent Sessions used to show only the top 20 rows of the filtered list with no way to drill in. Two changes here: 1. Pagination — render the full filtered list 50 rows per page with a prev/next pager. Page resets to 1 whenever the filter, sort, or auto-refresh changes the underlying list. 2. Click-to-expand — clicking a row inserts a detail row underneath showing 2-5 activity bullets summarizing what the user actually worked on in that session. Bullets come from the local claude CLI (Haiku via SUMMARY_MODEL) running over the session's user prompts, cached in a new session_summaries table keyed by session_id. Reuses summarizer.py's prompt extraction, noise filter, run_claude subprocess and prompt_hash cache logic — only the persistence shape changes (one row per session_id instead of per (date, cwd)). Locates the JSONL via cwd_hint when known, falls back to globbing every project dir for <session_id>.jsonl. Path-traversal guard on /api/session-summary?id= rejects ids containing '/', '..' or whitespace before the value reaches the filesystem. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
claudeCLI running Haiku and are cached in a newdaily_summariestable keyed by sha256 of the day's prompts./api/cell-summaryrequest per project, so summaries stream in instead of blocking on a sequential per-cell loop.Notable design choices
--output-format jsonwithout--json-schema— the schema flag returned an emptyresultfield on the current Claude Code CLI. We parse the JSON object out of the freeformresultstring instead.New surface
summarizer.py(prompt collection, noise filter, claude subprocess, cache write)daily_summariestable (auto-created)/api/daily-summaries?date=…(instant, marks pending cells),/api/cell-summary?date=&cwd=(per-cell)SUMMARY_MODEL(default:haiku)claudeCLI on PATH; absence shows a per-cell notice instead of breaking the dashboardTest plan
python3 -m pytest tests/ -q— 136 tests passpython3 cli.py dashboard— dashboard comes up immediately (no eager-pass wall)mv $(which claude) /tmp/and reload — dashboard still renders, cells show a "claude CLI required" notice instead of crashing🤖 Generated with Claude Code