Commit Graph

676 Commits

Author SHA1 Message Date
bvandeusen 873e70c7ea feat(journal): add JournalView UI with /journal route + nav link
Restores a working browser surface for the journal feature, which was
left UI-less when Stage F of the original plan was deferred. JournalView
is a fresh write (not a rename of BriefingView) — drops the briefing-
specific weather panel, news cards, RSS reactions, article-discuss
button, and setup wizard, since none of those have journal-backend
equivalents.

What it does:
- Fetches /api/journal/today on mount; shows today's daily-prep card
  (rendered from msg_metadata.kind === 'daily_prep' sections)
- Day picker via /api/journal/days lets you switch to past days
- Refresh-prep button hits /api/journal/trigger-prep
- Center is the existing ChatPanel pinned to today's journal conversation
  (so the chat input + SSE + tool-call cards inherit unchanged)
- Right sidebar keeps the upcoming-events list (uses the generic
  /api/events endpoint, not a briefing-specific one)

Also:
- Replace the dead Briefing API client functions with Journal equivalents
  (getJournalConfig, saveJournalConfig, getJournalToday, getJournalDay,
  getJournalDays, triggerJournalPrep, list/update/deleteJournalMoment).
- Remove NewsView.vue — it was orphaned (no route, no nav) and depended
  on the deleted /api/briefing/* endpoints. If a standalone news surface
  is wanted later it'll need to be rebuilt against new endpoints.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 11:54:06 -04:00
bvandeusen 0c91ab026d docs: add FabledSword design system + Scribe iteration decisions
Captures the FabledSword baseline (verbatim from initial draft) plus the
Scribe-specific decisions made during the first iteration pass:

- Hybrid accent rule (accent reserved for brand moments + nav/cursor +
  tags/wikilinks/in-progress/focus rings; Moss/Bronze/Oxblood/Pewter
  for action buttons by default)
- Light mode warm parchment (specific hex values pinned)
- Status + priority palette extension table (status-paused added)
- Typography: Inter for body, doc scale verbatim, two weights
- Chat-bubble "Illuminated Transcript" pattern codified
- Voice and tone: adopt principles, defer formal audit
- Border philosophy: structural not decorative
- Iconography: Lucide as source, strict 16/24 scale, 1.5/1 stroke
- Warm gold accent dropped (dates → text-secondary, paused → Warning)

Doc lives at docs/design-system.md. Polish pass (applying the system to
existing UI) is a separate, deferred phase.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 10:51:38 -04:00
bvandeusen ce76a003f7 feat(journal): /api/journal/* routes blueprint + cosine helper unit tests
Endpoints:
- GET/PUT /api/journal/config — per-user journal config
- GET /api/journal/today — today's journal conversation, generates daily prep on demand
- GET /api/journal/day/<iso_date> — past day's journal
- GET /api/journal/days — list of dates with journal content
- POST /api/journal/trigger-prep — manual regeneration of prep
- GET /api/journal/moments — list/search moments with filters
- PATCH /api/journal/moments/<id> — edit content/tags/pinned + junctions
- DELETE /api/journal/moments/<id>

Blueprint registered in app.py.
tests/test_journal_search.py — cosine helper coverage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 22:40:56 -04:00
bvandeusen ac188c40a5 feat(journal): LLM tools (record_moment, search_journal) + system prompt wiring
- services/tools/journal.py — record_moment + search_journal tool handlers
- services/tools/_registry.py: add `journal` flag on ToolDef + tool() decorator
- get_tools_for_user(user_id, conversation_type='chat'|'journal') —
  exclude journal-only tools from chat sessions; exclude set_rag_scope
  from journal sessions
- services/tools/__init__.py: register the new journal module; drop the
  unused get_briefing_tools export
- services/llm.py build_context: short-circuit for journal conversations,
  using journal_pipeline.build_journal_system_prompt and skipping all
  notes-RAG injection (preserves the journal/notes isolation invariant)
- services/generation_task.py: pass conversation_type into get_tools_for_user

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 22:39:42 -04:00
bvandeusen d9ab538ef4 feat(journal): backend services (moments, search, prep, scheduler, pipeline)
- services/moments.py — CRUD with embedding sync + entity-link helpers
- services/journal_search.py — three-mode search (temporal / entity / semantic)
  with notes-RAG isolation; cosine-similarity helper unit-tested
- services/journal_prep.py — gathers tasks/events/weather/news/projects/
  recent-moments/open-threads into a structured prep block
- services/journal_scheduler.py — per-user APScheduler cron for daily prep,
  follows the BackgroundScheduler + threadsafe-async pattern from event_scheduler
- services/journal_pipeline.py — system prompt (persona + calibration rules)
  with last-48h ambient moments injection
- app.py: wire journal scheduler start/stop hooks
- routes/settings.py: re-add live-reschedule on timezone change (now via
  journal_scheduler.update_user_schedule)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 22:37:39 -04:00
bvandeusen 7602bf2293 feat(briefing): hard-cut tear-down
Backend:
- Delete briefing services (pipeline, scheduler, conversations, profile, tools)
- Delete routes/briefing.py + remove blueprint registration
- Move _get_temp_unit into services/weather.get_temp_unit (reads top-level temp_unit setting)
- Rename briefing_preferences.py → rss_filtering.py (functions are RSS-specific)
- Strip briefing scheduler hooks from app.py
- Strip briefing scheduler call from routes/settings.py
- Update test imports (test_rss_service, test_tz_helpers)

Frontend:
- Delete BriefingView, BriefingSetupWizard, BriefingToolStatusRow
- Strip /briefing route + nav links (AppHeader, KnowledgeView)
- Strip Settings → Briefing tab + state + functions + imports
- Strip briefing-intermediate handling from ChatMessage
- Hide /news route + nav links (NewsView depended on briefing endpoints; orphaned in tree)
- Drop unused useSettingsStore from AppHeader

The Android BriefingScreen lives in a separate repo and is not touched here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 22:33:37 -04:00
bvandeusen d352e9264b feat(models): Moment + MomentEmbedding + junctions; rename Conversation.briefing_date → day_date
Also rename services/tz.user_briefing_date → user_day_date with a backwards
compat alias (briefing modules using the old name will be deleted in the
upcoming briefing tear-down stage). Update services/chat.py to_dict to use
day_date.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 20:40:02 -04:00
bvandeusen 6752765e2b feat(db): migration 0041 — add moments + four junction tables (FK notes) + embeddings
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 20:38:37 -04:00
bvandeusen 0fe7141949 feat(db): migration 0040 — rename briefing_date to day_date, hard cut briefing data
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 20:35:37 -04:00
bvandeusen b20d6dec66 chore(scripts): make pre_commit_fable_mcp.sh location-independent
Derive REPO_ROOT from the script's own location instead of hardcoding
the absolute project path, so the hook keeps working if the project
directory is renamed or moved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 17:56:02 -04:00
bvandeusen e652dece9b refactor: rename Fabled Assistant to Fabled Scribe
Updates user-visible branding across frontend (PWA manifest, page title,
Settings, push fallback), backend (email templates and subjects, LLM
system prompt, CalDAV displayname, SMTP from-name default), README,
quickstart compose, and MCP server description.

Also updates the CI image path and quickstart image reference to
git.fabledsword.com/bvandeusen/fabledscribe in preparation for the
Forgejo repo rename. Internal Python package, env vars, and database
schema unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 16:28:25 -04:00
bvandeusen 96a44886ef Merge pull request 'feat(workspace): redesign project workspace with floating chat widget' (#42) from dev into main v26.04.22.1 2026-04-22 19:11:11 +00:00
bvandeusen f422d4158c style(workspace-notes): larger, more spacious note title
Title input bumps to 1.4rem with Fraunces serif (matches the
design language's heading treatment) and gains 0.9/1.1rem padding
on the title row for breathing room.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:52:58 -04:00
bvandeusen 70ec060b7a style(workspace-notes): move active-note indicator to right edge
Anchors it to the editor side rather than the tasks-panel side.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:43:59 -04:00
bvandeusen 3b41a45757 style(workspace-notes): drop border between toolbar and body
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 14:35:45 -04:00
bvandeusen 19e1ca505d style(workspace-notes): unify editor chrome, distinguish rail
- Drop border-bottom lines between header / title / tags / toolbar
  so they read as one continuous input surface.
- Add a single border-top above the editor body so the body's
  existing boundary stays clear.
- Notes rail gets --color-bg-card so it no longer visually merges
  with the tasks panel (both previously shared --color-surface).
  Dropped the rail's border-right since the tint now carries the
  division from the editor pane.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 13:30:17 -04:00
bvandeusen f75c40b417 refactor(workspace): match KnowledgeView mini-chat dock style
- Widget is now a bottom-anchored dock spanning the content width
  (max-width 1200px, rounded top corners, bg-secondary, upward shadow)
  instead of a floating corner box.
- Drop the closed state and ✕ button — widget is always present,
  matching KnowledgeView's pattern. Collapsed = input-only dock,
  expanded = full ChatPanel above the input.
- Grid ratio 1fr:2fr → 0.85fr:2.15fr so tasks get a touch less room
  and notes a touch more.
- Workspace note-rail (the notes picker column inside the editor)
  widens from 155px to 200px so note titles breathe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 12:53:02 -04:00
bvandeusen 649c0f124b feat(workspace): history dropdown on project chat widget
Clicking the ▾ button reveals conversations where
rag_project_id === projectId, most-recent first. Selecting one
repoints the widget (and the workspace_conv_{pid} storage key) to
that conversation without deleting the previously active one.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:10:54 -04:00
bvandeusen 6026c24450 refactor(workspace): two-column grid; widget drives tool-call refresh
WorkspaceView now renders tasks (1fr) on the left and notes (2fr) on
the right with the floating WorkspaceChatWidget layered on top. The
widget owns the SSE streamingToolCalls watcher and emits note-changed
and task-changed events; the view listens and reloads the affected
panel refs.

Dropped from the view:
- ChatPanel mount, empty-state quick chips, and Chat header toggle
- The conversation lifecycle + SSE watcher (moved into the widget)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:09:50 -04:00
bvandeusen ae5c61a179 feat(workspace): floating project chat widget
Modeled on KnowledgeView's mini-chat. Three states (closed handle,
collapsed input-only, expanded full panel). Takes over the project
conversation lifecycle from WorkspaceView (resume-or-create on mount,
delete-if-empty-and-new on unmount) and adds a restart action. Reuses
ChatPanel for expanded view and ChatInputBar for collapsed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:08:25 -04:00
bvandeusen 7657f48f1e Merge pull request 'feat: unified lookup tool, Wikipedia integration, weather & briefing UX' (#41) from dev into main v26.04.18.1 2026-04-18 03:33:57 +00:00
bvandeusen 61e62a6904 fix: serialize article fetches in lookup to avoid lxml double-free
trafilatura.extract dispatched via run_in_executor isn't safe to run
concurrently — two parallel calls can crash the process with a
libxml2-level double free. The top-level Wikipedia+SearXNG gather is
fine; only the inner per-article extraction needs to stay sequential,
matching the pre-parallelization behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 23:04:05 -04:00
bvandeusen 9a252c8dde feat: parallelize lookup (Wiki+SearXNG) and include Wikipedia thumbnails
Runs the Wikipedia summary and SearXNG search concurrently and returns
both when available, so current-event questions aren't masked by a
generic role article from Wikipedia. When the Wikipedia summary includes
a thumbnail, it is cached through the existing image pipeline and
surfaced as an embeddable markdown snippet alongside the extract.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 22:44:42 -04:00
bvandeusen 8db6b4d230 feat: add Wikipedia as research pipeline source alongside SearXNG
Runs wiki_search in parallel with SearXNG queries; Wikipedia results
(which already carry content via their extract field) are merged into
the source pool before outline generation, skipping a separate fetch
step. Also fixes a pre-existing F811 ruff violation in the test file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:59:35 -04:00
bvandeusen d5e6a8f6da refactor: update all search_web references to lookup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 21:57:46 -04:00
bvandeusen 06cd3493fd feat: replace search_web with unified lookup tool (Wikipedia + SearXNG fallback)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:56:31 -04:00
bvandeusen 6a8f0e9143 feat: add wikipedia service with summary lookup and search
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:54:44 -04:00
bvandeusen 6f8c2201ed docs: add unified lookup & Wikipedia implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 21:20:47 -04:00
bvandeusen ec49e24c8d docs: add unified lookup tool & Wikipedia integration spec
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 21:17:48 -04:00
bvandeusen cac62c6caf feat(briefing): add 2-week upcoming events list below weather card
Fetch and display the next 14 days of events in the briefing right column,
grouped by day with color dots, time, and location. Fills the empty space
below the weather card.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 17:14:20 -04:00
bvandeusen 619f069358 feat(weather): add refresh button and return card data from refresh endpoint
Add a refresh button (↻) to the weather section header in BriefingView so
users can manually re-fetch weather data (needed after deploying the hourly
precip changes to populate the cache). Update the existing POST
/api/briefing/weather/refresh endpoint to return full card data instead of
just location keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 16:40:57 -04:00
bvandeusen ddab0db781 feat(weather): add hourly precipitation summaries and peak timing to weather card
Fetch hourly precipitation probabilities from Open-Meteo alongside daily
forecasts. Generate human-readable precip summaries ("Rain likely 2–5 PM",
"Rain likely all day") for today and each forecast day. Display today's
summary as a styled callout and show peak precipitation hour in forecast rows.
Also fix briefing pipeline to parse all weather location rows (not just first).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 16:05:26 -04:00
bvandeusen 443b11f287 fix(tests): patch get_setting at source module, not lazy import site
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 15:15:01 -04:00
bvandeusen 3c9e473823 fix(tests): mock get_setting in calendar tools availability test
The rss_enabled check in _check_requires now calls get_setting, which
needs a database connection. Mock it in the test that exercises
get_tools_for_user.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 14:49:33 -04:00
bvandeusen 3ac32dc3bc feat: add rss_enabled user setting to toggle RSS functionality
RSS is now off by default. When disabled:
- Scheduler skips RSS feed sync during compilation slot
- Briefing pipeline skips RSS item gathering
- RSS LLM tools (get_rss_items, add_rss_feed) are hidden
- API routes return empty results for feeds/news
- Frontend hides News nav link, RSS Feeds and News Preferences in settings
- Briefing view hides news sidebar section

Toggle in Settings > Briefing > RSS / News.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 13:58:50 -04:00
bvandeusen 29ef17f4f3 fix(llm): frame RAG notes as reference material, remove RSS from chat context
Add framing preamble to auto-injected notes so the model treats them as
reference material rather than user input. Remove RSS semantic search
injection from all chat conversations — the discuss tool handles that need.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 08:17:10 -04:00
bvandeusen fc82f7a0cb Merge pull request 'Fix CSP for Google Fonts' (#40) from dev into main v26.04.17.1 2026-04-17 11:16:33 +00:00
bvandeusen b743754ec2 fix(csp): allow Google Fonts for Fraunces typeface
Add fonts.googleapis.com to style-src and fonts.gstatic.com to
font-src in Content-Security-Policy header.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:45:22 -04:00
bvandeusen c4ffe418b5 Merge pull request 'Fix CSP blocking Silero VAD WASM compilation' (#39) from dev into main v26.04.16.4 2026-04-17 00:23:59 +00:00
bvandeusen 6cf880506d fix(voice): allow WASM compilation in CSP for Silero VAD
Add 'wasm-unsafe-eval' to script-src and blob: to worker-src in
Content-Security-Policy header. Required by onnxruntime-web to compile
the Silero VAD ONNX model. Also surface VAD init errors as a toast
instead of silent console log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 20:10:29 -04:00
bvandeusen aca34e2dfb Merge pull request 'Release v26.04.16.3 — Silero VAD + Briefing layout' (#38) from dev into main v26.04.16.3 2026-04-16 23:37:04 +00:00
bvandeusen c07a0f0f7e fix(chat): remove input bar border across all chat views
Remove border-top from .input-wrapper in ChatPanel directly instead
of overriding per-view. Applies to chat, workspace, and briefing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 19:25:48 -04:00
bvandeusen 776e5edb68 fix(briefing): responsive sidebar, remove dividers, scale forecast icons
Switch sidebar from fixed px to proportional 35% so it resizes with
the viewport. Remove border between chat and input bar and between
weather and news. Use container query units for weather/forecast icons
so they scale with column width.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 19:10:49 -04:00
bvandeusen 8b0dd732f7 feat(briefing): tabbed weather locations, sticky weather, wider sidebar
Add location tabs when multiple weather sources configured. Weather
section stays pinned at top of sidebar while news scrolls independently.
Bump sidebar width from 420px to 620px max for better readability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 18:30:16 -04:00
bvandeusen f12d29563a fix(briefing): 2-column layout with table-based weather forecast
Collapse briefing from 3-column to 2-column grid (chat + sidebar).
Weather moves to top of news column, forecast uses an HTML table so
rows align cleanly. Drop verbose condition text from forecast days
(emoji already conveys it). Switch CI node_modules cache to npm
download cache to avoid tar size error from onnxruntime-web.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 18:10:46 -04:00
bvandeusen a4995606e5 chore(voice): remove amplitude-based silence detector (replaced by VAD)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 17:47:45 -04:00
bvandeusen 0a8a755909 feat(voice): replace silence detector with Silero VAD in ChatInputBar
Swaps useSilenceDetector for useVad. Adds no-speech guard: when the
user manually stops recording without VAD ever detecting speech, show
a toast and skip the Whisper round-trip instead of sending pure noise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 17:45:21 -04:00
bvandeusen 719de12a6c feat(voice): add useVad composable wrapping Silero VAD
Provides speech-start/speech-end detection via @ricky0123/vad-web.
Retains amplitude-based visual feedback for mic pulse animation but no
longer uses it for stop decisions. Exposes stopAndCheck() which fires
onNoSpeech when the user manually stops without VAD ever detecting
speech — avoids wasted Whisper round-trips on noise-only recordings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 17:43:17 -04:00
bvandeusen 72018aa389 feat(voice): add ONNX WASM idle preloader for Silero VAD
Configures vite-plugin-static-copy to serve @ricky0123/vad-web's ONNX model,
audio worklet, and onnxruntime-web WASM files from the site root.
useOnnxPreloader warms the model cache during page idle so the first mic
click is instant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 17:41:17 -04:00
bvandeusen 1e73ea04f1 chore(frontend): add @ricky0123/vad-web dependency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 13:37:37 -04:00