feat: add AI-powered Insights with multi-agent generation - #16
Conversation
Add a summaries system that generates markdown summaries of daily agent activity using the Claude CLI. Summaries are append-only and stored in SQLite, supporting both daily_activity and agent_analysis types with optional per-project scoping. Backend: - Schema: summaries table with type/date/project/agent/model/prompt/content - DB layer: InsertSummary, ListSummaries, GetSummary, DeleteSummary - Summary package: prompt builder (queries sessions, assembles context) and generator (invokes `claude -p` via exec) - Server: GET/POST endpoints for list, get, and SSE-streamed generation Frontend: - New #/summaries route with nav button in header - SummariesPage: toolbar (date/type/project/prompt), summary list, markdown viewer - Store with load/generate/cancel state management - SSE client for streaming generation progress Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add multi-agent invocation for summary generation alongside Claude. Each agent uses its native CLI with JSONL stream parsing: - Codex: `codex exec --json --full-auto` with agent_message items - Gemini: `gemini --output-format stream-json` with result events - Claude: `claude -p --output-format stream-json` with result events Includes agent selector in the UI, server-side validation with default to "claude", and stream parser unit tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix stale filter race in generate(): capture filter snapshot at start and check on completion before prepending result - Add 10-minute context.WithTimeout for summary generation - Validate non-empty content before saving summary to DB - Flush TextDecoder on EOF in both SSE readers in client.ts - Add error event handling in parseStreamJSON for stream errors - Add tests for stream error events and malformed JSON resilience Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change needsRebuild to return (bool, error) so probe failures propagate instead of silently proceeding with stale schema - Add TestFindPruneCandidatesExcludesParents to verify parent sessions are excluded from prune candidates - Remove "no such file" from TestMigrationRace allowed errors since the DB is pre-created in test setup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Only treat os.IsNotExist as "no DB exists" in needsRebuild; propagate permission/IO errors instead of masking them - Add TestOpenProbeErrorPropagates for unreadable DB path - Add summaries store test for filter-mismatch during generation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split TestOpenProbeErrorPropagates into two subtests: - StatPermissionError: removes execute on parent dir to trigger os.Stat EACCES (tests the non-ENOENT stat branch) - ProbeReadError: removes read on file for SQLite probe failure Both skip when running as root via os.Geteuid check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Skip TestOpenProbeErrorPropagates on Windows where chmod semantics don't enforce access denial - Assert errors.Is(err, fs.ErrPermission) in StatPermissionError subtest for precise error class validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use --sandbox read-only for codex exec instead of --full-auto - Drain stdout pipe before cmd.Wait to prevent hangs on parse errors - Sanitize SSE error messages to avoid leaking internal paths/stderr - Replace _global magic string with GlobalOnly bool in SummaryFilter - Fix truncateString to use rune slice for safe multibyte truncation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SummariesPage was nested inside ThreeColumnLayout, causing a double-sidebar (session list + summary list). Move it outside the layout so it renders full-width with its own internal two-column layout. Use explicit viewport height calculation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single-generation model with concurrent task support. Each generate() call creates an independent task with its own spinner, phase tracking, cancel button, and error state in the sidebar. Completed insights auto-prepend to the list and auto-select for viewing. - Rename summaries store/page/route to insights throughout - Add InsightTask interface with clientId-keyed Map of handles - Support cancelTask(id), dismissTask(id), cancelAll() - Show generating tasks with pulse animation and spinner dots - Show errored tasks with dismiss button - Content header with type badge, date, project, agent, time Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Redesign the Insights page with refined visual treatment: Sidebar: - Compact 2x2 filter grid replacing single toolbar row - Collapsible prompt textarea via toggle button - Sticky "Active" section header with blinking live dot - Shimmer bar animation on generating tasks (replaces pulse) - Dismiss buttons hidden until hover for cleaner rows - Error tasks get tinted background via color-mix Content: - Reading area with bg-primary background for contrast - Pill-shaped type badges in content header - Formatted date (e.g. "Mon, Jan 15") instead of raw ISO - Model name in mono font, time right-aligned - Max-width 720px on markdown body for readability - Styled blockquotes with blue left border and tinted bg - Table, hr, strong, and link styles for markdown - Orbit animation for generating empty state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename the database table, Go packages, server handlers, API routes, frontend types, and store references from summaries/Summary to insights/Insight. The old summaries table is orphaned. - internal/summary → internal/insight - internal/db: Summary → Insight, SummaryFilter → InsightFilter - internal/server: /api/v1/summaries → /api/v1/insights - frontend: Summary → Insight, InsightType, InsightsResponse - Store: summaries → items, selectedSummary → selectedItem Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the agent label out of the second-line metadata and into a right-aligned mono-font label on each insight row. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stop filtering the sidebar list by insight type so daily activity and agent analysis insights are visible together. The type selector now only affects which type gets generated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the conditional Dashboard button with an always-visible Sessions nav button. Both Sessions and Insights buttons highlight based on the current route, so navigation works from either page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use generatingCount for Active header/Stop all instead of tasks.length - Make task dismiss/cancel buttons accessible via :focus-visible and visible on touch devices - Add overflow handling to .row-agent - Switch viewport height from 100vh to 100dvh - Sessions nav button deselects active session before navigating - Sanitize BuildPrompt error in SSE response Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename Active section to Tasks with count matching tasks.length so the section header is consistent with its contents. Keep live-dot and Stop all gated on generatingCount. Add 100vh fallback before 100dvh for browsers without dvh support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show a compact "Sessions / {project}" breadcrumb at the top of
the content area when viewing a session. Clicking "Sessions"
deselects and returns to the dashboard.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Switch primary font to Inter for crisper UI typography. Adjust color tokens for refined borders and shadows in both themes. Polish header, sidebar, breadcrumb, status bar, and insights page with tighter spacing, better letter-spacing, and subtle depth cues (active nav tint, generate button shadow). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add DELETE /api/v1/insights/{id} endpoint backed by the
existing DB.DeleteInsight method. Add deleteInsight API
client function, store deleteItem method, and a trash
button in the insight content header. Includes server
and store tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display the session agent as a colored badge (blue for claude, green for codex) and the session start date/time on the right side of the breadcrumb bar when viewing a session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Assign return values to blank identifiers to satisfy golangci-lint errcheck for the stdout drain calls in codex/gemini generators. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
roborev: Combined Review (
|
- Fix .breadcrumb-current ellipsis with flex: 1; min-width: 0 - Wrap badge+time in .breadcrumb-meta right-aligned container - Add default background on .agent-badge for unknown agents - Load Inter as variable font (wght@400..700) for 450/650 weights - Treat 404 in deleteItem as successful local removal - Add store tests: setAgent, cancelAll, load error/stale handling, deleteItem 404 reconciliation - Add API client tests: deleteInsight, listInsights/getInsight query serialization, generateInsight SSE parsing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Include DELETE in Access-Control-Allow-Methods header so cross-origin preflight succeeds for insight deletion - Add test verifying all HTTP methods in CORS header - Add .roborev.toml with threat model documenting that this is a localhost-only tool (no auth, rate limiting, or input size limits needed) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ApiError class with status field to client.ts. deleteItem now
checks e.status === 404 instead of e.message.includes("404").
Updated tests to assert on ApiError type and status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
roborev: Combined Review (
|
Replace single `date` column with `date_from` and `date_to` in the insights table to support analyzing date ranges (e.g., a week) in addition to single days. The list endpoint no longer filters by date, returning all insights reverse-chronologically. The UI shows two date inputs with quick presets (Today, 7 days, 30 days), and each insight row displays its analyzed date range. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The type selector is now on its own row with three modes: - Daily Activity: single date input (default) - Date Range Activity: from/to inputs with 7-day and 30-day presets - Agent Analysis: single date input The presets and range inputs only appear when Date Range Activity is selected. Single-date modes keep dateFrom and dateTo in sync. List rows and content header labels reflect the actual date range of each insight (Daily vs Range vs Analysis). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ApiError message falls back to "API <status>" when body is empty, preventing blank error text in UI callers - Add fetchJSON error path test covering ApiError instanceof and status, plus empty-body fallback - Cap ListInsights at 500 rows and add created_at DESC index to prevent unbounded queries as data grows - No-sessions prompt text now says "date range" when DateFrom != DateTo - Add multi-day range tests: prompt "Date Range" header, DB round-trip with distinct date_from/date_to values Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
uiMode is now a $derived value that infers the correct mode from insights.type and dateFrom/dateTo, with modeOverride for explicit user selection. This prevents stale range submissions when the UI shows single-date mode but the store still holds a range from prior interaction. Add store-level tests verifying date sync on mode switch and that generate() sends correct date_from/date_to for both single-day and range configurations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Display the date (or date range) being analyzed next to the type label in in-progress and errored task items, so users can see which date each generation targets without waiting for completion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove modeOverride entirely — deriveMode() already infers the correct UI mode from store state (type + dateFrom/dateTo), and handleModeChange updates the store immediately. The override was redundant and could prevent the UI from reflecting later store changes. Add test verifying ListInsights caps at 500 rows with newest-first ordering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the user selects Date Range Activity while dateFrom === dateTo, expand dateTo by 6 days so the derived uiMode switches to range_activity and the range controls appear. Without this, the dropdown selection had no effect and snapped back immediately. Tighten ListInsights cap test to assert exact boundary IDs (newest first, two oldest excluded) rather than a weak ordering check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
roborev: Combined Review (
|
roborev: Combined Review (
|
## Summary - Restores Copilot as a valid insight generation agent (removed in 8f90380 / 455587a due to sandboxing concerns) - Adds `generateCopilot` back with `--silent --no-custom-instructions --no-ask-user --disable-builtin-mcps` flags - Updates frontend agent picker and TypeScript types to include Copilot - Documents the sandboxing caveat in `.roborev.toml` review guidelines (guideline #16) Addresses #35 — Copilot was unintentionally dropped from the insights agent list during an overly cautious review. The sandboxing difference (`--disable-builtin-mcps` vs full no-tools modes) is real but acceptable: agentsview operates on the user's own session data under the same trust model as running agents on codebases. ## Test plan - [x] `TestValidAgents` includes copilot - [x] `TestGenerateCopilot_CLIFlags` verifies correct CLI invocation - [x] `TestGenerateCopilot_EmptyResult` verifies error on empty output - [x] `TestGenerateCopilot_PreservesBlankLines` verifies multi-paragraph output - [x] All existing insight tests still pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- **Insights feature** for AI-generated analysis of agent sessions,
supporting Claude, Codex, and Gemini as generation backends
- Full-stack: `insights` SQLite table with FTS5, Go HTTP handlers
(`GET/DELETE /api/v1/insights/{id}`, `POST /api/v1/insights/generate`
with SSE streaming), prompt builder with session context, and
multi-agent CLI dispatch
- **Date range analysis**: insights can cover a single day or a date
range (e.g., a week). DB schema uses `date_from`/`date_to` columns. The
generate endpoint validates both fields and supports `date_to >=
date_from`
- **Mode-driven UI**: type selector with three modes -- Daily Activity
(single date), Date Range Activity (from/to inputs with 7-day and 30-day
presets), and Agent Analysis (single date). Mode is derived reactively
from store state
- Svelte 5 Insights page with sidebar controls (type, date, project,
agent), concurrent generation tasks with live status spinners, date
display on in-progress tasks, and markdown content viewer with delete
support
- **Structured API errors**: `ApiError` class with `status` field for
programmatic error handling; empty response bodies fall back to `"API
<status>"` message
- **ListInsights capped at 500 rows** with `created_at DESC` index to
prevent unbounded queries
- `internal/insight` package: prompt construction from session data with
date-aware text ("Date" vs "Date Range"), streaming response parsing for
Claude/Codex/Gemini CLI output
- **Session breadcrumb bar** showing project name, agent badge
(color-coded), and session start time
- **Header navigation** with always-visible Sessions/Insights buttons
and active state highlighting
- Design polish: Inter font, refined color tokens for light/dark themes,
tighter typography and spacing
## Test plan
- [x] `go test -tags fts5 ./...` -- all Go tests pass (insights CRUD,
filters, 500-row cap, date range round-trip, prompt builder with
single/range dates, server handler validation)
- [x] `npx vitest run` -- all 360 frontend tests pass (insights store,
date sync, mode switching, generate payloads, ApiError handling with
empty-body fallback)
- [x] `npx tsc --noEmit` -- no type errors
- [x] `go vet ./...` -- clean
- [ ] Manual: generate a Daily Activity insight, verify single date in
list and content header
- [ ] Manual: switch to Date Range Activity, verify from/to inputs and
presets appear, generate and verify range displays
- [ ] Manual: verify all insights appear in the list regardless of
selected generation dates
- [ ] Manual: verify in-progress task items show the date being analyzed
- [ ] Manual: delete an insight, verify removal from list and content
area
Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
## Summary - Restores Copilot as a valid insight generation agent (removed in 8f90380 / 455587a due to sandboxing concerns) - Adds `generateCopilot` back with `--silent --no-custom-instructions --no-ask-user --disable-builtin-mcps` flags - Updates frontend agent picker and TypeScript types to include Copilot - Documents the sandboxing caveat in `.roborev.toml` review guidelines (guideline #16) Addresses #35 — Copilot was unintentionally dropped from the insights agent list during an overly cautious review. The sandboxing difference (`--disable-builtin-mcps` vs full no-tools modes) is real but acceptable: agentsview operates on the user's own session data under the same trust model as running agents on codebases. ## Test plan - [x] `TestValidAgents` includes copilot - [x] `TestGenerateCopilot_CLIFlags` verifies correct CLI invocation - [x] `TestGenerateCopilot_EmptyResult` verifies error on empty output - [x] `TestGenerateCopilot_PreservesBlankLines` verifies multi-paragraph output - [x] All existing insight tests still pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
insightsSQLite table with FTS5, Go HTTP handlers (GET/DELETE /api/v1/insights/{id},POST /api/v1/insights/generatewith SSE streaming), prompt builder with session context, and multi-agent CLI dispatchdate_from/date_tocolumns. The generate endpoint validates both fields and supportsdate_to >= date_fromApiErrorclass withstatusfield for programmatic error handling; empty response bodies fall back to"API <status>"messagecreated_at DESCindex to prevent unbounded queriesinternal/insightpackage: prompt construction from session data with date-aware text ("Date" vs "Date Range"), streaming response parsing for Claude/Codex/Gemini CLI outputTest plan
go test -tags fts5 ./...-- all Go tests pass (insights CRUD, filters, 500-row cap, date range round-trip, prompt builder with single/range dates, server handler validation)npx vitest run-- all 360 frontend tests pass (insights store, date sync, mode switching, generate payloads, ApiError handling with empty-body fallback)npx tsc --noEmit-- no type errorsgo vet ./...-- cleanGenerated with Claude Code