-
v26.08.22.1 — project inception (decide what a project inherits)
StableCI & Build / Python lint (push) Successful in 5sCI & Build / Plugin hooks (push) Successful in 12sCI & Build / integration (push) Successful in 27sCI & Build / TypeScript typecheck (push) Successful in 33sCI & Build / Python tests (push) Successful in 1m5sCI & Build / Build & push image (push) Successful in 15sreleased this
2026-08-22 00:56:27 -04:00 | 131 commits to main since this releaseProject inception (milestone 297, PR #124). A project's inheritance is a decision, not a default:
create_projecttakes what the project inherits (always-on rulebooks to exclude, rulebooks to subscribe, design system, seed the standard Systems);enter_projectasks the owner of an undecided project untildecide_project_inceptionrecords it; the New-project modal gains a second step and the project page an inception card; the Rules tab shows excluded always-on rulebooks. Exclusions are total across every rule surface, including the SessionStart block. Existing projects are stamped inherit-all (legacy) — no new asks for them.Migration 0085. Backup v10. Plugin 0.1.38.
🤖 Generated with Claude Code
Downloads
-
v26.08.21.2 — ledger first-contact fixes
StableCI & Build / Python lint (push) Successful in 4sCI & Build / Plugin hooks (push) Successful in 7sCI & Build / integration (push) Successful in 25sCI & Build / TypeScript typecheck (push) Successful in 33sCI & Build / Python tests (push) Successful in 57sCI & Build / Build & push image (push) Successful in 14sreleased this
2026-08-21 18:10:06 -04:00 | 140 commits to main since this releaseFixes found on the first refresh under v26.08.21.1 (PR #123, issue #2877):
- One-line CSS rules fingerprint their own declarations (they hashed to sha1("") and grouped 68 unrelated one-liners as one "copy" in the derive readout).
- The proposer writes
usesedges for already-judged consumers too (consumer maps were missing every call site classified before the edge table existed). - 0084 migration docstring reworded (extractor false positive).
No new migrations.
🤖 Generated with Claude Code
Downloads
-
v26.08.21.1 — shape audit consolidation + ledger follow-ups
StableCI & Build / Build & push image (push) Successful in 15sCI & Build / TypeScript typecheck (push) Successful in 23sCI & Build / Plugin hooks (push) Successful in 8sCI & Build / Python lint (push) Successful in 3sCI & Build / Python tests (push) Successful in 57sCI & Build / integration (push) Successful in 21sreleased this
2026-08-21 15:39:45 -04:00 | 142 commits to main since this releaseScribe shape audit (milestone 296) — code consolidation across tests/models/mcp/routes/services/frontend (PRs #120, #121): tests/helpers.py + conftest fixtures;
iso()+ model mixins;rules_payload;attach_relations; route helpers;start_periodic/ScheduledJob/hash_token/ backup row builders;auth-shared.css,apiErrorMessage, dateFormat helpers, modal canon in components.css (fixes ConfirmDialog unstyled, #2856).Ledger follow-ups (milestone 294, PR #122) — proposer v3 (language-family gate, reference stoplist, same-project semantic);
list_shapes(compact=)+classify_shapes_by_rule; thescopedbucket; derive ranking by body identity + CSS declaration fingerprints;bind_repo(ref=)(migration 0082);reason_codecatalogue (0083); case-insensitive repo lookup;code_shape_usesconsumption edges (0084); backup v9. Plugin 0.1.37.Migrations 0082–0084 run on deploy.
🤖 Generated with Claude Code
Downloads
-
v26.06.03
Stablereleased this
2026-06-03 12:51:04 -04:00 | 460 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 | 492 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 | 498 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 | 501 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 | 620 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 | 643 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 | 667 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
-