-
v26.06.03
Stablereleased this
2026-06-03 12:51:04 -04:00 | 77 commits to main since this releaseFirst release under the no-suffix CalVer scheme (rule 47). Covers everything merged to
mainsince v26.06.01.2.Features
- Stored Processes — reusable saved prompts (
note_type=process) with create/list/get/update +resolve_process; Knowledge-view editor (PR #55). - Dashboard — new
/dashboardlanding ("what to work on") with/redirect; Knowledge becomes the Browse surface (PR #55). - MCP
_INSTRUCTIONShardening — agents now drive task lifecycle (in_progress → log → done + landing dev-logs), keep a Scribe-rules pointer in host memory when a project subscribes to a rulebook, and proactively bootstrap project context at session start (PR #56).
Changes
update_taskgainsmilestone_id=-1(andproject_id=-1) to CLEAR an FK;0still leaves unchanged (PR #56).- CI now gates + builds
mainas well asdev;mainpublishes the immutable:<sha>image,:latest+:<version>are release-only (PRs #56–#57).
🤖 Generated with Claude Code
Downloads
- Stored Processes — reusable saved prompts (
-
released this
2026-06-01 08:11:45 -04:00 | 109 commits to main since this releaseRules subsystem matures from "additive cross-project rulebooks only" into a full first-class system: always-on rulebooks, project-scoped rules, an active-project handshake, and per-project suppression of inherited rules. Two PRs since v26.06.01.1.
PR #53 — Rules consolidation (4 slices)
Problem. Rules in Scribe were pull-only; CLAUDE.md and
~/.claude/.../memory/feedback_*.mdwere session-start auto-loaded. The MCP prompt never insisted that Claude fetch Scribe rules eagerly or codify new rules in Scribe rather than the competing stores. Result: Scribe rules silently lost.-
S1 + S2 —
always_onrulebook flag (commit658348f)- Migration 0058:
rulebooks.always_onboolean. FabledSword family rulebook seededalways_on=trueat migrate-time. - New MCP tool
list_always_on_rules()returns the union of standing rules for the user in one round-trip, no active-project needed. _INSTRUCTIONSrewritten: at session start, calllist_always_on_rules; treat as binding. Rules codified in Scribe viacreate_rule, never in CLAUDE.md or feedback files. Those stores are now scoped to user-facts and codebase onboarding respectively.- Frontend: badge on always-on rulebooks in
RulebookListPane; toggle inRulebookDetailPaneheader.
- Migration 0058:
-
S3 — Project-scoped rules (commit
43a860c)- Migration 0059:
rules.project_id(nullable FK, CASCADE),rules.topic_idmade nullable, CHECKck_rule_topic_xor_projectenforces exactly-one. - New MCP tool
create_project_rule(project_id, statement, title?, why?, how_to_apply?)— no rulebook ceremony for project-only rules. get_applicable_rulesadds aproject_rulesfield surfaced throughget_project,get_task(plan),start_planning.- Trash cascade: deleting a project soft-deletes its project-scoped rules along with the rest.
- REST:
POST /api/projects/<id>/rules; frontend Rules-tab gains a "Project rules" section with inline create form.
- Migration 0059:
-
S4 —
enter_projecthandshake (commitc546921)- New MCP tool
enter_project(project_id)composesget_project+get_applicable_rules+ milestone-summary + open-tasks + recent-notes into one round-trip. Intended for once-per-session use when work is project-scoped. _INSTRUCTIONSdirects Claude to call it before any project-scoped mutation.- No schema change; pure composition over existing services.
- New MCP tool
PR #54 — Project rule + topic suppressions (commit
7861607)Lets a project mute individual rules or whole topics from rulebooks it subscribes to, without unsubscribing the rulebook. Use case: subscribe to a broad rulebook (e.g. a future "FabledSword design system") but opt out of one or two rules — or a whole topic — that doesn't apply to a non-frontend project.
- Schema (migration 0060): two new pure m2m association tables —
project_rule_suppressionsandproject_topic_suppressions. PKs on both columns; FKs CASCADE. Nodeleted_at— pure associations, hard-deleted on project trash. - MCP tools (4):
suppress_rule_for_project,unsuppress_rule_for_project,suppress_topic_for_project,unsuppress_topic_for_project. All idempotent; verify project + rule/topic ownership. Project-scoped rules (Rule.project_id) are deliberately not suppressible — delete them instead. - REST:
POST/DELETE /api/projects/<pid>/suppressions/{rules,topics}/<id>. - Service projection:
get_applicable_rulesruns two extra queries and emitssuppressed_rules+suppressed_topicsas detail objects (id + title + rulebook context, not bare IDs — so the UI doesn't need a follow-up lookup). The mainruleslist is filtered SQL-side sotruncatedreflects post-suppression count. Rules now carrytopic_id+rulebook_idcolumns for the UI affordance. - Propagation:
suppressed_rulesandsuppressed_topicssurface throughget_project,enter_project,get_task(plan), andstart_planning— Claude sees what's muted from any standard handshake. - Frontend: "× skip" affordance reveals on hover for each rule row and each topic header in
ProjectRulesTab.vue; collapsed "Suppressed (N)" section at the bottom with per-item "↻ re-enable" buttons.groupByRulebookAndTopicrefactored to id-bearing structs. - Trash cascade: project deletion hard-deletes the project's suppression rows so a later restore starts fresh.
Migrations
- 0058 —
rulebooks.always_onboolean, default false; seeds FabledSword family to true. - 0059 —
rules.project_id(FK CASCADE),rules.topic_idnullable, CHECKck_rule_topic_xor_project. Down-migration requires migrating/deleting project-scoped rules first. - 0060 —
project_rule_suppressionsandproject_topic_suppressionsassociation tables.
All three run automatically on first boot.
Verification
- CI green on
c546921(S4 — after rebuild; original run flaked on npm-cache action),43a860c(S3),658348f(S1+S2), and7861607(suppressions). - Migrations 0058/0059/0060 applied cleanly to the dev environment; operator confirmed the suppression UI and MCP tools work end-to-end on dev (
migration in dev worked, 2026-06-01). - Tests cover:
list_always_on_rules,update_rulebook(always_on=…),create_project_rule(required-fields + title-derivation + explicit-title),enter_projectcomposed shape + 404,get_applicable_ruleswith project_rules + suppressed_rules + suppressed_topics, project-cascade trash hitting 7 tables (was 4 before S3, 5 after S3, 7 with this release).
Deploy notes
- Three migrations run automatically on container start.
- After deploy, MCP reconnects pick up the new
_INSTRUCTIONS; on the next project-scoped turn Claude should calllist_always_on_rulesandenter_project. Eyeball the tool-call transcript on first use. - No content migration: rule-shaped entries in CLAUDE.md and feedback memory files stay where they are. The prompt reroutes NEW rules to Scribe going forward.
What this release does NOT do
- No supersede semantics — a project rule can't yet replace a rulebook rule for one project (only mute it). Pure suppression covers the stated use case; replacement can land later.
- No write-scope enforcement on bearer tokens — mutating tools still ignore the read/write scope on
api_keys. M1 work, tracked separately. - No share-aware filtering on
list_trash/restore/purge— same M1 carve-out.
Downloads
-
-
released this
2026-06-01 00:13:58 -04:00 | 115 commits to main since this releaseSmall follow-up release on top of v26.05.30.1. Two commits, docs/prompt only — no schema, no behavior changes to running services.
MCP plan-instruction tightening
The Plans paragraph in the MCP server's
_INSTRUCTIONSpreviously ended with a quiet footer ("not in local .md files") that lost to the much louder superpowers brainstorming / writing-plans skill flow, whose terminal steps save todocs/superpowers/specs/*.mdanddocs/superpowers/plans/*.md. Reordered sostart_planningis named as the FIRST action when beginning non-trivial work, with an explicit override of those.mdpaths and coverage extended to specs as well as plans (matches rulebook rule 27).Effect: when Claude reconnects after the new image deploys, it will reach for
start_planningbefore any markdown plan file by default.Flutter companion-app docs removed
The Flutter app no longer adds value over web/PWA access. In-repo surface stripped:
- deleted
docs/android-app.md - dropped Android App row from README docs table and from the README feature paragraph
- dropped the two Flutter-related roadmap bullets from
docs/features.md - removed the "Flutter app port" subsection from
docs/design-system.md
The standalone
fabled_apprepo is untouched here; archival of that repo is a separate operation on that repo.Deploy notes
No migration. No data changes. Pull the new
:latestimage; restart. Done.Verification
CI green on commit
fd20b67(typecheck / lint / tests / image build all ✅) before merge.Downloads
- deleted
-
released this
2026-05-29 22:51:28 -04:00 | 118 commits to main since this release118 commits since v26.05.13.1. Headline: the MCP-first pivot lands in production, and three new feature arcs land on top of it.
MCP-first pivot (Phases 7-10)
Scribe is now a pure data store. Claude via the in-app
/mcpendpoint is the only LLM. ~30,000 lines deleted across backend, frontend, and infrastructure.- New endpoint —
/mcpmounted alongside/api/*via FastMCP's streamable-HTTP transport. ASGI middleware authenticates via bearer tokens from the existingapi_keystable; rejects with 401 before FastMCP sees the request. Per-requestuser_idContextVar for tool handlers. - 34 MCP tools covering notes, tasks, projects, milestones, events, typed entities (person/place/list), search.
- Embeddings: Ollama → fastembed. In-process ONNX (
BAAI/bge-small-en-v1.5, 384d). First boot downloads the model to/data/fastembed-cacheonce. Migration 0052 cleared the existing 768d note_embeddings; startup re-embeds existing notes. - Phase 7 — frontend strip: removed
/chat,/journal,/workspace/:projectId, voice overlay, the chat-style home view. Surfaces that survived:/knowledge,/notes,/tasks,/projects,/calendar,/graph,/settings,/rules,/trash. - Phase 8 — backend deletion:
/api/chat/*,/api/journal/*,/api/voice/*,/api/push/*,/api/quick-capture,/api/fable-mcp/*and their backing services. The standalonefable-mcpstdio wheel removed. - Phase 9 (migration 0053): dropped
conversations,messages,generation_tool_log,moments+ junction tables,moment_embeddings,pending_curator_actions,push_subscriptions,weather_cache,rss_item_embeddings. - Phase 10 (migration 0054): dropped
image_cache; removed Ollama service config and frontend orphans. - Rebrand: "Scribe" user-facing;
fabledassistantinternal package name kept stable. - Settings → MCP Access tab: create write or read-only tokens (
fmcp_<32-byte-base64url>format), shown once, sent asAuthorization: Bearer <token>. Configurable MCP server name + scope.
Rulebook system (May 2026 milestone)
Cross-project standards: Rulebook → Topic → Rule, sibling to Project, with project subscriptions.
- Migration 0055 —
rulebooks,rulebook_topics,rules,project_rulebook_subscriptions. Each rule is astatement + why + how_to_applytriple. - 16 MCP tools for rulebook/topic/rule CRUD plus subscribe/unsubscribe.
get_project(id)returnsapplicable_rules+subscribed_rulebooks(capped at 50). /rulesthree-pane UI (rulebooks → topics → rules) with rule editor; project Rules tab grouped by rulebook → topic.- Seeded: the external FabledRulebook (12 topic .md files) imported into the "FabledSword family" rulebook — 12 topics, 43 rules. Fabled Assistant project subscribed.
Plans-as-tasks (May 2026 milestone)
Plans are first-class without a new entity: a Task with
task_kind="plan".- Migration 0056 — additive
notes.task_kindcolumn (work|plan, defaultwork, CHECK-constrained). - MCP:
start_planning(project_id, title)seeds a plan template + returns applicable_rules.get_tasksurfacesapplicable_rulesfor plan-tasks only. - UI: "Start planning" button on
/projects/:id; Applicable Rules panel in the task editor; Knowledge view's Plans facet + plan badge. - Rulebook hook: rule 27 reframed ("Planning artifacts live in Scribe, never in git"); ritual rule 45 added ("Build plans via start_planning, not .md") — the rulebook itself points planning at Scribe.
Soft-delete / Trash / Retention (May 2026 milestone)
Deletes become recoverable.
- Migration 0057 —
deleted_at TIMESTAMPTZ NULL+deleted_batch_id TEXT NULL(+ix_<t>_deleted_at) on 7 tables (notes,events,projects,milestones,rulebooks,rulebook_topics,rules).SoftDeleteMixininmodels/base.py. - Cascade: project → milestones + tasks/notes; rulebook → topics → rules; restore brings the whole batch back together (reverses the prior FK SET-NULL behavior so a restored project comes back with its children).
- MCP surface: existing
delete_*flipped to soft (return{deleted_batch_id, message}); addeddelete_task,delete_project,delete_milestone(closes the CRUD-asymmetry gap); addedlist_trash,restore,purge_trash(confirmed-gated hard delete). - REST:
/api/trash(GET list, POST/<batch>/restore, DELETE/<batch>for purge). All entity DELETE handlers flipped to calltrash.delete. - Retention:
trash_retention_dayssetting (default 90,0= keep forever). Daily 03:30 UTC APScheduler purge cron. - UI:
/trashview (batches summary, Restore, Delete-permanently, Empty trash, empty state) + Settings → General → "Trash retention" field.g+xkeyboard shortcut.
MCP transport — stateless HTTP
mcp/server.pysetsstateless_http=Trueon the FastMCP instance. The default stateful streamable-HTTP transport handed Claude Code anMcp-Session-Id; after a container redeploy the server rejected the now-unknown id with 404, and Claude Code doesn't re-initialize on 404 (issue #60949), so the connection stranded until manual/mcpretry. Stateless makes every request self-contained (bearer-auth only); the next message after a redeploy reconnects automatically — no manual intervention.Pre-pivot work in the diff (removed by the pivot)
The diff includes substantial work that landed on dev before the MCP pivot and was subsequently removed by it: curator phases C1-C5 (additive-only curator tools, authority routing, Needs Review panel), journal closeout + captures panel, TTS migration (kokoro → piper) + voice admin UI, diagnostics for crash investigation, model-bench tooling (
bench_ollama.py), user-controlled think mode. These commits remain in history but the surfaces they touched no longer exist in production.Deploy notes
- Destructive migrations. 0052/0053/0054 drop large chunks of pre-pivot data (chat conversations, journal moments, voice settings, weather cache, image cache, push subscriptions, rss item embeddings). Back up before deploy if anything in those tables matters.
- Migration sequence: 0044 → 0057 run automatically on first boot.
- Compose stack reduces to two services:
app+db. No Ollama, no Redis, no background worker. - MCP access: create a bearer token via Settings → MCP Access after deploy. Configure in Claude Code via
claude mcp add --transport http scribe <BASE_URL>/mcpwith the token in the bearer header. - First-boot fastembed download: ~150 MB ONNX model goes to
/data/fastembed-cache; persists across container restarts.
Verification
- All backend pytest tests pass (CI green on commit
2f577fe). /trashUI + Settings retention field device-checked by operator 2026-05-29.- MCP reconnect verified after the stateless-HTTP fix (Portainer redeploy → next message reconnected without manual
/mcpretry). - Trash dogfood (via MCP this session): throwaway project cascade-delete →
list_trash→restore→ re-delete →purge_trashround-trip; singledelete_task→list_trash→restoreround-trip. Both passed.
Known follow-ups
Captured as plan-task 183 on project 3, milestone M1 "Authorization & share-correctness (May 2026)":
- Share-debt in soft-delete:
list_trash/restore/purgeignoreuser_id(cross-user leak under multi-user); retention reads user 1's setting globally rather than a per-instance admin value; collaborator-delete semantics undefined. - Cosmetic papercuts:
purge_trashrowcount is off-by-one when the batch holds parent + children whose DB-level FK hasON DELETE CASCADE(end state correct, count off by one); trash items showtype: "note"foris_task=Truetasks. - MCP write-scope enforcement — mutating tools currently ignore the read/write token scope.
These feed the M1 foundation work. See project 3 milestones for the full M1→M4 roadmap (authz → audit → review surface → retrieval quality).
Downloads
- New endpoint —
-
released this
2026-05-13 19:28:34 -04:00 | 237 commits to main since this releaseForty-five commits across four feature groups: the journal closeout work from earlier in the day, the LLM tool-use fixes from the 2026-05-08 prod conversation investigation, and two new fully-specced projects (task-as-durable-record and note version pinning).
Project A — Task as durable record
The task body becomes the canonical record of what happened, not just what was initially asked.
- Schema: new
descriptionfield on Note (user-stated goal). Newconsolidated_attimestamp. Migration 0044 copies existing body content into description for existing tasks. - Body semantics shift for tasks: body is now LLM-maintained, written by a background consolidation pipeline from the task's accumulated work logs. Description is user-owned and never edited by the pipeline. Embeddings continue to index
title + body, so semantic search now hits the work-done summary rather than the initial goal text — tasks become discoverable by what was actually done. - Consolidation pipeline: debounced after 3 new
log_workentries, OR fired immediately on task status transition todone/cancelled. Usesbackground_modelso the chat model's KV cache stays warm. Per-task asyncio lock prevents concurrent runs. Failures leave body untouched; next trigger retries. - Tool layer enforcement:
create_notetool drops thebodyargument when status is set (i.e., creating a task);update_notetool rejects body writes on tasks with an error that nudges towardlog_work. HTTP routes still accept body so the frontend editor works pre-consolidation. - Manual control:
POST /api/tasks/:id/consolidateendpoint +auto_consolidate_tasksuser setting (General tab toggle). Manual endpoint bypasses the toggle. - Frontend: "Goal" textarea added above the body in
TaskEditorView;TaskViewerViewrenders the Goal block subordinate to the body. TipTap body editor is gated to read-only onceconsolidated_atis set; a "Re-consolidate" button calls the manual endpoint.
Project B — Note version pinning
The existing rolling 50-version snapshot system grows two retention tiers above the baseline.
- Schema:
pin_kind(NULL= rolling,'auto','manual') andpin_labelcolumns onnote_versions. Migration 0045 leaves all existing rows as rolling. - Three FIFO buckets:
- Rolling autosaves: cap 50 per note (unchanged from before, but the prune query now filters
pin_kind IS NULLso pinned rows are not counted). - Auto-pinned: cap 25 per note. A daily 03:00 UTC APScheduler job walks each note's version chain and pins versions that are followed by another version ≥2 days later (or the latest version if it's ≥2 days old with no successor). Auto-label is generated from the stability window.
- Manually declared: unlimited. Never pruned.
- Rolling autosaves: cap 50 per note (unchanged from before, but the prune query now filters
- API:
POST /api/notes/:id/versions/:vid/pinaccepts an optional label;DELETE /api/notes/:id/versions/:vid/pinclears pin_kind/pin_label (downgrades back to rolling — does NOT delete the row). - Backup export/import roundtrip: both new fields persist through
/api/exportand restore..get()on import preserves backward compatibility with older backup files. - Frontend:
HistoryPanel.vueextended with kind-aware badges (filled circle = manual pin, half-filled = auto-pin), label rendering, and a pin/unpin/edit-label control row above the diff view.
LLM tool-use fixes (2026-05-08 investigation)
Five fixes shipped together because they share a root failure mode in colloquial project/task references.
search_projects_toolnow returnssuccess: Trueso the dispatcher doesn't mislabel valid results as errors.list_notesstrips filler type-nouns (task,tasks,note,notes,project,projects) fromqbefore the ILIKE AND-filter;search_notestool description nudges the model to usetype/projectparameters instead of stuffing those words intoquery.- New shared
score_project_matchhelper unifies ranking betweensearch_projects_toolandresolve_project. Tiered scoring (1.0 exact / 0.85 substring either way / 0.70 query-in-description / SequenceMatcher fallback against the title).score_project_matchalso stripsproject/projectsfiller from queries so "famous supply project" substring-matches "Famous-Supply Work topics" at 0.85 instead of 0.228. record_momenttool description tightenstask_titles/note_titlesto require values from a priorsearch_notescall in the same turn.- Journal calibration prompt + chat
tool_linesstatic block both gain a "search-first when user references existing work" clause.
Journal closeout
Nightly per-user closeout extracts profile observations from the day's journal.
services/journal_closeout.pyruns once per user per day at the user'sday_rollover_hour. Reads yesterday's/journalconversation, filters outdaily_prep-metadata messages at the SQL layer (hard data-exclusion guard against the briefing-era feedback-loop pathology), and asks the background model for 2–5 bullet observations. Appends toobservations_raw.closeout_enabledconfig key (default ON) wired to Settings → Profile.GET /api/profile/observations+ collapsible "Recent observations (14)" panel for transparency.- Catch-up on startup if today's
day_rollover_houralready passed and yesterday's entry is missing.
Deploy notes
- Two schema migrations (0044, 0045) — both additive and safe.
- No frontend build required beyond standard CI.
- The auto-pin scan first fires at 03:00 UTC after deploy. Existing notes won't see auto-pinned versions until then (or earlier if you manually pin via the new UI).
- The consolidation pipeline only fires for tasks that get new
log_workentries OR status transitions after deploy. Existing tasks retain their current body until they accumulate enough new logs to trigger consolidation.
Verification
- All backend pytest tests pass (CI green on PR #50)
- Migrations apply cleanly on the dev environment
- End-to-end on the dev environment: task description roundtrip, consolidation trigger after 3 work logs, body editor gating, version pinning + auto-pin scan, journal closeout settings UI
Known follow-ups
- Project D (
fable-dev #167) — journal prompt simplification + WRITE_FALSE_CLAIM reconciler + tool description tightening + model-swap safety check. Recommended next; high priority. M effort. - Project E (
fable-dev #168) — pipeline decoupling to enable journal model swap. Deferred.
Downloads
- Schema: new
-
released this
2026-05-12 21:32:01 -04:00 | 260 commits to main since this releaseTwo threads — one rebuilds a half-deleted feature, the other patches an LLM-misuse failure mode caught in prod.
Journal closeout for profile observations
The briefing tear-down on 2026-04-25 deleted the closeout job but left the read path:
build_profile_contextstill injectslearned_summaryinto journal-prep and chat system prompts. Result was a stale frozen summary plus no path to refresh it. This release reinstates the write side with a hard guard against the briefing-era feedback loop.services/journal_closeout.py(new) — runs once per user per day at the configuredday_rollover_hour. Reads yesterday's/journalconversation, filters out messages withmsg_metadata.kind="daily_prep"at the SQL layer, asks the background LLM for 2–5 bullet observations focused on user-side patterns (NOT structured fields like name/job/expertise — those are still theupdate_profiletool's lane), and appends toobservations_rawvia the existingappend_observations.- Hard data-exclusion guard — the daily-prep block is structurally invisible to the closeout LLM. The previous briefing-era closeout sent all messages with role labels and relied on the prompt to say "user revealed"; that's the shape that caused the feedback loop. Instruction-only role separation isn't reliable on local Ollama models against long transcripts.
background_modelfor the LLM call — keeps chat-model KV cache warm.closeout_enabledconfig key (default ON), wired to a Settings → Profile toggle. NewGET /api/profile/observationsendpoint and collapsible "Recent observations (14)" panel for transparency.- Catch-up on startup — if today's
day_rollover_houralready passed andobservations_rawhas no entry for yesterday, runs once.
LLM tool-use fixes from 2026-05-08 journal session
Prod conversation #282 exposed three concrete code bugs and two behavioral patterns. All five fixes shipped together because they share a root failure mode: when the user names a project/task colloquially, the model fails to find it, fails to trust valid matches, or skips searching entirely and fabricates a moment.
search_projectsreturnssuccess: True— the dispatcher reads this key to setstatuson the conversation history entry. Missing key → result labeledstatus: erroreven when data was returned → model second-guessed valid matches. One-line fix.list_notesstrips type-nouns fromq—task,tasks,note,notes,project,projectsare filtered out of the keyword-search tokens before the AND-ILIKE filter is built. Closed the case where "find the sebring secondary task" returned 7 unrelated tasks because task #95's title and body don't contain the word "task".search_notestool description also tells the LLM to usetype/projectparameters instead of stuffing those words intoquery.score_project_matchshared helper (new intools/_helpers.py) — tiered scoring (1.0 exact title / 0.85 substring either way / 0.70 query-in-description / SequenceMatcher-against-title fallback). Stripsproject/projectsfiller from the query so "famous supply project" substring-matches "Famous-Supply Work topics" at 0.85 instead of 0.228 SequenceMatcher floor. Bothsearch_projects_toolandresolve_projectuse the helper — single source of truth, no drift between the LLM-facing surface and the create-task resolver.record_momentdescription —task_titles/note_titlesmust come from a priorsearch_notescall in the same turn. Prevents the project-name-as-task-title misuse that triggered the original investigation.- Search-first heuristic added to both
JOURNAL_CALIBRATIONand the chattool_linesstatic block: when the user references existing work, callsearch_notesfirst; create or record only after no match surfaces and the user confirms.
Verification
- 178+ backend pytest tests pass (CI)
tests/test_journal_closeout.py— filter, run_for_user happy + skip paths, scheduler register/disable, catch-uptests/test_tool_use_fixes.py—_strip_type_nouns,score_project_matchtiers,search_projects_toolranks substring above SequenceMatcher,resolve_projectfinds colloquial match- Tool-use fixes verified end-to-end against fable-dev MCP:
search_projectsshowsstatus: success, score 1.0 for exact-match substring;search_notescorrectly splitquery="tool-use"/type="task"and returned the right task - Search-first heuristic verified in journal UI
Deploy notes
- No schema migrations; deploy-only
- After deploy, optionally click Reset Learned Data in Settings → Profile to wipe the stale briefing-era
learned_summary. The new closeout will rebuild from clean observations starting tomorrow's prep cycle.
Out of scope (follow-ups)
- Manual verification of the closeout toggle / observations panel (PR test plan checkbox left unchecked — covered separately)
- Hybrid BM25 + embedding search (replaces semantic-only)
- "Did you mean X?" UI surface for project matches in the 0.40–0.85 score band
Downloads
-
released this
2026-04-29 22:08:38 -04:00 | 284 commits to main since this releaseHighlights
EventSlideOver recurrence UI
The calendar event modal now exposes the existing
Event.recurrenceRRULE column. A "Repeat" select offers None / Daily / Weekly / Monthly / Yearly presets that map to/from canonical RRULE strings.CalDAV-imported rules with extra parts (e.g.
FREQ=WEEKLY;BYDAY=MO,WE,FR) are preserved — they surface as a disabled "Custom" option with the raw rule shown read-only, so they remain visible in the UI without us silently destroying them.Journal weather wiring fixes
Closes two real gaps that caused empty weather sites in the journal panel:
-
Saving locations now triggers a fetch.
PUT /api/journal/configkicks off a backgroundrefresh_location_cachefor every saved location with valid lat/lon. Previously, newly-entered sites had no cache row (or a stale one) until the user manually clicked the panel's refresh button. -
Orphaned cache rows are filtered. Migration 0040 deleted the briefing-era
briefing_configsetting but leftweather_cacherows untouched. Those briefing-era rows showed up as ghost tabs in the new journal weather panel.get_cached_weather_rowsnow accepts avalid_keysfilter; the journal weather routes and prep pipeline pass currently-configured location keys, so only cache rows that match an actively-configured location surface in the UI or the daily prep.
Commits
36cd08cfeat(events): expose recurrence presets in EventSlideOverc33cab7fix(journal): wire weather refresh on config save; drop orphaned cache rows
Verification
- 153 backend pytest tests pass
- Frontend
vue-tsc --noEmitclean - CI green on dev before merge
Downloads
-
-
released this
2026-04-29 16:04:58 -04:00 | 287 commits to main since this releaseCloses the 4/29 dentist-appointment investigation. Two complementary structural fixes plus the held-back EventSlideOver UX refactor.
Event-store data integrity
#160— Duration replaces end_dt at the storage layer. Schema migration 0043 addsduration_minutes(with>= 0CHECK constraint) and dropsend_dt. Wire format unchanged —end_dtis now a derived@property. End-before-start is structurally inexpressible. The corrupt prod row that triggered this work backfills toduration_minutes=NULLautomatically.Behavioral upgrade: moving an event's start now slides the effective end forward (preserving duration), instead of corrupting or hard-rejecting.
#161— Tool layer disambiguates multi-match. Whenupdate_eventordelete_eventget a query that matches 2+ events, the tool returnssuccess: falsewith acandidatesarray. The model picks one by passingevent_idon the next call. Pre-fix: both tools silently tookmatches[0], which is exactly how the dentist event got applied to the wrong row.Calendar UX
EventSlideOver redesigned as a centered modal. Auto-save on close (X / Esc / backdrop click / Enter in form). Trash icon in the header (edit mode only). Invalid form in edit mode → toast + discard; in create mode → silent discard. Removes the right-edge floor band where the destructive Delete button was visually invisible.
Reverted in-flight
94b169f(A+B hotfix) is reverted byb7e7073— superseded by#160. The hotfix made bad data filterable;#160makes it inexpressible.
46 calendar/events tests pass. Ruff clean. Schema migration runs automatically on container restart. Tag push triggers the build.
Downloads
-
released this
2026-04-29 12:11:12 -04:00 | 293 commits to main since this releaseHotfix-style follow-up to v26.04.29.1.
Anti-placeholder rule on
create_eventThe model was creating events with stand-in titles ("Appointment") and "details TBD" descriptions when the user mentioned a future event without concrete specifics, instead of asking for the missing pieces first. The placeholder title then never got updated when the user supplied real details.
The
create_eventtool description now names the failure mode explicitly and instructs: record a moment, ask for the missing pieces, and callcreate_eventonce with the actual title, time, and location. Pairs with the capture-first persona changes from v26.04.29.1.Pure prompt change. 18 calendar-tool tests pass; ruff clean. No schema or migration.
Downloads
-
released this
2026-04-29 10:38:03 -04:00 | 295 commits to main since this releaseCalendar tool — date/time handling made model-agnostic
A "schedule for this Friday at 8am" request landed on Thursday. Two distinct fault lines fixed:
- Split
startintostart_date+start_time— aYYYY-MM-DDstring carries no TZ for the model to mis-tag, so the calendar day cannot drift across the local→UTC boundary. Strict regex rejects TZ suffixes on either field. Legacy combinedstart/endkept as backcompat. - Today's weekday anchored in system prompts;
expected_weekdayvalidator oncreate_event/update_event. Prompts now read"Today is Wednesday, 2026-04-29"instead of forcing the model to derive the weekday. The validator rejects mismatches with a self-correcting error and respects the user's local TZ (Tokyo Friday 23:00 stays Friday).
Journal — three rough edges from real usage
- Persona tuning — capture-first; helpdesk-style follow-ups banned; emoji ban; first-person moment phrasing required (no more "The user mentioned…").
record_momentdata hygiene — server-side keyword-overlap guard drops moment→task links that share no meaningful keyword; placeholder filter drops generic single-word place names (work,home,office).- Prep filtering — tasks bucketed into due-today / upcoming / overdue (overdue items surface with staleness duration, not as "due today"); events use a TZ-aware day window + proximity filter, fixing recurring events surfacing 5 months out.
fable-mcp 0.3.0
Briefing tools removed, journal tools shipped. Reinstall with
pipx install --forceafter deploy.
53 backend tests pass; ruff clean. No schema or migration changes — deploy-only.
Downloads
- Split