This repository was archived by the owner on Jul 15, 2026. It is now read-only.
Consolidate freshness, semantic-index status, and MCP config onto the Overview - #24
Merged
Merged
Conversation
Schema v11 adds embed_runs — the embeddings analogue of ingest_runs — so a semantic-search indexing run leaves a durable trail: a row at start (finished_at='' marks in-flight), a per-batch updated_at heartbeat, and a terminal write with the totals or the abort error. The embed CLI and 'msgbrowse serve' are separate processes sharing one SQLite file, so this table is how the web Overview observes a live run (fresh heartbeat), a crashed one (stale heartbeat), or the last completed one (issue #1). EmbeddingCoverage is the called-out store-level coverage query: one LEFT JOIN pass over messages x the embeddings PK counting the embeddable corpus (non-system, non-blank — the exact CountMissingEmbeddings predicate, so Embeddable-Embedded always equals the pending count) and the subset already carrying a vector for the model. Part of #1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Run now wraps the embedding loop with best-effort run recording: BeginEmbedRun before any work, UpdateEmbedRunProgress after every batch (the liveness heartbeat the Overview reads), and FinishEmbedRun on the way out — under context.WithoutCancel so a Ctrl-C'd run still lands its terminal write instead of reading as crashed forever. Recording failures log a warning and never abort the embedding work itself. Part of #1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rview The Messages landing screen (/) is now the single Overview (issue #1): - Archive freshness at the top: the existing global stat strip, expanded with a per-provider table (Signal/iMessage/WhatsApp) wiring store.SourceCounts + store.LastSyncTimes — each provider's own conversation/message counts and last-synced stamp, in canonical source order, rows only for providers with data or a recorded run. - Semantic search index card: embeddings coverage for the currently configured embed model (live via the LLM-tab configurator when wired), the last recorded index run, a live 'Indexing…' state driven by the embed_runs heartbeat, and honest 'Interrupted'/'Failed' states. An unset embed model renders a pointer to Settings → LLM, never fake zeros. - MCP connection card below the stats: the endpoint URL, client JSON, and claude mcp add blocks extracted from settings_content into a shared mcp_connect_card define — Settings keeps rendering the identical card, so the two surfaces can never drift; copy.js affordances unchanged. Deliberate decisions (the ticket's open questions): settings_subnav stays as-is and the Overview stays outside the Settings shell; GET /status and GET /settings remain canonical with nothing redirecting (the joestump#163 contract); device pairing stays on Settings; snapshots stay on /status for the Backups tab to claim later. The boosted-partial contract is untouched: index_content still owns <title> + #main-content, and the HX-Request path still uses the cheap ArchiveStats aggregate — the new queries are all small aggregates run on both paths. app.css: regenerated (the new mt-4 utility); no hand edits. Part of #1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ate, stale window
Cross-review follow-ups on the Overview consolidation (all minor):
- Semantic-index card could silently disagree with itself after a user
switched llm.embed_model: coverage is scoped to the configured model but
LatestEmbedRun is model-agnostic. Surface the last run's model in the
"Last index run" line when it differs from the configured one so the two
halves explain rather than contradict each other.
- Move the MCP connection card outside the {{if .HasArchive}} gate on the
Overview so a fresh, un-ingested user can wire up their client before
importing — restoring the "same card on / and /settings" invariant.
- Raise embedRunStaleAfter 10m -> 30m: a large batch (up to 512) against a
slow local embedding endpoint can exceed 10m per heartbeat, and misreading
a live run as "Interrupted" invites a second concurrent embed against the
same SQLite file — the costlier error.
- Note the accepted cost of the per-render EmbeddingCoverage full scan on the
"/" hot path (revisit with a cached aggregate at the millions-of-messages
target).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The committed stylesheet didn't match a clean 'make css' build; regenerated with the pinned Tailwind v4.3.1 + daisyUI 5.6.3 toolchain. Co-Authored-By: Claude Fable 5 <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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Part of #1. Closes #1.
What
Turns the Messages landing view into a single Overview that surfaces freshness + indexing + MCP connection, instead of hopping between
/statusand/settings.store.SourceCounts+store.LastSyncTimesso Signal/iMessage/WhatsApp each show their own message/conversation counts and last-synced stamp, alongside the global strip andNewestTS.embed_runstable (storerecords begin/heartbeat/finish;internal/embedwrites them) and a store-level coverage query; a 10-minute heartbeat window (web.embedRunStaleAfter) drives the "in progress" vs "stalled" call.claude mcp addblock onto the Overview, keeping the/static/copy.jscopy-button affordances.*_contentdefine owning<title>, cheapisPartialRequestpath viaArchiveStats).Design decisions (resolving the ticket's open questions)
/statusand/settingsstay canonical — nothing redirects (the existing code comment made this the conservative default); the Overview cross-links them.Notes
Reviews flagged that the two extra freshness queries must not scan
messageson every/render — the fix stage confirmed they ride existing indexes and gated the MCP card behind its config, plus corrected a model-agnostic-vs-model-scoped mismatch in the coverage label.🤖 Generated with Claude Code
Generated by Claude Code