com.matthiasn.lotti CC-BY-SA-4.0 GPL-3.0-only Lotti Private logbook with AI assistants

Lotti gives you a private logbook and a staff of personal AI assistants to go with it. Record your day the way it actually happens — tasks, tracked time, voice notes, transcriptions, journal entries, habits, and health data — and long-living agents read what you record, keep it summarised, remember the context you would otherwise lose, and propose the next step. Agents suggest, you decide: every proposed change waits for your approval, with one small exception — an initial title or language for an otherwise empty task.

All of it happens on your own devices. No server ever holds your data in readable form: multi-device sync is end-to-end encrypted, and the relay between your verified devices holds only ciphertext — not forever, and nothing depends on it keeping anything. There is no telemetry. On capable hardware the AI models run locally too, so your data never has to leave the machine; on lighter hardware, or to save battery, you route inference — per life category — to a cloud provider you choose. Your logbook is ordinary SQLite on your own disk with attachments in ordinary files beside it, readable without Lotti, so there is nothing to export and nothing to unlock.

Under the hood, sync runs over Matrix using Vodozemac (Rust) for Megolm crypto; the homeserver relays only ciphertext between your own devices, and encryption keys reach only devices you have verified. A new device catches up because your other devices re-send history, not because a server stored it.

Get support and join the Lotti community on Discord via the Contact link.

What it does:

Matthias Nehlsen https://github.com/matthiasn/lotti https://matthiasn.github.io/lotti/manual/ https://discord.gg/uuSaa8NpY https://github.com/matthiasn/lotti/issues com.matthiasn.lotti.desktop com.matthiasn.lotti

Changed: Goals now use one trustworthy status language everywhere. The Goals list, detail page, and agent chat agree on On track, At risk, Behind, and No data; recovery hints say how many successful days are needed instead of reading like a countdown. Goal check-ins have distinct Close and Save actions, transcription failures can be retried, long histories load in pages, and voice recording and playback expose localized screen-reader controls. The first-run Goals page explains how to begin, completed goals remain available in an archive, phone agent controls take less space, and switching 14/30/90 day ranges keeps the previous view visible while the new range loads.

Added: a faster, cheaper Melious profile. "Melious.ai (Flash)" joins the existing Melious profile rather than replacing it, so nothing you have set up changes. It runs everyday thinking on DeepSeek V4 Flash and keeps Kimi K3 for high-end reasoning and image recognition, with the same Whisper transcription and image generation. On our task-agent evaluations it matched the standard profile's results across three full runs while costing an order of magnitude less per agent wake and answering in about a third of the time.

Fixed: DeepSeek V4 Flash works when you choose it. The model was offered in the Melious catalog under an identifier the provider does not serve, so every request made with it failed. It now points at the served model.

Added: your goal agent reads your check-ins. Each check-in is distilled once into a short structured record - what happened, what you said you would do, what was in the way - and it is that, never the raw transcript, that reaches the agent. Recent check-ins ride along with the measured facts, so the agent can quote a dated commitment back to you. Your own words never override the measurements: a cheerful check-in cannot turn a missed week into "on track". Checking in marks the standing report out of date rather than triggering an update per recording.

Added: check-ins on a goal. Say what is actually going on, in your own words, whenever it is worth saying - one tap into the recorder from the goal's app bar, its Check-ins card, or a banner that asks. Recordings land as dated beats on the goal's timeline and play where they sit, with their transcript beneath; a recording is saved before it is transcribed, so it is never lost waiting for words. Daily reflections join the same timeline, and tapping one reopens that day. On a wide window the timeline is a column beside the dashboard; on a phone it previews in a card with a full history behind it. The reflection sheet's note gained a second way to answer: a voice note, kept separate from anything you typed.

Added: voice memos play on an event's timeline. A recording linked to an event used to show only its duration; it now carries the full player - play, scrub, speed - where it sits, with its transcript beneath.

Added: a personal CRM for a deliberately curated set of people. One relationship entity per person, plus structured check-ins (interaction type, sentiment, topics, narrative) linked to it, behind the new People tab (enable_relationships). Includes the recency-ordered list, the per-person detail page with status, cadence and nickname, the add/edit person modal with manually entered contact channels (phone, mobile, email, messaging) on every platform, a linked-tasks section that connects tasks to a person in either direction, and a check-in capture sheet that is editable and deletable afterward. Cascade deletion, sync, categories, and the private flag all apply, and contact channels never enter AI context.

Changed: goal signal charts now show the trend behind the number. Daily steps use bars and weight keeps its filled curve, both with a dashed trailing seven-day average overlaid. Legends identify actuals, averages and targets, with each target threshold annotated on the series it belongs to, and the steps card distinguishes daily steps from the average it evaluates.

Changed: a pass over the goal detail page. Charts reserve only the gutter their own axis labels need, so the plot uses the card width; tooltips name the day once as a header above their values, keep the value bold with a quieter label beside it, and can no longer be clipped by the card edge. Habit cards read one thing per row - cadence, span, days, then the six-week tail - and their day strips narrow to fit instead of opening with the first days cut off. A quota already passed reads as "6 this window - target 3" rather than "6 of 3". The day-cell key appears once, on the first habit card. A signal with no readings shows no empty chart frame, tracked-time bars gained a value axis, a date row, a key and a tap-to-read value, and the suggestion to check off a habit is now a proper prompt instead of fine print.

Changed: reflection sheets tell the truth about a day's numbers. A step count is labelled "Steps", not "Average steps per day", and the trailing seven-day average it belongs to appears on its own line. Rating individual dimensions no longer renders each name as a column of single letters, and the sheet clears the status bar.

Changed: goal health data refreshes when you open Goals. Entering the Goals list or a goal's page re-imports the health signals that goal watches, so weight, blood pressure and step cards are never a day behind the phone.

Changed: the goal page opens with the agent's read, wider, without repeating itself. The AI summary sits first with the goal-days strip beneath it; the "Your goal" label and the statement no longer repeat under a title that already names the goal; the chat button reads "Talk to agent" instead of echoing the goal's name; and the Goals list and detail columns widened to what the Habits page renders while keeping their gutters on small screens.

Changed: goal habit days now offer every quick status. The day menu adds Skip and No entry alongside Success and Missed; clearing appends an empty latest outcome without deleting the day's history, and the polished rounded menu's hover fill now reaches its bottom edge cleanly.

Added: daily goals can track time by label. A goal can require time on entries carrying a chosen label across categories, show partial daily progress until the hour target is met, and give its agent the entries' Markdown descriptions so coaching can reflect what the time was spent on.

Added: a unified Goals page, behind a flag. Turning on "Enable unified Goals page" in Settings - Flags adds a Goals tab that merges Habits and Goal Agents into one surface: each goal is a card with its health pill (recovery hint folded in), a one-line summary computed from live data, and its habits directly inside it with the familiar one-tap complete. Habits that belong to no goal keep their own group, and the consistency heatmap and completion-rate chart close out the page. The Habits tab stays unchanged while the flag is off.

Changed: slow local agents get more time to finish. An agent wake can now run for up to ten minutes instead of two, so larger local reasoning models are less likely to be aborted before they return.

Removed: the experimental "Enable Agents Page?" flag and its tab. The unified Goals page replaces that surface, so the toggle is gone from Settings - Flags (and cleared on existing installs); goal details, chat and the goal wizard now live under the Goals tab.

Changed: the goal detail page scrolls smoothly. The page now builds all of its cards up front instead of mounting them lazily mid-scroll, which removes the stutter while flinging through a goal's progress, watching and history sections.

Changed: the goal detail page is a dashboard, with the agent as a drawer. The permanent desktop chat column is gone: the page is one focused column - "This week" above the agent's read (now carrying an "as of" timestamp), each at the column's full width, then your habits and data signals under their own headings and a completion-rate chart scoped to just that goal's habits - and the conversation slides in as a compact drawer from "Talk to ..." or the new "Ask why" link, which arrives pre-filled with the exact status on screen. The agent's read wears the same panel as the task agent section on Task Details - same colors, same header, same update controls, and the goal's cumulative inference cost pills - so the two agent surfaces read as one product. The page wears the same status pill as the Goals list, and the whole page shares one time range: a single 14/30/90-day picker drives the goal's day strip, every habit and signal track and the chart together; longer spans open at today and all tracks scroll as one, so the same date stays lined up down the page. And a habit shared by several goals shows "Also in ..." on each goal's card - recorded once, reflected everywhere. When an update cannot run - the AI provider is out of credits, the network is down - the card now says so, quoting the reason, instead of sitting silently on "Out of date".

Changed: every banner in the rotating bar now carries its goal's persona chip and name - on desktop and on the compact bottom bar - so with several goals speaking, each nudge is attributed at a glance.

Changed: snoozing a banner quiets the bar, not the goal's own page. The goal detail page always shows its goal's current banner; while it is snoozed or dismissed from the bar, a live countdown under the card says when it returns. The snooze sheet's four full-width buttons became compact duration chips.

Fixed: toast borders now follow their rounded corners cleanly. Countdown and tone indicator strips no longer paint over the outline at the left corners, removing the doubled edge that was most visible at the top-left.

Fixed: screenshots work with AI image analysis again. New captures stay inside Lotti's documents directory instead of a similarly named sibling folder, and Settings → Advanced → Maintenance now offers Repair screenshot storage to safely move and reconnect every affected older screenshot.

Changed: editing a goal is two steps, not three. The separate "What do you want to work toward?" page is gone from the edit flow - the statement is a single-line field at the top of the edit page with the suggestion chips right beneath it, and the step indicator now says so.

Fixed: the plus and minus of the "At least N of M" rule changed the count but also dismissed the "How this goal comes together" sheet with every tap - the stepper now adjusts the count on a full-width control with proper touch targets, the sheet scrolls when space is tight, and it stays open until Done.

Changed: the Goal Agents list reads at full size. The per-goal week strip drew 12px dots that were illegible at list scale; it now uses the same cell size as the detail page, and the chip row is reduced to the health chip, the trend chip and one badge - the "needs attention" pill appears only as a fallback while the agent has no one-liner yet.

Fixed: on the desktop goal details page the middle column's scrollbar floated mid-pane at the reading measure's edge; the scroll view now spans its pane, so the scrollbar hugs the divider beside the chat.

Fixed: a day's bar is judged by that day's number. Step and measurement bars took the trailing-week verdict, so a 12,400-step day inside a weak week rendered as short of a 10,000 target; wherever the target is a per-day quantity, the bar, the week strip, the reflection sheet and the "met yesterday" tally now all judge the day by its own value.

Fixed: the agent quotes the same rounded number as the card - the report and banner used to receive the raw aggregate while the card showed the rounded one.

Changed: the steps signal no longer repeats its own name - the target input inside the "Average steps per day" card is labelled "Daily target" instead of duplicating the card title.

Changed: the habits completion-rate chart aims at a "Target", not a "Goal" - the dashed line and the points badge now say Target (and the equivalent in translations where the old word collided), so the word "goal" stays reserved for actual goals.

Fixed: Markdown reports paste as rich text in the editor. Headings, bold text, inline code, quotes, horizontal rules and lists copied as Markdown source now keep their formatting instead of appearing with the punctuation intact, while ordinary plain text and richer HTML clipboard content keep their existing behavior.

Changed: Tasks and Projects have a desktop focus mode. Once an item is selected, you can hide the list and give the detail the full workspace, then restore the list with its search, filters, scroll position and previous width intact. Back stays reserved for real navigation: project details do not show it in the desktop split, and task details show it only after opening a linked task.

Changed: goal-agent banners now make Snooze the primary action, with 1, 3, 6, and 8 hour choices. Dismiss for today is a secondary option, banners return automatically after the chosen deadline or on the next local day even after an app restart, and durable snooze and dismissal timing history gives the goal agent evidence for choosing better initial display times.

Fixed: asking the goal agent in chat to change its report now changes it. Telling the agent to make its report shorter, sectioned, or less repetitive used to produce only a chat reply while the standing report stayed exactly as it was; the request now rewrites the report itself, and an explicit refusal to change it is respected.

Changed: goal agent pages get the whole screen on phones. The bottom navigation bar slides away on a goal's detail page, its chat, and the create and edit wizards, the way it already does for project details, so the day sheet's record button and the wizard's Continue band dock at the bottom edge instead of sitting under the bar.

Fixed: project agents no longer keep an empty daily 06:00 wake alive. Digest work is scheduled only after relevant project or linked-task activity, and existing dormant schedules disappear from the Wake tab on startup.

Fixed: pending project-agent work now survives failures, restarts, and every sync arrival order. Meaningful one-shot fallback wakes stay visible in the project report countdown until the work succeeds or you cancel it, and cancellation cannot be re-armed by an in-flight wake.

Fixed: the goal agent's report opens short and expands. The card has always had a short summary and a Show more toggle, but the goal agent never filled them in separately, so every report arrived as one unbroken wall of text with nothing to collapse; it now leads with a one- or two-sentence summary and opens the full report on demand.

Fixed: no more internal ids or status codes in the goal report. Lines like "Close the gap on habit 71ca84b0" and "the overall status is insufficientData" are gone, criteria are named by their title, and links to tasks are untouched.

Changed: agent update controls read as one deliberate control on phones. The freshness word, Update now and the automatic-updates switch used to sit crammed together on three left-aligned lines; status and its refresh button now span the row, a rule separates them from the switch, and the button lines up with the switch above it.

Added: a fourth day verdict, Improving, for a day where you missed some of the goal but moved the right way - previously such a day shared "Mixed" with days that simply stalled.

Added: reflections start from your data. Opening a day's reflection pre-selects the verdict the evidence points at and says so, rather than always starting on Met; a day with nothing recorded suggests nothing at all.

Changed: day verdicts show on the Goal Agents list too - a day you filed as missed used to sit there in the grey of a day nobody looked at, so one goal read two different ways depending which screen you were on. The report is also selectable and eases open rather than snapping, like the task agent's.

Fixed: the agent-recorded badge on a chart bar stays inside the chart instead of floating over the card header above it.

Fixed: a reading inside its target no longer shows as missed. The day sheet printed "122" against a 125 ceiling and crossed it out, because the mark came from the rolling average rather than the reading beside it.

Changed: the seven-day rows line up. The whole-goal week, the habit squares and the step bars now share one column grid, one cell shape and one legend shape, so a day sits in the same place down the page. The reflection sheet is spaced deliberately too: one gap scale instead of five, the measured evidence fenced in its own card, and the per-dimension row no longer floating.

Fixed: the card and the report now quote the same number. The dimension card recomputed its own weekly average over a different set of days than the agent's, so the headline figure and the report beside it could disagree about the same week.

Changed: "Reflect on today" moved up to the week it closes off - it sits inside the "The whole goal" card, directly under the seven-day strip whose cells open the same sheet, instead of last on the page below every chart, and it states today's verdict once you have recorded one.

Changed: the agent's report now leads the page, with the update controls below it; ahead of it they pushed what the agent actually says below the fold. The day-square key moved inside the card it explains and now names the empty state it used to leave out.

Changed: the goal report reads as sections - where things stand, the wider window, the latest change, data coverage and what is next - with the next actions as a list, and headings that follow your app language whatever language the report was written in.

Changed: "Not enough data" no longer contradicts the report beside it. The chip is hidden wherever the agent has published an assessment, and thin coverage is still stated inside the report itself.

Changed: long goal names get two lines in the goal and chat headers instead of being cut off mid-word, the per-signal note says whether the last reading moved toward the target instead of repeating one sentence on every card, the habit card's weekly streak moved onto the section heading line rather than sitting alone under the day squares, and the compute pill reads "thinking" rather than "AI time".

Fixed: averages no longer show false precision. A step average rendered as "7,684.429 of 10,000" and now reads "7,700 of 10,000" - a weekly average is an estimate of a habit, and its last two digits never meant anything. Blood pressure stays whole and weight keeps the decimal that does mean something.

Changed: every day in the seven-day goal strip is tappable, including past days. The squares now match the habit day squares in size, and tapping one opens that day's reflection; previously the only way in was a "Reflect on today" row, so a day could never be closed off once it had passed.

Changed: your own verdict for a day decides its colour. A day you have reflected on takes the colour of the verdict you gave it rather than what the app measured, and a new "Improving" verdict covers a day that missed some of the goal but moved the right way. Met, Improving, Mixed and Missed each have their own colour, and none of them is the grey of a day with no data.

Fixed: the day-verdict labels were mistranslated in seven languages. "Met" was rendered as the past tense of meeting a person - "Getroffen" in German, "Ontmoet" in Dutch, "Conheci" in Portuguese - and left untranslated in Romanian.

Changed: goal step bars are coloured by the goal they were measured against. A day at or above the target wears the same green as a met day square instead of the same muted slab as a day at half the goal, and the bars are slimmer so they no longer dominate the card.

Added: an explicit goal-name field in the goal editor. The name is a labelled field on the mapping step — pre-filled from the selected habits until you type your own — and the confirmation step shows the same field read-only with a pencil that unlocks it.

Added: steps and matching health signals are offered directly. The automatic step count is always available as a signal row, and an intention that names blood pressure or weight arrives with that health signal already selected and sensible targets filled in, while a habit that merely tracks the same reading waits unchecked under a Suggested caption.

Changed: goal-agent reports now wait behind a visible two-minute refresh countdown when new evidence arrives. Progress updates and the out-of-date state remain immediate, while the shared agent controls let you update now, skip one pending run, or turn automatic report updates off.

Changed: a design-panel pass over the goal create/edit flow. Every signal lives as one kind of row in one signals card with a provenance icon and its targets right on the row (blood pressure is a single row with paired inputs and one direction), rows keep their position while you toggle them, all signals are added through one multi-select picker, a missing target errors on its own input and scrolls into view, the continue button is always on screen on both form factors, and the confirmation step leads with the agent and recaps the goal as readable prose.

Changed: a design-panel polish pass across the goal-agent surfaces. The banner's Log today opens a one-tap logging sheet, day cells wear a dedicated success green with an inner dot for partial days, Restarting reads in blue, warning orange is reserved for genuine attention, the goal statement is labelled, phones get a persistent chat button, the Goal Agents list keeps one card silhouette with the week strip on the right on wide screens, day squares accept taps on a larger area, and chart target lines render at full strength.

Fixed: goal-agent health reports separate today's actions from rolling recovery. When today's blood-pressure reading is on target, the agent now says logging is complete today, reports the rolling average and latest change separately, and does not ask for another reading. Structured report sections keep latest values, trends, coverage, and actions from being omitted, while explicit current-day action items are accepted only for health criteria the app proves remain loggable.

Added: goal-agent chat supports voice input. The composer now has a microphone button that records, transcribes, and fills the text field.

Added: rolling-week charts show partial successes in a lighter green when the habit was completed but the window target was not yet met, habit cards offer a one-tap check-off when matching data was recorded today, and each day square shows its concrete date on hover and at the top of the Success/Missed menu.

Changed: the Agents tab is now called Goal Agents, and the goal detail page leads with the standing report and banners directly under the goal definition, with habit cards and charts below.

Changed: banners refresh when their evidence changes. A new measurement or habit check-off that changes the facts a banner quotes expires the outdated copy and wakes the agent for a replacement, and the standing report gains an out-of-date badge when new data arrives after it was written.

Changed: blood pressure and weight distinguish today's result from the rolling trend. They show the latest measurement and give positive feedback when today's reading is on target, while an over-target average still needs attention when today has not been measured.

Changed: goal health trends now use charts that fit the data. Systolic and diastolic blood pressure share one dual-line chart with separate target lines, while weight uses a line chart that makes small day-to-day changes visible. Other measurable dimensions keep their existing progress bars.

Changed: goal setup can monitor time spent in active categories, with a rolling seven-day hour target and an at-least or at-most direction.

Fixed: goal agents receive every timestamped blood-pressure and weight observation in the goal window alongside the rolling aggregate, so reports can cite the latest value and improving trend instead of presenting an average as a measurement.

Fixed: goal agents can choose an inference profile from Agent internals. Their AI setup row now opens the profile picker even though goal agents have no linked task.

Fixed: the Daily OS planner no longer wakes for days that are already over. Finished days kept firing full model runs that found nothing to do and re-scheduled themselves, burning inference for no result. Such wakes are now skipped before any model call, their leftover schedules are cleared automatically, and the planner can no longer schedule a new wake for a finished day.

Fixed: the wake-queue cancel button now actually cancels. Dismissing a scheduled planner wake from the sidebar queue or the Wake Cycles page previously only cleared agent state, so the wake returned on the next check; it now removes the underlying scheduled wake so cancelling one makes it stay gone.

Goal-agent criteria are ready for refinement. Goal agents remain configurable with linked habits and rolling seven-day step targets. Their evaluation foundation now preserves a separate accountable result for every configured criterion.

Added: goal agents can combine linked measurables, habits, steps, weight and blood pressure through all, any, or at-least-N rules while preserving accountable evidence for every dimension. New and existing goals can set a direction and target for weight and separate systolic/diastolic blood-pressure observations. A sustained health trend projected to reach its target within four weeks is on track without being mislabeled as achieved. Goal details support separate daily Met/Mixed/Missed reflections and identify the dimension that needs attention. An explicit quantity for a linked measurable in goal chat now produces an editable approval card; accepted values use the normal measurement history and retain visible agent provenance.

Changed: the Melious.ai profile now runs on GLM 5.2 and Kimi K3. Connecting a Melious key installs Kimi K3 alongside the models already offered, and the profile Lotti sets up for you binds GLM 5.2 for thinking, Kimi K3 for both high-end thinking and reading images, and Whisper Large v3 for transcription. Image generation stays on Flux 2 Klein 9B. An existing Melious profile moves to the same models on the next launch — unless you renamed it, described it, pinned it to a device or chose any model yourself, in which case it is left exactly as you set it. Voice capture that has no transcription model configured — onboarding's first task included — now also lands on Whisper Large v3 instead of the Voxtral chat path.

Added: vision models can use task images when writing coding prompts. Choosing an image-capable model such as Kimi K3 now offers the task's attached images as visual context, with up to ten selections. Text-only models keep the existing one-step flow, and linked AI image analyses remain part of the written task context as well.

Changed: AI task summaries now look like AI content wherever you scan tasks. The agent's one-line take uses the AI accent in task lists, appears beneath linked task titles, and sits between the title and status pills on task details, so the same compact context is visible without opening the full AI summary card.

Added: experimental goal agents — a flag-gated Agents tab with per-goal health at a glance (a coarse health chip and a trend arrow rather than a raw percentage), an editable day-by-day rolling progress grid that refreshes the expandable standing report, proposal approval, goal creation and deletion, lifetime AI-consumption and compute pills, purpose-bound durable goal conversations with Markdown and collapsible long replies, and dismissible rated text banners in a full-width shell-level dock above the navigation. Goal creation starts with the user's own intention, maps it only to observable signals, gives every watched habit its own weekly cadence, and confirms the goal and agent name; existing goals reuse that flow, saving every edit as a new version while retaining history. One rotating banner slot is shared across the Tasks, Daily OS and Habits tabs, shows the complete animated headline in the agent's tone, keeps compact banners to that voice and a trailing dismiss action, supports arbitrary snoozes, and lets an explicit request for a new banner override dismissal cooldown. Phones open conversation as a pushed page, desktop keeps it beside goal detail, drafts survive navigation, and failed turns can be retried without losing the user's message.

Changed: the Manual now matches the app it documents. An audit of every English page against the source found the recorded facts had drifted, and the corrections landed in all eleven languages: transcription offers every supported language rather than the three the Manual listed; the Language setting is described as the app's own language rather than just the Manual link; Settings paths name the branch they actually live under (Definitions, Sync Settings, Advanced Settings → Config Flags); Habits and Dashboards say up front that they ship switched off; destinations are called what the app calls them (Logbook, Insights, DailyOS); and the agent auto-apply exception is stated precisely — the field being set must be empty, which is wider than the "otherwise empty task" the Manual promised. Sync gains a table of what syncs and what stays on the device, the five AI skills are named, and the first-device page leads with its homeserver prerequisite.

Changed: the 1-on-1 with an agent now looks like one screen rather than several. The conversation home opened with a banner that repeated the page's own title, followed by a card headed "Current Proposal" in the state where no proposal exists, and a sentence printed twice on the same screen. It now leads with the one thing you can do, then what the agent has been doing since you last spoke, then what you decided last time, with past 1-on-1s visible without scrolling. The conversation itself no longer stretches its text the full width of a desktop window, the agent's replies are readable instead of sitting a shade above the background, and starting a session shows what is happening rather than a hairline spinner in the corner of an empty page. The wake-activity bars read as a chart rather than blurred lozenges, and their date labels thin out on a narrow screen instead of all shortening to "J…".

Fixed: large image nodes in the knowledge graph no longer overlap. Cover-backed tasks and photo collections are deliberately twice the normal node diameter, and the local layout now separates their actual circular footprints while keeping the focused task fixed in place.

Fixed: the one-on-one with an agent opens again on desktop. Choosing Review on a template or a soul did nothing in a desktop window — the address changed but the same page stayed on screen — so there was no way to start an evolution conversation, pick up one already waiting, or read past sessions. Phones and tablets were never affected. The desktop settings pane now recognises the review address and opens the conversation home it was always meant to.

Fixed: task agents now clear a blocked status once the blocker is gone. When a note said the thing holding a task up had been resolved, the agent would describe that in its report and leave the task sitting in Blocked anyway, because the instruction it follows treated a description of progress as something it must not act on. It now treats a resolved blocker as reason enough to propose moving the task out of Blocked, while still leaving vaguer impressions of how work is going alone.

Fixed: task agents no longer lose a change because a smaller model spelled the call slightly wrong. Two near-misses were common enough to cost real work: a model reaching for update_task_status when the tool is set_task_status, and a model sending a list of checklist updates as text rather than as a list. Both were discarded, and because the agent had been told the call succeeded, its report could describe a change that was never made. The right tool is now recognised under either spelling and the list is read either way, so the change reaches your proposals for confirmation as it always should have — a corrected call is still a proposal, never something applied behind your back.

Changed: demo tasks now explain themselves. Every task in the penguin demo world carries a full description of what the work actually is — why the air scrubbers are overdue, what the missing squid pallet's cold rating means, what the customs filing has to contain — instead of a single line. The thirteen tasks that shared four generic runbooks now have checklists drawn from their own work, and all of it is translated into every supported language.

Changed: the store listing and README now say what Lotti actually is. Both introduce Lotti as a private logbook with a staff of personal AI assistants — agents that read what you record and propose the next step, while proposed changes wait for your approval — and describe sync by its durable guarantee: no server ever holds your data in readable form.

Fixed: Lotti opens on Tasks, and the demo no longer leaves traces in your own journal's navigation. Starting the app — or switching between the demo world and your own — now always lands on the Tasks tab. Each tab also returns to its own starting point, so leaving the demo while a demo entry was open no longer leaves that tab pointing at an entry that only existed in the demo.

Added: knowledge-graph photos now open full screen. Tapping an image in the graph inspector's photo carousel opens the shared full-screen viewer with zoom, rotation and download, and — new for collections — chevron buttons and the left/right arrow keys move through all of the entry's photos, with a position counter showing where you are.

Fixed: the penguin demo banner is shorter, more prominent, and blue-themed, with its exit action aligned inline. The exit sheet buttons align inline when space permits and wrap safely when needed, seeded tasks have task-specific four-step checklists, and edits to seeded rows are preserved across seed updates.

Changed: demo image downloads now show live progress. The demo banner reports the completed image count while its R2 catalog hydrates in the background, without delaying entry into the workspace.

Added: the demo is now a whole absurd penguin logistics world. Its 29 tasks each have unique cover art, multiple attached operational photos or artifacts, and lived-in notes, checklists, or logged work. Six active space-logistics habits carry four weeks of imperfect history. All 91 images stream from a checksummed Cloudflare R2 catalog in the background, so slow or unavailable networking never blocks seeding or opening the demo and incomplete downloads retry on the next startup.

Changed: the task knowledge graph is now a readable local workspace. Instead of presenting the whole topology as a field of mostly anonymous dots, it shows a bounded one- or two-hop neighbourhood with prioritized full labels, stronger edges, exact-count aggregates for dense groups and photos, and a small topology map for long-distance jumps. A Connections list offers the same navigation grouped by relationship and direction, while density and filters control what remains visible. Task cover art and photo nodes now appear at twice the standard node diameter, turning them into useful visual landmarks instead of icon-sized textures. The compact task inspector surfaces cover art and related photos, keeps long titles intact, and leaves the detailed AI brief collapsed until requested. Keyboard, reduced-motion, high-contrast, and screen-reader navigation are supported.

Fixed: the knowledge graph is easier to read. Node labels no longer print under the toolbar or behind the legend, and the view now frames a task's neighbourhood into the space the floating controls actually leave free instead of a fixed guess, so linked nodes stop hiding behind the legend and minimap. Every direct neighbour keeps its name at any zoom level, so the next step in a walk can be read before tapping it. Photo collections of two or three images fill their circle instead of showing black wedges, and the photo count now matches the images previewed inside it. Checklist and AI-source links are drawn with their own dot patterns, so every relationship type is distinguishable without relying on colour. The linked-entries list shows a "More below" control while the list continues past the panel edge, and its fade no longer makes a scrollable section look disabled.

Fixed: knowledge-graph zoom now stays anchored under the cursor. Two-finger trackpad zoom (and pinch) kept sliding the graph while zooming because the fixed point was computed in window coordinates instead of the canvas's own — the content under the cursor drifted by an offset that grew with the zoom level. The point under the cursor now holds still through the whole gesture, matching maps/canvas-tool conventions.

Fixed: "Settings" no longer stacks into a column of letters in a narrow sidebar. Dragging the sidebar narrow, or raising the system text size, used to wrap the label one character per line and stretch the row to several times its height. Navigation labels now stay on one line and shorten with an ellipsis instead — the icon still identifies the row — and every icon is vertically centred on its label rather than pinned to the top of it, which was visible even at the default text size.

Changed: queued sync counts beside Settings are now abbreviated. A busy queue printed its full figure and took the space the Settings label needed; counts now read exactly through 999 and then compactly (1.2K, 18K), with the precise number still announced to screen readers. The divider between Settings and the contact buttons has been removed on both the desktop sidebar and the phone's More sheet.

Changed: those same sync counts now read as ambient status rather than as alerts. Each was boxed in an outline, which gave routine queued work the weight of something needing attention next to the Settings label. The outline is gone, the digits sit at a lower emphasis than the label beside them, and each arrow now sits directly against its number instead of a word apart.

Fixed: knowledge-graph images no longer flash away when selecting a node. Walking to a linked task (or any refresh of the graph data) rebuilt the canvas from scratch, briefly dropping every already-visible node image and cover thumbnail while they re-decoded from disk. Decoded thumbnails now survive those rebuilds, so established images stay on screen through node selection, navigation, and background sync refreshes.

Fixed: multi-device sync no longer mistakes a newer file for an older message. File-backed messages now name the exact encrypted attachment version they were sent with, so delayed, reordered, duplicated, or replayed events cannot manufacture missing-change storms from a different version at the same path. Backfill also verifies that a payload really covers the requested change before sending it and repairs stale historical mappings. Older app versions remain compatible while upgraded peers gain the exact guarantee.

Changed: the task knowledge graph is now a readable local workspace. Instead of presenting the whole topology as a field of mostly anonymous dots, it shows a bounded one- or two-hop neighbourhood with prioritized full labels, stronger edges, exact-count aggregates for dense groups and photos, and a small topology map for long-distance jumps. A Connections list offers the same navigation grouped by relationship and direction, while density and filters control what remains visible. Task cover art now also appears directly in its circular graph node for faster visual recognition. The compact task inspector surfaces cover art and related photos, keeps long titles intact, and leaves the detailed AI brief collapsed until requested. Keyboard, reduced-motion, high-contrast, and screen-reader navigation are supported.

Changed: task cover art now opens full screen. Tap the artwork at the top of a task to use the same zoom, rotation and download viewer as linked photos.

Added: getting in touch is now one tap from the navigation. Four equal contact buttons close the More sheet on a phone and sit pinned to the sidebar's lower-right corner on desktop. The envelope opens a mail draft to the project, followed by the manual in your language, the source repository, and the Discord community. Queued sync work appears beside Settings as separate quiet outlined directional counts — downward for incoming and upward for outgoing — instead of a red error-like badge or a separate stats row. The old opt-in sync-activity row and its config flag have been removed. All four contact actions leave Lotti and open in your browser or mail app. On a collapsed sidebar the row goes away, and the manual is still in Settings.

Fixed: a hovered row in the Add menu is no longer cut by the lines around it. Pointing at an action highlighted it, but the hairlines above and below stayed drawn straight across the highlight, so the row read as two halves rather than as one thing you were about to tap. Both now step out of the way while the pointer is on the row — the same behaviour the settings lists already have — and nothing shifts as they go.

Fixed: initial Sync setup no longer gets stuck on impossible checks or one bad row. A first device skips the comparison code that only a second device can verify, while added devices still confirm it. Message history now clearly offers All, custom ranges use the full calendar including the year, and one malformed history row no longer stops the remaining history from being queued. The summary names failed rows and retries only those rows.

Added: demo mode — explore Lotti in a play world before trusting it with your own data. The onboarding welcome leads with it, and you can also start the demo from the tasks empty state or Settings. The Intergalactic Penguin Logistics workspace is a real week of work: 28 tasks across three areas, linked to each other and to their notes, photos, checklists and logged sessions, with due dates relative to today, plus a guided "first mission". It lives in its own sandbox with separate databases and no sync, so nothing reaches your real journal unless you copy it over. A persistent banner marks the demo while it is active, and you can leave at any time — exiting keeps the demo resumable, and the exit sheet offers to copy the tasks and entries you created there (and any AI setup you connected) into your real journal. The demo's AI is fictional until you choose otherwise: a guided step can connect your real AI provider inside the demo, and the key stays in the sandbox unless you copy it over on exit.

Fixed: health imports stop asking for permission you have already answered. Lotti requested authorization on every import, including the background ones a dashboard starts for each of its health cards on open. Once a data type has been answered for — allowed, or switched off in your device's health privacy settings — asking again cannot change anything, and what you got was a sheet with nothing in it to answer, every time you opened the dashboard. Access is now asked for once per session, and again only when you tap a row on Settings → Advanced → Health Import, which is when asking is the point.

Fixed: blood pressure asks once instead of twice. The blood-pressure card charts systolic and diastolic as two separate series, so it started two independent imports and each one raised its own permission request — two prompts, back to back, for a single switch. Each kind of data is now authorized as the family it belongs to: one prompt for blood pressure, one for sleep, one for body measurements.

Fixed: an import blocked by permissions no longer reports success. With a data type switched off, Apple Health reports the authorization as fine and then returns nothing, so the row showed a green tick reading "No new samples" — the same thing it says when you are simply up to date. A category that read nothing and has never brought in a single sample now says so, and the page offers a shortcut to the system settings where read access is turned back on. Apple does not disclose whether an app may read a type, so this is worded as something to check rather than a verdict.

Fixed: a blocked activity import no longer writes days of zero steps. It wrote one entry per day before noticing it had read nothing, and those zeros then charted as real days.

Changed: task agent suggestions now appear while the agent is still working. They used to arrive all at once when the whole wake finished, which meant waiting out the agent's report writing even though it had already decided what to suggest. Suggestions now show up as soon as the agent proposes them, and arrive in waves when it works through several rounds. A wake still produces a single suggestion card, and nothing changes about reviewing or confirming them.

Changed: full-screen photos now follow phone rotation. The rest of Lotti remains portrait-only on iPhone and Android phones, but opening a journal image or event photo temporarily permits either landscape direction. Wide cover art is contained and centered in either orientation, with controls floating over a canvas that reaches the screen edges, and closing the viewer restores portrait.

Changed: the task page's Add menu speaks the same language as the page. The "..." menu offered "Text Entry", "Checklist" and "Audio Recording" — the same actions the new-task card had just introduced as "Write a note", "Add a checklist" and "Record a voice note". One action now has one name wherever it appears, every row is a verb, and rows whose outcome isn't obvious say it in a word — "Add a task" explains that it creates a task linked to this one, "Capture a screenshot" says what is captured and where it goes, "Start a timer" warns that the clock starts immediately. A small plus marks rows that create something right away; an arrow marks rows that open another screen first — the same cue the new-task card uses. Where the window allows, the button that opens the menu is a labelled "Add" pill rather than an unlabelled ellipsis — an ellipsis promised leftovers and delivered the page's creation hub. On a task the menu never lists "Timer", since the bar's Track time button is that same action, and it no longer ends on a stray divider under a row that isn't there.

Changed: setting a category is now an offer, not a report. An uncategorized task led with a hollow checkbox-like square saying "No category" — the first thing on the page, describing an absence. It's gone; a dashed "Set category" chip now sits with "Set due date" and "Add estimate", and the breadcrumb appears once the task actually belongs somewhere. The chips themselves split into two tidy rows — what the task is (status, priority, set values), then what you can still add — instead of wrapping wherever the window edge happened to fall, and the priority chip gained the same little arrow the status chip has, so it reads as changeable. The dashed chips are also drawn more visibly in both themes — they were nearly invisible against a white page and, for low-vision users, effectively absent in dark mode.

Changed: the new-task card explains every row. Each of the four offers now carries one quiet line on what the tap does — the voice-note row says the recorder opens first and nothing records until you start it there — and the page's first tap eases the column out to its reading width instead of snapping it. The bottom bar keeps its full set of buttons throughout: Track time stays the filled primary, and the microphone, checklist and image buttons remain exactly where they always are.

Fixed: searching for a task to link no longer flickers as you type. Every keystroke in the Link existing task modal used to rebuild the list against a search that had not finished, so the modal briefly claimed "No tasks found", hid the offer to create the task you were describing, and then repopulated a moment later — resizing itself twice per character. The search now settles once, shortly after you stop typing: the results, the create row and the empty message appear together and describe the same search, and the last complete set of results stays on screen while the next one loads. A word typed quickly now costs a single database lookup rather than one per letter. Clearing the field still snaps back to the full list immediately, and pressing Enter waits for its own search rather than acting on the previous one.

Fixed: health imports no longer give up for the rest of the session. The first time an import hit an error — a data type this phone cannot read, a momentary failure in Apple Health or Health Connect — the queue feeding every health chart was left marked as busy and never ran again. From then on the dashboards' background imports stopped: charts went on showing whatever was already stored, no error appeared anywhere, and only restarting the app cleared it. A failing data type is now recorded and skipped, and everything queued behind it still imports. Workout imports had the same flaw and have the same fix.

Fixed: importing health data no longer flashes a permission sheet you cannot answer. Apple Health shows one authorization sheet at a time, and Lotti could ask for two at once — opening a dashboard starts a background import per chart while the Health Import page starts one on tap — so the second request replaced the first, and the sheet appeared and vanished before it could be read. Requests now go one at a time, and importing a family of data asks once rather than twice. On iPhone, tapping Import Activity Data also no longer raises an unrelated Location prompt in front of the Health sheet: those extra permissions are an Android requirement and are now only requested there.

Fixed: sleep charts count the whole night. Apple splits sleep into core, deep and REM, and the "Asleep" chart is the sum of the three. Core sleep — usually the largest part of a night — was matched against a name Apple no longer uses, so it was dropped, and the chart showed roughly half of what you actually slept. Re-import a date range to fill in the missing hours.

Fixed: a dashboard set up for a health type that no longer exists now says so. It previously imported nothing at all, in silence, which looked exactly like an import that was broken.

Changed: Settings → Advanced → Health Import was rebuilt. The old page was a column of differently-sized buttons that told you nothing: tapping one started an import that was never waited for, so a successful import, an empty one and an outright failure all looked identical — nothing happened. Each kind of data now has a row saying what it will bring in, and after a run the same row reports what actually happened: how many samples arrived, that there were none, that access was denied and where to grant it, or that the import failed. A row shows a spinner while it is working and cannot be started twice. The date range gained Last 7 / 30 / 90 days shortcuts and no longer defaults to an end date of tomorrow, and an Import all button runs every kind in turn. On desktop, where there is no health data to read, the page now says so instead of offering six buttons that quietly do nothing.

Fixed: the Add device QR code has a clearer edge for scanners. Its white margin was narrow enough that the outer QR modules looked almost clipped against the surrounding card. The code now has four more pixels of white space on every side, making its boundary easier for a camera to distinguish.

Fixed: adding a device no longer sends the same history over and over. During a full initial message transfer, the new device could mistake queued or in-flight history for missing data and repeatedly ask for it in batches, adding substantial duplicate work on slower phones. The two devices now coordinate that first full transfer before the new device logs in: automatic gap repair sends no early batch while the snapshot announcement is still on its way, and the final suppression check cannot race the durable request enqueue. Repair resumes immediately when the transfer finishes; choosing a partial transfer or closing either onboarding sheet releases the provisional hold, while a failed full transfer remains bounded to an hour. Manual recovery remains available throughout.

Added: a new task now tells you what to do next. Opening a task you have just created used to leave you with a "No title" label, a row of chips, and half a screen of nothing. The title is now a field you land in with the cursor already blinking, asking you to name the task — press Return to save it — and below it a short card offers the four things a task usually needs next: write a note, add a checklist, record a voice note, assign an agent. They are worded rows rather than unlabelled glyphs in the bottom bar, and while the card is up the bar drops the buttons that would say the same thing twice. The card disappears the moment the task has any content, and the whole page is composed in the window rather than stacked at the top of an empty one.

Fixed: the task page no longer offers to link a task when there is nothing to link to. On a fresh install the Linked Tasks card explained blockers, follow-ups and duplicates to someone who had exactly one task and could not link it to anything. It now stays away until a second task exists, and its explanation is one short line rather than three.

Fixed: task detail buttons are visible again. The action bar's Track time, microphone and menu buttons rendered as heavy dark slabs in light mode; they now read as light chips on the glass strip, with Track time carrying the accent as the bar's single primary. The overflow menu at the top of the page was near-invisible in both themes and is now legible. The knowledge-graph icon beside it is desktop-only — the graph needs a wide window to be usable.

Fixed: unset task chips ask for what they need. They were set in italics, which read as unavailable rather than empty and was hard to read at large text sizes, and they were worded as statements — "No due date" describes the task rather than offering to fix it. They now read "Set due date" and "Add estimate", upright, and a value you have actually chosen is inked more strongly than one you have not. On a phone the due date also dropped to a second row while half the first row sat empty; status, priority and due date now share the first row.

Fixed: task priority icons use the right colours in light mode. The priority glyph carried the dark theme's palette regardless of theme, and the Open status ring was drawn at a third of its intended strength.

Added: Daily OS has a Today button. Once you step off today, a Today button appears beside the date arrows and takes you straight back. Returning previously meant either opening the date picker or knowing that a long press on the date did it. On today itself the button is not shown, since there is nowhere to return to, and it also stays away when the window is too narrow to hold it beside the date — a phone, or a desktop window with a wide sidebar. There, tapping the date opens Lotti's own date sheet, which carries a Today shortcut of its own.

Fixed: stepping through days in Daily OS no longer moves the arrow you are clicking. The date between the arrows was only as wide as the day it showed, so a shorter or longer date moved the forward arrow out from under the pointer and walking through a week meant re-aiming at every step. The date now sits in a fixed slot wide enough for the longest date your language can produce, so both arrows stay put. The slot is measured, not fixed in pixels, so it still fits when you increase the text size. Where the window is too narrow for one line, day navigation now takes a line of its own — it previously shared the top line with the filter and menu buttons, which squeezed the date until it was cut off mid-word — and a narrow window drops the year, the least useful part of the date while stepping between nearby days.

Fixed: Daily OS stays in the view you chose while you move between days. Whatever you had open — Day, Agenda or Activity — was thrown away and replaced by that day's default view every time you stepped to another date, which made reading the same view across a run of days impossible. The view now changes only when you change it. Starting the app still opens on the usual view for the day.

Changed: the recovery actions on Backfill sync take the standard in-card button size. The buttons under Advanced recovery were one size up from what the design system prescribes for actions living inside a card, so each one out-weighed the title and description it belongs to; they now match comparable in-card actions across the app.

Changed: the morning briefing is prepared once, not once per device. Every device signed in to the same account woke up and produced its own copy of the same daily briefing, so a laptop, a phone and a tablet meant three AI calls billed for one result, every morning, forever. Devices signed in to sync now agree among themselves which one prepares it, using the record they already share rather than anything new. If the chosen device goes away before it starts, another takes the window over about half an hour later. A device with no sync identity of its own has no one to coordinate with and still prepares its own.

Changed: the assistant's own working notes are now tidied away too. As it works, an assistant writes private notes to itself about what it just did. Those were kept forever, and on a long-lived assistant they became the fastest-growing thing in the database. Notes older than six months are now cleared out, oldest first where they can be, and never leaving a gap in the middle — the assistant's memory of what happened stays readable rather than developing holes. Kept regardless: its summaries, the note it is working from right now, anything it flagged as a complaint or a piece of praise worth revisiting, and anything you wrote.

Changed: old day-status records stop piling up. These are the running record of how each day was going, raised several times a day and kept indefinitely, so the database grew every month with nothing ever released. The full record is now kept for about ninety days — longer if the morning briefing has not read it yet, since nothing is cleared before then — and older days keep only their final status, which is what the app shows when you scroll back to them. Space already taken on disk is reused for new data rather than handed back, so the file stops growing rather than shrinking. Nothing you wrote is ever affected: check-ins, plans, day summaries, directives, saved knowledge, reports and personalities are kept for good, as are weekly totals, your run history and ratings, and the record behind every suggestion you accepted or rejected. Tidying runs in the background after start-up and can be interrupted safely.

Fixed: assistants for past days stop waking up. Daily OS gives each day its own assistant. Those were never stood down, so every day you had ever used still counted as live: they were all reloaded each time the app started, and any one of them left holding a scheduled time could wake and think again — spending model calls on days that were long finished. A day's assistant now stays active for that day and the morning after, so it can pass anything unfinished to the planner, and then retires. Those days stay readable; their assistant simply does not think again on its own.

Added: a failed planning step now says so on the day it happened. When Daily OS could not draft or update a plan, or could not read a check-in, it failed in silence: no notification arrived, and the day showed no sign anything had gone wrong. Work that has stopped now appears in that day's Activity timeline, saying in plain words which step did not finish and why — the model could not complete it, no planning model is set up, there is no plan to update yet, or it is waiting for the network — and offering Retry in place. Retrying puts the work back in flight and the entry disappears. Network waits also resume on their own once you are back online. Steps still running are not listed; the plan itself already shows those. Failed drafts and updates now raise the notification they were always meant to.

Fixed: deleting an agent now deletes its files too. Everything an assistant syncs is also written to a file on disk so other devices can fetch it. Nothing ever removed those: deleting an assistant cleared its data from the database and left the files behind, still readable, and disk use tracked everything ever synced rather than what you still had. Deleting an assistant — and the background tidying of old day-status records — now removes the matching files as well, as far as the system allows: a file the app cannot reach at that moment is left alone rather than failing the deletion.

Fixed: weekly totals stop changing on their own. Daily OS pools each past week's planned and recorded minutes into a shared summary the morning briefing reads. Recorded time was bucketed into weeks using the calendar of whichever device was doing the summing, so a laptop and a phone in different timezones — or one device carried across them — computed different totals for the same finished week and kept overwriting each other's answer. Recorded time is now bucketed by the clock of the device that recorded it: an hour worked at 9am in Tokyo counts to that Tokyo week everywhere. Past weeks are re-summed under the new rule as they come back into range.

Fixed: habit reminders schedule again on macOS. Ticking off a habit recorded it, but arming the next reminder failed, so no follow-up notification was scheduled. The failure was also reported as though the completion itself had failed, which skipped the confirmation toast and replayed the celebration animation a second time once the row caught up.

Fixed: the translated manual catches up with the English one. Three sections existed only in English — letting a task agent suggest labels, choosing a task agent's AI setup, and dictating useful context into a recording — and now appear in the German, French, Spanish, Czech, Romanian, and Portuguese manuals too. The Romanian welcome page was an outdated copy missing its screenshot and opening section; it is now the current page. The Danish and Swedish manuals had left nearly every screenshot description in English — those are now translated — and the Italian and Dutch manuals lose their machine-translation artifacts: garbled sentences, mistranslations, and formal address where the app speaks informally.

Fixed: the morning briefing plans the day you came back on, not the day you left. Daily OS arms its next morning digest ahead of time, tagged with the day it was meant to run. If the device was asleep, offline, or the app simply was not running through that slot, the digest still fired later carrying the old day — so after a weekend away it would reason about, and issue plans for, a day that was already over. A digest now anchors to the day it actually runs on. Windows missed while you were away collapse into that single catch-up run rather than replaying one briefing per skipped day, and it still reads everything that happened since the last briefing it finished. If none ever finished — a new install, or a run of failures — it reaches back about two days rather than to the beginning.

Fixed: confirmation buttons stop shouting. Destructive confirmations — deleting a database, removing a device from sync, unlinking a task, discarding a recording — rendered their confirm action in all-capitals, unlike anything else in the app, and the built-in fallback labels were hardcoded English. Confirm actions now read in normal sentence case in every language, a dialog that does not name its own Cancel gets the localized one, and several broken translations hiding in the shouting were repaired along the way.

Fixed: a briefing interrupted by a crash is retried the same day. If Lotti was killed, or the device shut down, while the morning briefing was being written, that briefing was not just unfinished — it was skipped entirely, and the next one arrived the following morning. The interrupted run is now picked up the next time you open the app that day. A briefing that did finish is never redone, so this costs nothing when nothing went wrong.

Fixed: creating your first task no longer asks to send you notifications. Notifications are switched off until you turn them on in Settings, yet the first task you created on a new Mac or iPhone raised the system "Lotti would like to send you notifications" dialog anyway — asking for a permission the app had no intention of using. Lotti now checks the setting before it asks for anything, so with notifications off the dialog never appears — and when you do switch them on, it asks once, right then. Switching them back off takes the task count off the app icon straight away, instead of leaving it there until you next write something.

Fixed: a task's header says which of the two things above it is missing. The line above a task's title names its category and its project, and with neither set it read "unassigned / No project" — a lowercase word that never said what was unassigned, in a different capitalization from the words beside it. It now reads "No category". A project belongs to a category, so until one is picked there is no project to choose either: the separator and the "No project" placeholder now stay away until the category is set, instead of offering a choice that could not be made.

Fixed: moving a task to another category no longer leaves its old project on it. A project belongs to one category, and a task can only be put into a project from its own — but changing the task's category afterwards left the old project attached, so the task went on showing a project from a category it was no longer in. Changing the category now takes the task out of a project that does not belong to it. Re-picking the category it is already in changes nothing, and clearing the category removes the project too, since there is no way to pick one without a category.

Changed: the habits tab and consistency heatmap open faster. Loading habit completions pulled the full stored record for every completion in range — including the whole entry payload — when only three fields were ever used. The read now fetches just those, so the habits tab and the heatmap spend less time waiting on the database and less time decoding what they discard.

Fixed: agent startup no longer floods diagnostic storage when its database has already shut down. Runtime restoration bulk-loads the required state and links, then aborts the pass with one diagnostic if that snapshot fails instead of querying and logging once for every persisted agent. Incomplete restoration remains failed and retryable rather than silently succeeding.

Fixed: a repeated interface failure no longer fills diagnostic storage with thousands of identical stack traces. Lotti keeps the first complete framework error and then records bounded, counted summaries for repeats, including short bursts that stop; errors from different call sites or widget contexts still retain their own full diagnostics.

Fixed: weekly planning history from earlier builds opens and syncs again. Some saved weekly rollups omitted their start-of-week date, making otherwise valid planning history unreadable. Lotti now restores the date from the rollup's canonical Monday key; irreparable remote records are ignored without blocking later sync.

Fixed: deleting an entry no longer traps an otherwise healthy sync batch in retries. Bundled sends mistook a soft-deleted entry for a missing database row, retried every valid sibling with it, and eventually left the whole batch as failed. Deletion tombstones now travel in the bundle like every other journal update.

Fixed: detailed sync diagnostics stay useful without growing by tens of megabytes a day. Repetitive per-record bookkeeping is represented by counted samples, with separate totals for inserted versus merged outbox work and sequence writes versus duplicate skips. Gap detections, actual backfill requests, retries and errors remain complete so initial-sync and repair work can still be investigated.

Changed: the task-list header gets out of the way while you read. On a small phone the Tasks header — title, search field, saved-filter rail and active filter chips — took up to half the screen before the first task appeared. Scrolling down now folds it into a slim bar with the title and two buttons, so the reclaimed space shows two to three more tasks; a deliberate upward scroll (or a tap on the bar's title) brings the full header back. The same fold applies wherever the list is narrow, including the desktop split view's list pane. The slim bar still says what is narrowing the list: an ad-hoc filter is named as a count of its clauses, an active saved view shows its name next to the title, and an active search shows the query in quotes. Typed search text survives the fold, a list too short to scroll never collapses, and with reduced motion enabled the switch is instant instead of animated.

Changed: an unfiltered task list no longer wears chips. The chip row used to echo the default status set (Open, Groomed, In Progress) as removable chips even when nothing was narrowed, making the resting view look filtered. Status chips now appear only when the selection deviates from the default open-work view, and once two or more things are narrowing the list — clauses, the search query, or both — the row ends with a "Clear all" chip that restores the default open-work view and clears the query. The saved-filters button in the mobile rail also dropped its saved-filter count, which read as "1 filter is active" on an unfiltered list — numbers in the header now consistently mean how much the list is narrowed.

Changed: the saved-views button is called Views. It opens saved views, but it was labelled "Filters" — sitting directly beside the funnel that opens the actual filters, so the two most-used controls in the header shared a name and led to different places.

Changed: colour in the filter chips means what the chip means. Every active filter chip sat on the same tinted plate regardless of what it stood for, so a red P0 priority chip was drawn on a green background. The plate is now neutral and the chip's own colour carries the meaning.

Fixed: an ad-hoc filter keeps its name on a narrow screen. On a 375-point phone the "Custom" pill was squeezed until only its task count was left, so the one control naming your current filter showed a bare number. The save affordance now yields its label first.

Fixed: the "no tasks match" message no longer sticks to the screen edge. When the Tasks list's empty-state message wrapped to a second line — a longer language such as German, or a larger system text size — it was laid out across the full width of the screen, flush against the left edge with no margin. It now uses the same centered, inset empty-state treatment as the Logbook, with the tasks glyph above it.

Fixed: planning after your working day has ended now finishes instead of retrying an impossible answer. Daily OS was told to add no blocks once the planning window closed, but its required final step rejected an empty plan. It can now save an explicit empty draft, keep any existing blocks intact, and surface selected work that no longer fits instead of looping until the request fails.

Fixed: Daily OS plans stay inside your configured working hours. On an overloaded day, the planner could keep the total duration under your capacity by leaving a gap and then scheduling the final task after your working day ended. Plans outside the configured window are now rejected and retried, so work must be shortened or omitted explicitly instead of quietly overrunning.

Changed: the Matrix Stats page reads as one page again. Its headings had been set by hand and disagreed with each other — "Sent messages" shouted while "Top KPIs" was left at whatever size it inherited — so the page looked like three unrelated panels stacked together. Every group heading now sits at the same level, the counter tiles share one rhythm, and the numbers on them line up with the figures on Backfill sync.

Fixed: assistant proposals are in your language. Every suggested change — set a title, change a status, add a checklist item, log a time entry, link two tasks — was written in English at the moment the assistant thought of it, and then shown to you in English no matter what language the rest of the app was in. Those rows are now composed as you read them, so they appear in your own language, with the relationship between two tasks phrased properly rather than pasted together word by word. Suggestions your device does not recognise — from a newer version, say — still show their original wording rather than nothing at all.

Fixed: the German and Spanish relationship pickers say the direction they mean. Offering to link two tasks, the German dropdown read "Duplikat von" — "duplicate of" — for the direction that actually records the opposite: the current task being duplicated by the chosen one. Spanish had the same problem with follow-ups, where "Tiene seguimiento de" reads as tracking the other task rather than gaining it as a follow-up. They now read "Wird dupliziert von" and "Tiene como seguimiento", matching what picking them does.

Fixed: the sync diagnostics panel is translated. Its heading, its refresh button and its "Last ignored" list stayed English on every device, whatever language the rest of the app was set to.

Fixed: the sync statistics counters say the right thing in five more languages. "DB Missing Base" counts entries held back waiting on a record that has not arrived yet, but the Spanish, French and Romanian translations said the database is missing — contradicting the legend on the very same panel — and the Italian and Dutch ones stacked the words in an order that read as neither. The Romanian buttons on that page also addressed you informally, unlike the rest of the app.

Fixed: the refresh button on Backfill sync is easier to hit, and says what it is. It was a 16-pixel icon with barely any room around it — a 24-point target, half the size a finger needs — so on a phone it took an accurate tap. The icon is unchanged, but the button now occupies a full touch target, which makes the header of that card taller. Screen readers also named it without ever saying it was a button.

Fixed: the privacy policy described device pairing incorrectly. It stated that encryption keys are exchanged via the QR code and never transmitted over the network. Neither half was true: the QR code carries your sync account credentials, while the encryption keys travel between devices over the homeserver — encrypted, and only to devices you have emoji-verified. The practical consequence had gone unsaid too: anyone who photographs the pairing code can sign in to your sync account and lock you out, even though they still cannot read your entries. The policy now says all of this, in the same words the manual already used.

Fixed: the privacy policy promised a data export that does not exist. It offered to export your data at any time. There is no such feature, and none is needed: your logbook is an ordinary SQLite file on your own disk that any SQLite client can read. The policy now explains how to take a consistent copy and where the attachments live, rather than pointing at a button that was never there.

Fixed: reporting a security vulnerability no longer starts by publishing it. The security policy asked for vulnerability reports in the public issue tracker, which the contributing guide separately tells you not to do, and which exposes everyone running Lotti before a fix exists. Reports now go through GitHub's private vulnerability reporting.

Changed: the app description says what Lotti actually tracks. It now mentions that AI usage is recorded per category and model — tokens and requests for every cloud call, and cost, energy and CO2e wherever the provider reports them — and that planning and time recording stay separate so intent and outcome remain distinct facts. It no longer describes third-party providers as GDPR-compliant, because that is their claim to make rather than Lotti's, and no longer lists time recording twice.

Fixed: the documentation no longer promises impact figures every provider can supply. The README and privacy policy described cost, energy and CO2e as recorded for every AI call. Only providers that return those numbers with the response are measured — today Melious — while everyone else contributes token counts and leaves the rest empty rather than estimated. Local inference is not measured at all. The same pages also described a just-in-time notice naming the provider before each AI feature runs, which does not exist: routing is chosen in settings, and once a category is configured its work can reach that provider without a further prompt.

Fixed: the documentation stops calling a freshly paired device a backup. Pairing gives a new device everything written from then on, but existing settings and earlier entries arrive only when "Send settings" and "Send message history" are run from a device that has them. Describing every paired device as a complete replica could have led someone to retire their only full copy. The docs now say what pairing does and does not carry, and no longer describe the journal as an append-only log — editing an entry overwrites it rather than adding a version.

Fixed: the Italian theming settings were labelled "Il nome" ("The name"). The entry and its logging domain now read "Tema", with the standard "Aspetto scuro" and "Aspetto chiaro" mode labels. The garbled Dutch and Swedish light-mode labels now read "Licht uiterlijk" and "Ljust utseende".

Added: the manual keeps every released version readable. Its version dropdown lists each published release next to Development, every release keeps its exact pages and screenshots permanently, and the manual's front door leads to the newest release once one exists. Older manuals also learn about releases published after them.

Added: models can be removed right where a provider lists them. A provider's detail page shows its models and offers "Add model", but taking one away meant switching to the Models tab and finding the same model again in the full list. Each model row on the provider page now carries a small trash action; a tap asks for confirmation and then removes the model, with the same brief undo window available for deletions elsewhere in the app.

Fixed: a confirm button no longer disappears when its label is long. The buttons at the bottom of a dialog were placed side by side or stacked according to how wide the screen was, without ever measuring the buttons themselves. A longer translation — German and Romanian most often — therefore still counted as fitting on a phone: the confirm button was squeezed down to nothing and a striped overflow warning ran across the footer, leaving the dialog with no visible way to confirm it. Dialog footers now measure the actual buttons and give each its own line as soon as they stop fitting side by side.

Fixed: Lotti installs on older iPhones and iPads again. The app had come to require iOS 17, which left devices that cannot be updated past iOS 15 — the iPhone 6s and the first-generation iPhone SE among them — unable to install it at all. Nothing in the app actually needed iOS 17: the requirement arrived with a speech feature that was removed from iOS shortly afterwards, and was never lowered again. Lotti now asks for iOS 15.8, the last iOS 15 release, so those devices are supported once more as long as they are fully up to date.

Changed: core screens now fit the smallest supported phones. Agent wake rows, AI usage figures, Daily OS planning and refinement, speech transcripts, session ratings, and What's New no longer overflow or cut off their controls at the original iPhone SE's 320 × 568 layout size. Short forms and planning panels scroll when necessary, while compact rows wrap or shorten safely.

Changed: sync lists line up with the rest of the app on narrow phones. The Sync Conflicts and Outbox pages gave their lists a one-off side margin on screens narrower than most phones; they now use the same spacing step as every other list, so the two pages no longer sit two pixels tighter than their neighbours.

Fixed: transcription now counts towards your AI usage figures. When a recording was transcribed by a Melious speech model, the cost and the energy, carbon and water it used were reported by the provider and then thrown away — so the AI usage charts showed transcription as free, and every total that included it was short. Those figures are now recorded like any other AI call.

Changed: older sync maintenance screens now match the rest of the app. Rebuilding the search index and repairing the sequence log now use the shared progress treatment, while sync statistics and this-device profile settings use the same cards, fields, rows, spacing, colors, and type as newer screens.

Changed: sync filters now match the rest of the app. The Waiting, Failed, Sent, Unresolved, and Resolved controls on Sync Outbox and Sync Conflicts now use the shared design-system chip and count treatments, with consistent selected, hover, pressed, light, and dark states.

Changed: the sync screens sit on the app's own spacing and type scales. A handful of sizes on these pages had been picked by hand rather than taken from the app's scales, so they drifted from everything around them: the device glyph on each card in the device list was slightly undersized, the figures on Backfill sync were a shade lighter than comparable numbers elsewhere, the dotted leader lines between a label and its figure were faint enough to be hard to follow across the row, and the counter tiles in sync statistics were a little taller than wide for the same padding. All four now match the rest of the app.

Changed: the "More" menu at the bottom of the phone screen is no longer cramped. Its rows were sized to the bare minimum a finger needs, so the destinations stacked up against each other with the icons almost filling each row. Each row now has room around it, and the list keeps an even rhythm from top to bottom.

Fixed: the app no longer asks for the microphone the moment it starts. On a fresh install, Lotti asked to record audio while you were still looking at your task list, before you had asked it to record anything. The app was checking whether it already had the permission, purely to write the answer to its log, and on Android and iOS that check is the request. The check is gone: the microphone is only ever asked for when you start a recording.

Changed: Daily OS planning now gives up on stalled or overlong AI responses sooner. Cut-off answers no longer save partial plans; planning retries cleanly instead.

Changed: Daily OS planning stays fast as retained history grows. Current-day scheduling and agent wakes now use bounded database lookups instead of walking older processing jobs or captures.

Changed: Daily OS is opt-in again while its planning quality is improved. Existing installs that had enabled it keep that choice, while new installs start without the Daily OS navigation entry. It can be enabled explicitly from Settings → Advanced → Config flags.

Changed: repairing agent sync data has its own place, and runs when it matters. The "choose what to sync" list mixed two unrelated things — settings to send, and a repair for agent items saved without the marker other devices use to put them in order. The repair now lives under Sync Settings, Backfill sync, and also runs automatically just before sending message history, so it no longer depends on having sent settings first.

Changed: the sync screens follow the app's own button and layout rules again. On the Devices page the "Add device" button is no longer an oversized bright pill, "Stop syncing this device" lines up with the cards above it instead of sitting indented, the "This device" marker no longer outshouts everything around it, and the two dates on each device card are the same size. In "choose what to sync", the list was centred, which made shorter labels look nested under longer ones; it now uses the same full-row selection pattern as category pickers, with labels on the left and checkboxes on the right. Confirm buttons across the sync and maintenance dialogs no longer shout in capitals or stretch the full width.

Fixed: the bottom navigation bar no longer collides with Android's system buttons. On phones that show the recents/home/back bar at the bottom — Samsung devices among them — the app's own bar sat partly underneath it, so its labels were crowded and taps near the bottom went to the system bar instead of the app. The bar now keeps clear of the whole system area.

Changed: the "Enable Sync Actor" setting is gone. The advanced-settings toggle never did anything — the isolate-based sync it was meant to switch on was never finished or connected — so it is removed rather than left as a switch with nothing behind it.

Changed: the sync statistics legend moved onto the panel it explains. The "Legend" button in the sync statistics view did nothing when tapped — the explanations of each counter only ever appeared as a hover tooltip, so on a phone they could not be reached at all. The button is gone, and the explanations now sit on the heading directly above the counters, where a tap shows them.

Fixed: the sync statistics panel no longer shows counters that never move. Most of what it displayed — processed messages, failures, catch-up batches, retries, circuit breaker trips and the signal counters — had stopped being recorded when sync was rebuilt, so they sat at zero forever and made a healthy sync look idle. Those rows are gone. The headline figures are now what was written to the database, how many conflicts were logged, and how much is still waiting to be applied.

Fixed: a photo or recording that never arrived now repairs itself. If a device ended up holding an entry whose image or audio file it never received, that file stayed missing forever — nothing noticed, and only re-sending your whole history could fix it. Devices now ask each other for the specific files they are missing, and any device that has one sends it back. No action needed, and nothing is asked for repeatedly if no device still has the file.

Fixed: photos and audio now reach a device you sync your history to. Sending your existing entries to a newly set up device — from sync maintenance, or automatically when a device noticed it was missing entries — transferred the text of every entry but none of the images or recordings, leaving the new device with photo and audio entries it could not open. Only entries created after the device joined arrived complete. History transfers now carry the media with the entry.

Fixed: a cancelled device verification no longer claims to have succeeded. When the other device refused or cancelled the emoji check, this one showed the green shield and "You've successfully verified…" anyway — on the outgoing screen, next to the cancellation notice at the same time. The two devices had not verified each other, and nothing said so. Cancelled and failed ceremonies now say they were cancelled, and only a real success shows the shield.

Fixed: leaving an AI setting takes one back tap, not two. After opening a provider, model or profile from AI Settings, backing out of the list you returned to appeared to do nothing: the list slid away and an identical list slid straight back in, and only a second tap actually left. Coming back from a detail page had quietly left the app in a halfway state that still showed the list, so the next tap was spent leaving that rather than going anywhere. Back now moves one level per tap, and the Inference Profiles page animates like a back gesture instead of like opening a new page.

Changed: planning the rest of today is faster and listens to the whole check-in. Capture parsing and drafting now stay focused on the one artifact each step must produce, stop as soon as that artifact is saved, and immediately pick up a capture that arrived while background processing was already running. This removes avoidable AI round trips that could make planning take about a minute, while preserving separate time constraints, breaks and explicit overcommit trade-offs from dense spoken plans.

Fixed: an over-full day no longer wastes a planning attempt on an impossible placeholder. When some work did not fit, the planner could represent the omitted task as a zero-minute "unscheduled" block. The app correctly rejected that block, but only after spending the first model response. The planner is now told to name omitted work in its reasons or status note instead.

Fixed: a plan no longer treats work of unknown length as free. When deciding what fits in a day, the planner is now shown how long each task you approved is expected to take — it previously had to find that elsewhere, and on many plans could not see it at all, so it packed in more than the day held. Tasks with no estimate are marked as unsized rather than counted as taking no time.

Fixed: saying "nothing to do today" no longer fails. When you spoke a note with nothing actionable in it, the assistant worked that out correctly and then had no way to say so — the app rejected the answer, and it had to either invent a task or try again. It can now record that a note held nothing, which also clears anything it had wrongly picked out of that note earlier.

Changed: encryption keys are never shared with unverified devices — and sync never stops for them. Keys now go only to devices you have emoji-verified; an unverified device receives ciphertext it cannot read. Until now one unverified device — typically a dead session left by an uninstalled app — silently stopped all syncing on every device until it was removed. Now everyone you trust keeps syncing, the device list warns that the unverified device can't read new entries, and verifying or removing it is a calm cleanup step instead of an emergency.

Added: see and manage every device in your sync account. The sync status page now lists all sessions — not just unverified ones — with a "This device" marker, Verified/Unverified chips, when the server last saw each device, and a hint when a device has been silent long enough to be presumed dead. Sessions signed in with this account can be removed — except the one you're on — including previously verified ones. Devices paired the old way, each with its own separate account, can be verified but not removed. While any device is excluded from sync, the list says so in plain words.

Fixed: sync finishes catching up after a large or still-growing backlog. A reconnect could spend its recovery allowance following the newest messages, report that partial walk as complete, and leave the remaining entries missing with nothing queued to retry. Recovery now budgets the actual network work and automatically resumes whenever that allowance is reached. It also remembers the oldest unresolved encrypted message across restarts, so a newer applied message cannot move recovery past a gap that still needs its decryption key.

Fixed: the planner is told how much of the day is actually left. It knew your capacity and your working hours, but had to work out for itself how much time a mid-afternoon plan really had — and got it wrong, running plans past the end of the working day. It is now given the remaining minutes directly, and when the work on offer does not fit it is asked to say so rather than quietly shrinking everything until it appears to fit.

Fixed: the planner can no longer mark blocks as agreed on your behalf. A fresh plan could come back with blocks already marked committed — the state that means you approved this — so work you had never seen presented itself as settled, and uncommitting the day was the only way to undo it. Only you can commit a block now. A re-plan still carries forward blocks you already committed, unchanged.

Fixed: time on a task is credited to that task's area. A planned block could name a task from one area while being filed under another, so the day's per-area totals — and the weekly rollups built on them — quietly credited the wrong one. A block that names a task now always follows that task's area.

Added: tell the task assistant how tasks relate — in either direction. Saying "this task is blocked by X", "this supersedes the old migration task", or "this duplicates Y" now becomes a reviewable suggestion that records the actual relationship — blocks, follows up, duplicates, fixes, supersedes, or a plain link — between this task and an existing one. Both phrasings of a relationship work ("A blocks B" and "B is blocked by A" store the same edge), the blocked side shows up as blocked exactly as if the link were made by hand, and nothing is written until the suggestion is confirmed.

Changed: the linked-tasks card is a third shorter. The relationship headings ("Follows up on", "Has follow-up", …) floated in the middle of a large empty band instead of sitting with the tasks they label, and every linked task sat in a row a third taller than it needed to be, so a card with two links took up as much room as one with five. Each heading now sits close above its own rows, the rows themselves are tighter, and nothing moves when you switch the card into Manage mode.

Added: a spoken follow-up task can carry its relationship. "Create a follow-up task X that blocks this one" creates X and the blocking link in one confirmable suggestion, instead of a plain link that loses the "blocks" part. The assistant also sees how already-linked tasks relate to the current one, so it stops guessing parent/child roles from link direction and won't re-suggest a relationship that already exists.

Added: add a device from whichever device you have to hand. "Add device" is now an action on the device list itself, so the phone in your pocket can bring in the new laptop just as well as the other way round. The sheet shows the pairing code, tells you when the new device has actually joined, and keeps "Send settings" — for your categories, habits, dashboards and AI settings — within reach the whole time instead of below the code. Transfers unlock only after that exact new device completes emoji verification, when it can receive the encryption keys needed to read them. The sheet also says plainly what the code is: letting your own new device scan it is fine, keeping a screenshot or sending it through chat is not.

Added: send message history while adding a device. "Send message history" now sits beside "Send settings" on the existing device, where it can queue the local history the new device does not have yet. It defaults to everything, also offers the last 30 days or a custom range, and stays open with per-phase progress until the messages are queued.

Added: a machine with no camera can be brought in too. The typing screen now explains how to get the code across from the other device — copy it there, and move it the way you would a password — and says so instead of doing nothing when there is nothing on the clipboard to paste.

Changed: a device removal the server refuses can now be finished, not just reported. If the sync account's password was changed on another device, this one keeps syncing on its existing session but can no longer prove who it is when removing a device — and the attempt ended in a message telling you to go and do it somewhere else. It now asks for your current sync password and completes the removal on the spot, and tries to save that password so the next removal does not have to ask again.

Changed: verifying a device that looks dead warns you first. The emoji check needs the other device awake, online and showing Lotti. Starting one against a device the server has not heard from in weeks left you watching a screen that would never answer. Lotti now says so before opening it, and you can still go ahead.

Changed: the device list tells status and identity apart. A device with no encryption keys yet wears a quiet grey "Unverified" chip instead of borrowing the dress of the "This device" marker, and the Verify button beside a highlighted removal now carries the accent color instead of reading as Cancel.

Changed: sync cards sit on the app-wide card surface — same tone, same hairline border, no one-off shadow — so Devices no longer looks subtly foreign next to the pages around it.

Changed: setting up sync starts with a real first screen. Before anything is configured, the Devices page used to show a single row that repeated the menu entry you had just tapped, floating in an otherwise empty pane. It now says what sync is — your journal on every device you own, end-to-end encrypted, between your own devices only — with one Set up sync button.

Changed: the pairing QR code always renders whole. On a short window the pinned "Send settings" bar could slice the code in half — unscannable, and with nothing suggesting the rest was below. The QR and its check code now live in one pairing card that sizes itself to the window, so the two things the other device asks you to look at are always visible together — on phones too, where the pinned bar used to clip the check code.

Changed: every pairing screen has one clear next action. After a failed connection the highlighted button is now Enter a new code — a rejected code usually predates a password change on the account, which only a fresh code fixes, so retrying the identical code is the quiet option beside it, not the promoted one. While the emoji ceremony is still outstanding, the paired screen shows it as a numbered gate — confirm the emoji first, receive your settings after — with the locked step visibly locked, and the highlighted button reopens the ceremony.

Changed: the emoji verification ceremony matches the rest of the app. Same type, spacing and buttons as every other sheet. Cancel is no longer painted red — backing out of a ceremony is a safe, ordinary act — and the success shield uses the app's own green.

Changed: security warnings look like warnings again. The "only use a code you made yourself" and "treat this like your password" callouts had been muted to grey, quieter than the buttons next to them; they carry the warning color now. Destructive actions carry an icon as well as the red, so they never rely on color alone.

Changed: desktop stopped stretching phone buttons. "Add device" and the paste and connect actions size themselves to their labels instead of spanning the entire pane, and the devices panel keeps a readable width on wide windows.

Changed: the app has one look now. Every screen renders the design system's own theme — the same surfaces, type and accents the newer pages were built against — instead of a third-party color scheme with the design tokens bolted on top. Backgrounds, cards and accents finally agree across old and new screens, and the brief near-black flash while the app starts is gone.

Changed: the theme-scheme picker is gone. Theming settings kept a list of 22 color schemes, but as screens moved onto the design system the picker changed less and less of what you actually saw — on recent screens, nothing at all. What remains is the choice that still does something: light, dark, or follow the system, synced across devices as before.

Changed: pairing a device is a guided flow now, not a form. A three-station progress track — Get code, Check, Connect — draws where you are instead of narrating it, and every screen leads with the one thing to do there. On phones the camera opens straight away, with accent brackets framing where the code should land, and pasting is the fallback rather than the other way round. The check step makes the comparison the whole screen: the code your other device shows, large, with "Same code on both screens?" beneath it and the mismatch consequence riding on the decline button. Waiting is narrated by the journey's own figure — a phone and a laptop with dots streaming between them — and when the emoji match succeeds, the gap between the two machines closes into a solid line with a small celebration: your devices trust each other now, and the screen says exactly that.

Changed: nothing in the pairing flow waits forever without saying what to do. If the emoji check never appears, the last screen now tells you where to start it by hand instead of spinning indefinitely. If the camera cannot start, there is a way to try again once you have granted access. And if the device list cannot be reached while you are waiting for a new device to appear, it says so and offers a retry rather than pretending to still be looking.

Changed: the device list reads constructively. The roster now says how many devices are on which server, lays the cards out in two columns where the window affords it, and anchors each card on a device tile with its trust badges beneath the name. "Add device" is the page's one highlighted action, removing a healthy device is a quiet icon in its card's corner, and the stop-syncing and technical-details actions sit below their own divider at the very end. "Delete device" is now "Remove from sync", which is what it does, and a removal that the server refuses explains the situation instead of showing you the raw error.

Added: setting up your very first device has a real path. The "first device?" note used to end in "see the manual" with nothing to press; it now carries an Open the first-device guide button that lands directly on a new manual page — available in every manual language — explaining where the very first pairing code comes from and what to do with it.

Added: the hand-off no longer dies with the Add device sheet. If a new device joins and finishes its emoji ceremony while you are looking at the device list — say you closed the sheet too early — the list offers Send settings and Send message history right there, instead of leaving you to find the same transfers in Maintenance.

Fixed: an entry's time follows your device's clock. If your device is set to a 24-hour clock, an entry recorded at 21:54 said "9:54 PM" at the top of the entry — while the editor that opens when you tap it correctly said 21:54. The header only ever asked the app's language what a time looks like, never the device, so an English-language app was locked to AM/PM whatever the device was set to. Both now agree, in every language.

Fixed: the entry header no longer has a hole in the middle of it. The category button sat between the date and the rest of the buttons but belonged to neither, so the leftover width in the row collected on one side of it — a gap that grew with the window and, on a wide screen, left the category stranded in open space. Date on the left, every button together on the right, evenly spaced.

Fixed: the date at the top of an entry is no longer shouting. It sat at the same size as the app's own title text, and heavier than the body text beneath it, which made the timestamp the loudest thing on a card whose actual content sits underneath. It now sits one step down, on every screen — including the narrow phone layout that splits the date over two lines.

Fixed: times in your day plan follow your device's clock. If your device is set to a 24-hour clock, a block running 14:30–16:05 still read "2:30 PM–4:05 PM" on the agenda card and in the block editor. The app only ever asked its own language what a time looks like, never the device, so an English-language app was locked to AM/PM whatever the device was set to. It now asks both.

Fixed: a block shows the same time wherever you look at it. The plan list in Refine used a different clock from the rest of Daily OS, so one and the same block could read "2:30 PM" on the agenda and "14:30" while you were talking about changing it — on every device, in every language. Both now agree.

Fixed: an event's times follow your device's clock too. The date under an event title, every time down its timeline, and the end of a recorded session were all fixed to a 24-hour clock, so an event at half past two read "14:30" even on a device set to AM/PM. They now read the way the rest of your device does.

Fixed: chart tooltips are readable in your language and on your clock. The date in a chart's tooltip was always in English — "Mar 15" whatever language the app was in — and its time was always 24-hour. Both now follow the app's language and the device's clock setting.

Fixed: the blocks on your day's timeline read on your clock. Every block showed its span as "14:30–16:05" regardless of the device — and the proposed change describing that same block used a 12-hour clock instead, so the two disagreed. Blocks and proposals now both follow your device. The hour scale down the side of the timeline stays 24-hour: it is a ruler, and its end-of-day mark has no unambiguous 12-hour spelling.

Fixed: switching Time Analysis to Day shows today. Choosing Day took you to the first day of whatever you were looking at — January 1st from the year view, the 1st of the month from a month — so the page you landed on was almost never the one you wanted. It now opens on today whenever the period you are in still includes it. Looking at a past period still keeps your place there rather than jumping you back to today.

Fixed: the date picker in Time Analysis no longer changes size as you browse. Months need five or six rows of dates depending on their length and which weekday they start on, and the card grew and shrank to match — so paging through months moved the arrows out from under the pointer. The card now reserves room for the longest month and keeps one height throughout.

Fixed: removing a dead device now unblocks sync immediately. Deleting a device from the sync device list refreshes the cached device keys and nudges the pipeline right away, so the remaining devices resume syncing without an app restart. Deleting also asks for confirmation first — it signs the device out of the sync account — and a rejected password now gets a clear explanation instead of a raw error dump.

Fixed: sync no longer loses messages that arrive before their decryption key. When a lot of entries arrived at once over a slow connection, some could be discarded while the app was still waiting for the key to decrypt them, leaving that device permanently short of entries the other device had.

Fixed: a screen reader can now activate the whole "Automatic updates" row. Tapping the wording flipped the switch for everyone else, but assistive technology could only reach the switch itself.

Fixed: the update section at the bottom of the AI summary card takes up much less room, especially on a phone. The switch row in particular had far more space above and below it than it needed, which pushed the model line down and made the settings area compete with the summary itself.

Fixed: event and project assistants show up right away too. Creating an event or a project with an assistant left its card empty for several seconds before the assistant appeared — the same delay tasks had, from the same cause. It now appears as the page opens.

Added: decide per area whether assistants keep themselves up to date. New tasks in an area got an assistant that only ever updated when you asked it to, and turning that on was a per-task chore. Areas with an agent template now carry a "Wake the assistant automatically" switch that decides what new tasks start with. It is separate from the area's automatic-AI switch on purpose — transcription and image analysis keep running whether or not assistants update themselves. The switch applies to tasks created after you flip it; tasks you already have keep whatever their own switch says, so nothing you set by hand gets overwritten.

Fixed: the update section at the bottom of the AI summary card now reads as its own band in dark mode. Its tint was mixed the wrong way for a dark background, so it was all but invisible against the card.

Changed: the AI summary card's update controls read as two clear groups — "is this current, and can I refresh it now" on the left, "does it update itself, and when next" on the right, where the countdown belongs to the switch it comes from. The manual button is deliberately quieter than "Confirm all" above it.

Changed: cancelling one scheduled update is now "Skip once", and model names shorten by dropping whole parts ("Qwen 3.5 Plus · Alibaba · via Melious.ai" to "Qwen 3.5 Plus · Melious.ai" to "Qwen 3.5 Plus") instead of cutting words mid-name.

Fixed: planning a day that has already started no longer wastes a round trip. When you asked for a plan mid-afternoon, the planner would sensibly start your first block "now" — and the app rejected the whole plan for starting in the past, because by the time the plan came back, "now" had moved on. The planner had no way to win: it would have had to predict how long it was going to think. It is now told a start time that is still valid when the plan lands, so the first attempt succeeds instead of the second.

Fixed: day plans stop scheduling work that is waiting on something else. When the planner drafted a day without a voice note to work from — a scheduled draft, or the "plan my day" button on its own — it was told to respect blocked tasks but never shown which tasks were blocked, so it would place blocked work as if it were ready. Blocked tasks now arrive with their status and what they are waiting on, and the planner either schedules the blocker first or leaves the blocked task out and says why.

Fixed: every row in the update section starts on the same edge, including on a phone and in longer languages, and the card keeps the same bottom margin whether or not the report attribution line is showing.

Fixed: choosing your own model no longer switches off automatic transcription and image analysis. Picking a model by hand for a task's assistant replaced the whole AI setup, not just the thinking model, so the category's automatic transcription and image analysis quietly stopped — and picking a different model afterwards never brought them back. Each of them now falls back to the profile the task inherits from its category, so they keep using the category's transcription and image models while your chosen model handles the thinking. A profile you picked for a task still wins every capability it actually configures; only a missing one falls through. This also fixes tasks created before their category had an AI profile, which never picked one up.

Fixed: a new task gets its assistant right away. Creating a task in a category with an agent template left the AI card empty for several seconds before the assistant appeared, which looked like assignment had failed and led people to add one by hand. The assistant was in fact created immediately — the card just had no way of hearing about it until the first update finished running. It now appears as the task opens.

Changed: the AI summary card's bottom section is simpler and works on a phone. The update controls no longer sit in a box inside a box, so the strip reads as one quiet band and stops running out of room on narrow screens or in longer languages. As space gets tight the countdown shortens its wording rather than cutting off the time itself.

Changed: "Wake agent" is now "Update now", the summary states "Up to date" or "Out of date" in words rather than only as a coloured icon, and cancelling a scheduled update is a labelled "Skip" instead of an unmarked cross.

Fixed: ticking off a checklist item no longer looks broken as the row leaves. With the Open filter on, a checked item's row shrank away but its checkbox stayed full size and got sliced in half by the shrinking row, while the rest of the row jumped sideways the instant the animation began. The row now shrinks as a single piece — checkbox, text and buttons together — and fades out smoothly.

Fixed: your day plan can no longer contain tasks from categories the day agent is not allowed to see. The list of tasks a plan was permitted to reference came from the agent's own request without being checked, so a task from any category — or one that had been deleted, or never existed — could be attached to a block just by naming it. Task references are now resolved against your journal and filtered by category, as every other task reference already was.

Fixed: no more phantom calendar entries in your day. Day plans could include blocks marked as imported calendar events, which the app then refused to let you edit, telling you to change them in the source calendar where they did not exist either. The day agent is never shown your calendar, so it can no longer claim an event came from one.

Fixed: nothing gets planned into the part of today that has already passed. A block could still be placed in the past by marking it as already committed; only genuinely started, finished, or dropped work may sit earlier than the current time.

Fixed: you can trigger an update at any time again. While an automatic update was scheduled the manual button disappeared entirely, so the only way to run the agent by hand was to cancel the countdown first.

Fixed: the report attribution line no longer breaks mid-sentence, and hover highlights in the AI summary card no longer stretch across the whole card.

Fixed: a soul's history no longer blinks while it updates. On a soul's version history and evolution history, any change to that soul — an edit, a finished ritual session, a sync arriving — swapped the list you were reading for a loading spinner and back, collapsing the section and shifting the rest of the page. Those lists now stay on screen while they update. The same applies to an agent template's reports list.

Fixed: answering a task suggestion no longer jumps the page. Checklist suggestions already stayed put, but the others did not. Accepting or dismissing a due-date, language, priority, label or estimate suggestion while you had scrolled past the assistant card yanked whatever you were reading upwards, because the answered row's card shrinks as it collapses and nothing was holding the content below it in place. Accepting a follow-up task moved the page too, and could move it again seconds later when the new task finally appeared in the linked-tasks list. All of these now hold their position, and scrolling still cancels the hold immediately so nothing ever fights you.

Fixed: deleting a bundled AI profile or model now sticks on every device. Deletions were remembered only on the device where you made them, so a second device could re-create the profile and sync it back; the deletion now travels with your other AI settings. Removing a provider still takes its models with it and still restores them if you add that provider again, and re-running onboarding still brings back that provider's bundled profile.

Entries you mark private are stored private. Anything created with privacy set but without being attached to a parent entry — a private measurement, a completion of a private habit — had that flag cleared as it was written, and was stored as an ordinary entry. Privacy is now kept through the write. Entries attached to a parent still take the parent's setting, which is unchanged.

Link a task that doesn't exist yet, without leaving the picker. Searching for a task to link used to dead-end on "No tasks found" when the work simply hadn't been written down. Typing a title that matches nothing now offers to create it: the task is made with that title, put in the same category and project as the task you're linking from, connected with the relationship you already picked, and you stay where you were — with the usual Undo. The "Create new linked task…" menu entry still does what it always did, creating a blank task and taking you to it.

Dropdowns and search boxes now look like the same control. Where the two sit stacked — choosing how a task relates, then searching for the task to link — the dropdown was drawn as a flat opaque box with much rounder corners and a heavier outline than the search field, so the pair read as parts of two different apps. The dropdown now matches the search field's shell, including in dark mode, where it lifts off the panel it sits on instead of looking like a hole punched in it.

Warnings, errors and status text are readable in light mode. The amber, green and blue used for warnings, successes and information were mixed too light to stand out against a white or off-white background — amber measured barely above the page it sat on, so a "blocked" mark or a pending-sync notice could all but disappear. Those three tones are now deep enough to read, and any text carrying one of them — priority labels, status chips, connection results, ledger figures — is picked to stay legible in whichever theme you use. Dark mode is unchanged apart from error text, which lightens slightly on cards.

Areas created during onboarding now start with automatic AI on. Automatic transcription and image analysis stay off by default for categories you create later, but the onboarding flow — where you connect a provider and record a first capture on purpose — switches it on for the areas it creates, so the app keeps working the way onboarding just showed you. Reusing an area where you had already switched automation off leaves it off.

Fixed: re-running onboarding restores a bundled profile you had deleted. Setting up a provider through onboarding again now brings back that provider's bundled profile even if you had removed it earlier, so the areas onboarding creates always point at a profile that exists. Deleting it stays permanent everywhere else.

Fixed: deleting a bundled AI profile or model now sticks. The app re-created its bundled defaults whenever one was missing — at every launch, and again each time you saved a provider — so deleting one you did not want brought it straight back. Deletions are now remembered. Removing a provider still takes its models with it and still restores them if you add that provider again.

Fixed: clearing a profile's automated skills no longer re-enables them. Removing every skill from a bundled profile used to put them back, with automation switched on, on the next launch.

You now hear about a day plan that failed, not just one that worked. If drafting or refining a plan gave up while Lotti was in the background, nothing told you — you came back to a day that had simply never been planned, with no explanation. Those failures now raise a notification that takes you to the day so you can retry.

The "Active" badge on inference profiles now means something you can control. A profile was badged Active purely because one of its models belonged to a provider you had connected, so it could appear active the moment you set up a provider with nothing you could do to change it, while the profile your categories actually used showed nothing. The badge now reads "In use" and appears only when a category or a task agent routes through that profile.

A provider's page now lists every profile that depends on it, under "Profiles using this provider", instead of naming a single arbitrary "Active profile" — so you can see what would break before removing a provider.

Automatic AI now waits to be asked, per category: transcribing new audio and analyzing new images automatically is an explicit per-category switch under the category's AI profile. Picking a profile used to be enough to start it, and audio could be transcribed automatically with no profile chosen at all. The switch starts off everywhere, including categories that already had a profile, so turn it on where you want AI to keep working in the background. Per-recording opt-out is unchanged.

Turning on automatic updates for a task agent now wakes it right away instead of only arming future updates — unless the summary is already current, in which case nothing is spent.

Undo a link you just made. Picking a task in the link or blocker picker still commits on that single tap, but it now says what it wrote ("Blocks: Draft crew rotation schedule") and offers Undo, so a mis-tap or the right task under the wrong relationship is one tap to take back instead of a trip through Manage links.

Fixed: the Linked Tasks card cut off its own name in German and Spanish, and at larger text sizes in every language. The Link action now drops to its icon where the label won't fit beside the heading, rather than the heading giving way. The unlink confirmation also names the task you're removing, instead of asking about "this task" from a row of unlabelled icons, and an empty card offers both actions in words rather than hiding "create new linked task" behind the overflow menu.

Fixed: the Linked Tasks header broke at larger text sizes. At accessibility text scales the Link button was cut off and the overflow menu vanished entirely, which while editing links was one of only two ways out.

Fixed: undo after linking left the message on screen. It removed the link but kept showing the confirmation and a live Undo button for another ten seconds, offering to undo something already undone. The confirmation now shows the linked task's full name instead of cutting it off, and modal titles shorten with an ellipsis rather than reflowing their bar in longer languages.

Fixed: a task you had already linked could be linked again. A plain link reads the same from either end, but the picker only recognised it from the side it was created on, so a task already listed on the card was offered again — and taking it left two identical rows and needed two confirmations to remove one link.

Fixed: failures said the wrong thing and looked like successes. Every rejected link reported "this would create a blocking cycle", even for relationships that can't create one, and failure messages arrived on the same background as the "link created" confirmation. Manage mode also has a way to add a link again, its header slot being taken by the Done button while you're editing.

Fixed: the link and blocker pickers listed no tasks at all. Browsing, before typing anything, came back empty in every case, because the query treated "all categories" as "no categories". Searching still worked, which is why it looked like a search quirk rather than an empty list.

Fixed: a task with links briefly claimed it had none — opening a task showed the "Link a task" empty prompt until its links finished loading, so every populated Linked Tasks card flashed an empty one first.

Fixed: finished tasks can be linked again. "Follows up on", "Duplicates", "Fixes" and "Supersedes" all commonly point at work that is already done, but completed tasks were excluded from the picker and it reported "No tasks found" for a task you could see everywhere else. Blockers still list only open tasks, since a finished task can't block anything.

Fixed: undo after linking now tells you when it fails instead of silently leaving the link in place, and it stays on screen long enough to reach. Edit and unlink in manage mode meet the 48pt minimum touch target; they were 40pt, side by side, over a row that is itself tappable.

Fixed: task search could deny a task that exists. In the link and blocker pickers, full-text search results were matched against only the first 200 open tasks loaded, so on a larger backlog a task you searched for by name could come back as "No tasks found". Matches outside that window are now fetched directly.

Linking a task is a labelled button again: once the Linked Tasks card had any links, its only way to add another was an unlabelled icon, and it now reads "Link", matching the Done button that shares that slot. Save in the edit-relationship sheet stays off until you change something, instead of offering to save an edit nobody made. French and Romanian task statuses are sentence case rather than all caps, matching every other language.

One word for one relationship: the header chip on a blocked task reads "Blocked by 2 tasks" again, matching the section it jumps to and the option that created the link. Previously it said "Waiting on", so the same relationship went by two names depending on where you met it.

The edit-relationship sheet now names the task you are editing the link to; it read "This task… / Is blocked by" with nothing after it, leaving you to remember which row you had tapped. Editing links also no longer hides each linked task's status, since knowing a blocker is already done is most useful exactly when you are deciding what to unlink.

Manage mode says it is on: the Linked Tasks card shows a Done button in its header while you are editing links, instead of leaving the only exit inside the same overflow menu you opened it from.

On a desktop-sized window the task search field is focused when the link and blocker pickers open, so you can type straight away; it is left unfocused on phones, where it would raise the keyboard over the results. The Linked Tasks overflow menu now uses the app's own surface and radius rather than Material defaults, so it matches the card it opens from.

Picking what two tasks mean to each other is now one choice, not two. The relationship picker was a row of type chips plus a separate direction switch, which put the same word on screen twice — a chip reading "Blocks" directly above a switch whose first option also read "Blocks". You now pick from a single list that completes the sentence "This task…": Relates to, Blocks, Is blocked by, Follows up on, Has follow-up, Duplicates, Is duplicated by, Fixes, Is fixed by, Supersedes, Is superseded by.

You can change a relationship after creating it — turn a plain link into a blocker, or reverse which of the two tasks is the blocker, without unlinking and starting over.

The Linked Tasks card groups links under the exact phrase you picked, so it reads back the words you chose. What the task is waiting on comes first and is the one thing called out, and each row shows the linked task's status. The "waiting on" chip in the task header is now compact: it states that the task is waiting and how many tasks it waits on, rather than embedding the blocker's full title and spanning the header.

Linking, blocking and editing sheets adapt to the window — a bottom sheet on a phone, a centred dialog on a wide window, matching every other task picker — and size themselves to their content instead of leaving a large empty area below a short list.

Fixed: two tasks can hold more than one relationship. A task already linked to another could not be linked again with a different relationship; the second attempt silently reported "No tasks found".

Fixed: a task with no links can now be linked. The Linked Tasks section was hidden until a task already had a link, and the only way to add one lived inside that hidden section. It now always offers a "Link a task…" action. Long task titles also no longer truncate mid-word when picking a task to link.

AI activity now uses one consistent decoder-bars animation across Unified AI progress, entry details, cover-art generation, task details, and Daily OS, with smooth entry and exit transitions and tap-to-open progress where available.

Task agents can now read your image analyses: the AI analyses attached to a task's images — brief summaries and full OCR extractions alike — are part of the task agent's context, each with the model that produced it, when it ran, and its full text. The agent can act on what's in an image (e.g. extract an appointment date from a photographed card and propose it as the due date), and a completed analysis now flags the task for the agent's next regular update.

AI analysis cards are collapsible and visually calmer: long analyses (e.g. a full OCR extraction) under an image or audio entry start fully collapsed — just a Show more toggle and the model pill — and the cards drop their heavy card-on-card look for the tinted AI surface that matches the agent report cards in both light and dark themes.

Task links now carry real relationships — Blocks, Follows up, Duplicates, Fixes, or Supersedes — in either direction, for both existing and newly-created linked tasks. The Linked Tasks section groups them by relationship, a "Blocked by" chip appears in the header next to the status when a task is blocked, and marking a task Blocked now optionally prompts you to name the blocker on the spot.

Fixed: photo rows in the Logbook no longer shout. An image entry's caption was rendered several sizes larger than the title of every other row in the same feed; it now sits on the same title scale as note, task and event rows, and its timestamp matches the other cards' brightness.

Daily OS planning got a reliability pass: a plan draft or refinement that finishes while the app is backgrounded now raises a "your plan is ready" notification; failed processing stops retrying after a few attempts instead of silently re-running AI requests forever; a committed plan can no longer be replaced without your approval; two quick refinements no longer swallow the second instruction; rebuilding your day after a crash uses your latest selections; the Activity timeline reflects every processing state change live; and a day worked on from two devices no longer ends up with an invisible plan or a check-in stuck in parsing.

The Daily OS coordinator now briefs each day's planning agent: a morning digest reviews escalations and recent days, then issues a distilled per-day directive (commitments, capacity budget, carry-overs, cross-day context) which that day's agent must honor when drafting — placing each commitment, trading it away with the collision named, or escalating back via typed status events the coordinator picks up at its next digest. Each digest also pools the last four complete weeks into per-category planned-vs-recorded rollups, so the coordinator can steer month-scale pacing, not just the day at hand.

Fixed: the green focus border in list boxes no longer gets cropped at the corners. In the task filter box (and every other grouped list, e.g. in Settings), the first and last row's keyboard-focus highlight was drawn as a sharp rectangle and clipped by the box's rounded corners. Edge rows now round the highlight to match the box's corner radius.

The Manual's five walkthrough videos are now available in every language Lotti supports (previously English and German only): French, Italian, Spanish, Czech, Dutch, Romanian, Portuguese, Danish, and Swedish.

Manual videos now have a mobile-view variant, matching the existing screenshot toggle. The same mobile/desktop switch that already controlled screenshots now also switches the walkthrough videos, and first-time visits from a phone or narrow window default both to mobile view automatically; saved viewport preferences continue to take precedence.

Voice captures now survive the app closing before they're parsed: submitting or retrying a Daily OS capture queues its parsing durably, so backgrounding or killing the app between recording and parsing no longer loses the parse — it runs when the app reopens.

Fixed: the Settings list no longer jams its last entry (the Manual) against the bottom navigation bar on phones — the list now scrolls clear of the docked nav pill.

Fixed: the Keyboard Shortcuts page now smoothly hides the bottom navigation bar, matching the slide-away motion every other terminal settings page already had.

Fixed: the Projects list's floating "new project" button no longer covers the last project card — the list reserves clearance for the button and the nav bar, including the home-indicator inset on modern phones.

Fixed: opening a project from the Projects tab now slides the bottom navigation bar away, giving the project detail page the whole bottom edge — the same motion as the settings detail pages.

Fixed: the category icon picker no longer overflows its grid tiles on narrow phones — the icon label now shrinks into the available space instead of spilling out of its tile.

Fixed: same-day plans can no longer schedule new blocks in the past. The drafting guard now covers buffer blocks too; only imported calendar events — which legitimately span the current moment — are exempt.

Fixed: the Settings destination is readable again in Italian and Swedish. Several Settings-related labels showed "Impostazioni delle impostazioni" in Italian and "Miljöer" in Swedish instead of "Settings" — now "Impostazioni" and "Inställningar".

Fixed: the coding-prompt "Copy Prompt" button is correctly labeled in Dutch — it previously read "Waarschuwing kopiëren" ("Copy warning"); now "Prompt kopiëren".

Five narrated walkthrough videos are now embedded in the Manual, in English and German: creating a task with your voice, generating cover art, turning a coding task into an AI-ready prompt, filtering and saving task views, and setting up a category.

Accepting AI suggestions no longer bounces the task page: header changes (labels, due date, priority, status, title) confirmed together with checklist items keep the proposals pinned in place instead of shoving the page down and snapping it back mid-batch.

Drafting or refining a day's plan now survives the app closing mid-request: the request is queued durably instead of held only in memory, so backgrounding or killing the app no longer loses the work — it finishes and the result is there when the app is reopened.

Each day now gets its own planning agent instead of sharing one long-running identity, so its wake history, token spend, and conversation log (Settings > Agents > Inspect agent) show that day on its own going forward. Past days already planned are unaffected.

The agent Stats tab has been removed: Settings > Agents now opens on Templates and keeps four views (Templates, Instances, Souls, and Wake Cycles), with AI usage reporting living in the AI Usage view instead.

The "Here's what I heard" screen now animates the thinking shader on its action bar, matching the other planning steps, until parsing fills the Heard column, instead of sitting frozen for many seconds.

A day recording's text is now edited right on its Activity card with the same rich-text editor used across the journal; the separate text dialog is gone. Text written or corrected there counts as the final wording: a pending transcription completes instantly with that text, and a transcript that arrives later is kept as a record without overwriting it.

AI work now shows its real footprint where it was created. Coding prompts, generated and analyzed images, and audio transcripts carry a tappable attribution pill. Its details show the creator, model, request evidence, available input/output/cached/reasoning tokens, and the provider's actual cost. When Melious reports it, the same view also shows energy, CO₂e, and water use. Audio entries show the total across all their transcripts, while each transcript retains its own attribution. Coding-prompt usage also contributes to its parent task's AI-consumption total.

Generated cover art no longer clutters the task's timeline. The banner and list thumbnail are unchanged, but the generated image's own entry in the task's linked entries now starts collapsed instead of showing the same artwork a third time.

The task AI summary card's wake control no longer moves around. Freshness, the wake button or countdown, and the automatic-updates switch always live together in one row; model identity is always its own row below.

Fixed: Generate Cover Art now actually shows the generated image. The task was pointed at the wrong internal id after generation, so the artwork was created successfully but never appeared in the task header or task list.

Fixed: the record/stop button no longer flashes both states at once. Starting or stopping a recording briefly showed the record button overlapping the stop/pause/cancel row mid-transition.

Day recordings can no longer get lost: stopping a Daily OS check-in saves the audio to the journal before any transcription is attempted, and failed or offline transcriptions retry automatically in the background. A new Activity view on the Day header shows saved recordings with playback, check-ins, the generated plan, and day summaries in order, with retry and manual-text actions for pending transcripts. The day planner also sees recordings as soon as their transcript exists. Live (realtime) transcription and its mode toggles were removed; transcription always runs over the finished recording.

The logbook now matches the rest of the app. On desktop it uses the same split layout as Tasks: the entry list stays on the left, and opening an entry fills a reading panel on the right instead of navigating away, with a resizable divider and a highlighted selected row. The list got the same titled header as Tasks and Projects, denser cards with matching font sizes, and the entry details page now shares one unified background with the list, presenting the entry as a card with a comfortable reading width on wide windows.

Fixed a SIGABRT crash after closing Lotti by stopping background services and releasing every SQLite database before the Flutter engine exits.

Restored Flatpak access to the desktop Secret Service so Matrix credentials and other protected values can be read and persisted instead of failing with a misleading locked-keyring warning.

Task AI summaries are now cleaner and more compact: report and proposal text matches editor entries and card summaries, metadata is easier to read, and scheduled updates plus their switch form one responsive footer group beside the model on wide cards and above it on phones. Countdown ticks no longer shift neighboring controls, turning off automation during a pending update keeps the summary correctly marked as out of date, and accepting suggestions keeps the task detail scroll position stable while checklist and proposal content resize.

Date pickers now follow the device region's week order. Entry dates, entry ranges, due dates, and project target dates start on Monday in European regions and Sunday in the US, with matching weekday headers and calendar-day positions.

AI-generated work now carries a consistent attribution record. Coding prompts, generated and analyzed images, audio transcripts, and agent reports show who or what initiated the work and expose model, usage, timing, interaction evidence, and provider-reported cost. Attribution is preserved across encrypted sync. Existing work without attribution stays unattributed rather than receiving a guessed creator or cost.

Screen-reader controls now expose one clear actionable announcement with their label and state. New accessibility labels are also available in Danish, Swedish, and Dutch.

Matrix sync now finishes catching up after reconnecting during a large burst, even on poor networks. Reconnected devices recover every missed entry instead of stopping after a partial server page.

Danish and Swedish are now available throughout Lotti and its Manual. The app follows Danish and Swedish system locales, and Settings → Advanced → Language can open each matching manual explicitly.

Dutch is now available throughout Lotti and its Manual. The app follows Dutch system locales, and Settings → Advanced → Language can open the matching Dutch manual explicitly.

Settings → Advanced → Language now changes Lotti's UI as well as the external Manual. Selecting a language updates both immediately; Follow system restores your device language for both.

Screen-reader navigation, fields, and visual controls now describe their actions and state. Overflow menus, text-field icon actions, search clear, chart-scale controls, and calendar dates expose accessible names; fields keep their labels and validation feedback when focused; back navigation follows the app language; and unavailable navigation destinations announce their disabled state instead of sounding actionable.

Italian is now available throughout Lotti and its Manual. The app follows Italian system locales, and Settings → Advanced → Language can open the matching Italian manual explicitly.

The task AI summary card is more compact and calmer. The summary leads directly under a tighter header, and all secondary controls moved into a quiet footer at the card bottom: the Wake agent button, a small countdown chip while an automatic update is scheduled, the automatic-updates switch, and the model line. While automatic updates are off, a slim status strip under the summary always reserves the same space, showing either an out-of-date notice with a right-sized Wake agent button or a quiet up-to-date confirmation, so the card never jumps when freshness changes. Proposal rows lead with the proposed change itself over quiet accept and reject icons and a neutral kind tag, long summaries keep a readable line length on wide windows, and History plus Confirm all share one row under the list.

Audio transcripts respect the automatic-updates switch. Finishing an audio transcription, locally or synced from another device, no longer wakes the task agent while automatic updates are off. The summary is marked out of date instead, so the card shows the Wake agent action and no inference tokens are spent without consent.

Portuguese is now available throughout Lotti and its Manual. The app follows Portuguese system locales, and Settings → Advanced → Language can open the matching Portuguese manual explicitly.

French, Spanish, and Romanian now read more naturally throughout the app. Agent controls, AI and Sync setup, dashboards, health import, and task actions keep the selected language's own register and terminology instead of exposing literal or mixed-language copy.

The Manual link now opens English, German, French, Czech, or Romanian documentation to match your system language. You can choose a different language from Settings → Advanced → Language at any time.

Manual is now a distinct final entry in Settings and is also available from the desktop Help menu, keeping the navigation sidebar focused on the app.

Czech now reads consistently across Lotti and its manual. Category, dashboard, habit, time-analysis, session-rating, reference-image, and sync labels use one informal Czech voice, with the accompanying manual and screenshots using the same terms.

Absolute task due dates now use the selected app language. The desktop task header and reusable due-date label format calendar dates in the active locale instead of falling back to English month names.

Events and built-in surveys now follow the app language end to end. Event status and date labels, the PANAS questionnaire, and its embedded navigation, progress, validation, and dismissal controls no longer fall back to English in German or Czech.

Czech and German setup, automation, and release-note screens now stay in their selected language. Agent controls, inference profiles, labels, Sync activity, onboarding diagnostics, maintenance previews, and the newest release badge no longer fall back to mixed English UI copy.

German and large-text layouts stay usable in key setup flows. AI form status text no longer pushes actions off-screen, Daily OS time anchors wrap at accessibility text sizes, and the What's New footer gives translated actions enough room on phones.

Onboarding now follows the active light or dark theme throughout setup. Panels, text, controls, provider tiles, recording previews, task handoff states, and the animated neural and aurora artwork all adapt to the matching design-system palette. Critical setup actions support keyboard activation, and scaled text switches work areas to a readable single-column layout.

The desktop sidebar is navigation-first and keeps important task filters visible. Saved task filters now appear directly under Tasks with live counts. The first five follow the order you set, More expands the complete list without a limit, and the manager handles reordering, renaming, and deleting. Recording, timer, and agent status share one compact expandable activity row, while healthy sync stays quiet until work needs attention.

Saving a task filter now stays inside the filter flow, with explicit Update filter and Save as new choices instead of a separate popup.

The entry date stays readable on narrow phones. Entry-header action buttons now use tighter 4px gaps, so the date and time remain visible while every button keeps its full-size tap target.

Lotti now guides first-time setup through one onboarding welcome. The welcome walks through connecting an AI provider and creating a first task, replaces the older provider-selection prompt, and can always be replayed from Settings then Onboarding.

Survey questions now fit cleanly in their modal. Bundled questionnaires keep every answer choice and the Next action visible on both phones and desktop instead of clipping the final controls in a fixed-height sheet.

Inference profile model labels are readable again. Capability names use normal caption spacing instead of widely tracked overline text, so labels such as Image Recognition no longer wrap character by character.

Daily OS shutdown now stays usable on narrow phones. Its actions stack responsively, and wrapped metric labels keep enough height at both standard and larger accessibility text sizes instead of overflowing their cards.

Mobile navigation remains stable at fractional accessibility text sizes. Bottom-bar labels now reserve the same rounded line height Flutter renders, avoiding tiny overflows at scales such as 1.3×.

Time Analysis now stays usable in narrow windows. Period shortcuts wrap below the navigator, headline cards stack in reading order, and chart controls move below their heading instead of overflowing or clipping.

Completed Daily OS tasks now keep their cover thumbnails. Finished agenda rows retain the same task artwork as open and in-progress work, so a busy day stays easy to scan without losing task identity after completion.

Task agents now update only when you ask by default. New agents keep watching their task without automatically spending inference tokens after every change. An outdated summary stays visible with a clear Wake agent action, while automatic two-minute updates remain available as an explicit top-level opt-in. The redesigned card separates report reading from automation and model setup, and places Read more after the content it expands.

The remaining settings lists now fade their dividers on hover. Hovering a row in Categories, Labels, Habits, Measurables, Dashboards, or the Matrix sync maintenance list fades the hairlines above and below it, so the hovered row is never bisected — matching Config Flags and Advanced Settings Maintenance. The row layout stays fixed while only the divider colour changes.

Logging a measurable now stays in one clear, accessible sheet. Changing the observed date and time moves to a calendar page in the same capture flow instead of stacking another modal over the editor. Values and comments stay intact when navigating back, the complete time picker scrolls above the sticky action, and Save waits for persistence with visible progress and retry feedback.

Task agents now use evidence-first processing for everyone. The previously optional behavior is now standard and its Advanced Settings toggle has been removed. If you already had it enabled, nothing changes.

Synced alerts are now available to everyone. Alerts stay consistent across devices whenever Matrix sync is active, and the former Advanced Settings toggle has been removed.

The Knowledge Graph is now available from every task. The graph button is always present in normal task headers, embedded task details suppress the recursive entry point, and the graph surface is localized in all supported languages.

Daily OS is now a schedule you can actively operate. Long dictated plans stay fully visible and editable, AI activity appears from the first processing frame, and task-linked titles and categories update immediately. Planned blocks can be moved, resized, or edited in a design-system modal with familiar Start and end controls, atomic saving, and Undo.

Hovering a row on the Advanced Settings Maintenance page now fades the dividers above and below it, so the hovered row is never bisected by a hairline — matching the existing Config Flags behaviour. The row layout stays fixed while only the divider colour changes.

On mobile, the bottom navigation bar now slides out of the way on Settings detail pages — the AI and Agents sections, every Sync page (backfill, stats, outbox, …), and Advanced pages like Config Flags, Logging, Maintenance, and About — so the page owns the full height, and it slides back when you tap back. Menu hubs (Advanced, Sync, Definitions) and the browse lists (Categories, Labels, Habits, …) keep the bar, since you navigate onward from them.

AI agents now respond sooner when several are active. Up to three different agent wake cycles run concurrently by default instead of waiting in one global line, while each individual agent remains single-flight. The device-local limit can be tuned from one through eight in AI Settings.

Desktop Lotti now has a keyboard-first command layer. Command/Ctrl+K opens a context-aware command palette, Command/Ctrl+1–8 jump to fixed main destinations, F6 moves between desktop regions, and primary work surfaces expose contextual save, search, refresh, and create actions. macOS menus, command execution, and the fully localized shortcut reference in Settings share one catalog. Split panes can be resized from the keyboard, and Daily OS commits no longer require a pointer-only hold gesture.

Command+S saves changed rich text again. The save command now travels with the reusable editor, so it works in journal cards and task forms as well as on the standalone entry page without reaching for the Save button.

Keyboard navigation now enters task and project details directly. Right Arrow on a focused row opens the adjacent detail pane instead of resizing the divider, and keyboard row focus uses the same full-width color and rounded clipping as pointer hover.

Task and project filters now share one coherent, accessible flow. Status, category, label, and project choices stay inside the same smoothly resizing sheet or desktop dialog, with consistent full-width selection states, responsive actions, keyboard focus restoration, and clearer activity and sort controls. Linked-entry activity and sort pills match the compact size of the task-header chips, with hover feedback confined to the pill itself, while active activity pills retain their individual colored outlines. Task filters open immediately while project data refreshes in place, and active filters remain visible as compact chips on the task page.

New tasks now stay in the filtered list where they are created. A task inherits a single selected category, project, or status together with every selected label, while ambiguous multi-selections keep the existing defaults.

Checklist cards now collapse cleanly after every item is complete: the completion message stays on one line instead of stacking its letters.

The editor formatting toolbar renders correctly on macOS again instead of becoming a grey error strip when an editor gains focus.

Bulk checklist suggestion acceptance no longer flickers. Confirm all keeps every proposal row mounted through its staggered exit even when fast checklist check-offs resolve the underlying suggestions before later rows begin animating, while the task page stays anchored throughout the batch.

Matrix sync now reliably catches up after a device was offline. Reopening a device after another device sent a large burst always walks forward from the last applied Matrix event instead of occasionally treating a cached timeline as complete and leaving newer entries missing.

Date and time pickers are now clearer and steadier across the app. Entry ranges show weekdays, include Start and End Now actions, and transition to a calendar page within the same sheet. Due dates and project target dates share the same weekday calendar, while tighter wheel controls and stable status spacing keep the layout compact without jumping in light or dark mode.

Pickers now feel like one coherent part of Lotti. Task status, priority, labels, category and project, project status, AI profiles and models, and Gemini thinking mode share the same full-width rows, selection and hover/focus treatment, typography, and responsive phone-sheet or desktop-dialog presentation. Task-agent AI setup keeps profile, provider, and model choices in one navigable sheet, with an inline confirmation for pausing AI instead of another modal. Its overview groups the active profile, effective model, and automation into a compact settings hierarchy, and keeps the loaded AI catalog between pages so navigation no longer flashes an empty state. Page changes use a calm staggered fade while the sheet eases smoothly to its new height, and a tapped thinking model shows its selected state immediately while the change is saved.

Mistral Voxtral now supports contextual chat transcription. Instruction-following Voxtral Mini and Small models use the same temporary MP3 lifecycle as Melious, keeping long uploads compact while applying task instructions and speech-dictionary terms during recognition. Archived M4A audio remains unchanged and temporary files are removed after every request.

Accepting checklist suggestions no longer makes the task page jitter. Single and bulk accepts keep the suggestion area anchored before each checklist layout change is painted, including when several to-dos arrive across successive refreshes.

Daily OS now has a discoverable settings page for choosing its default inference profile and preferred name, plus per-planner profile and thinking-model overrides. Setup explains that assembled planning context is sent to the selected provider and identifies whether its configured endpoint is local or remote.

The preferred name you set for Daily OS now syncs across your devices, with the most recent edit winning, so each device greets you the same way.

Long Melious Voxtral recordings now use a temporary MP3 for transcription instead of an oversized WAV upload. The archived M4A remains unchanged, and temporary decoder and MP3 files are removed after successful and failed requests.

AI coding prompts now show up under their task. A generated coding prompt is linked to both its parent task and the audio or text note it came from, and appears in each of their linked-entries lists under the Code activity filter. Previously the prompt was created but stayed hidden from the task timeline.

Daily OS is now available to everyone. The Daily OS day-planning surface no longer sits behind a feature flag and appears in the main navigation for all users.

Returning from a Sync sub-page such as Backfill sync to Sync settings now uses the same clean pop animation as every other settings screen, instead of the jarring page-swap transition it played before.

Audio recordings can now be paused and resumed mid-capture from the recording sheet, next to stop and cancel, so you can pause a brain dump and pick it back up without splitting it into separate entries. While paused the elapsed timer and level meter freeze. Available for standard recordings; live-transcription recordings are unaffected.

Task details now stay steady while AI results and accepted suggestions land. Completed audio transcripts and image analyses expand smoothly instead of snapping linked entries taller, content above the viewport no longer yanks the passage being read, and checklist items created from accepted AI suggestions reveal progressively while the suggestion card remains anchored.

Voice input now reports transcription failures instead of silently disappearing. Chat, saved audio entries, linked tasks, and agent-evolution input show provider diagnostics, including empty-response failures. Melious Voxtral now converts a temporary copy of the compact M4A master to WAV for a buffered contextual chat request on every supported platform, then deletes its scratch files. Conversion uses native system media APIs without bundling FFmpeg, and failures surface their decoder detail instead of dropping to a less contextual request. Requests fail with provider detail and a request ID after 60 seconds instead of waiting indefinitely. Voxtral is preferred over Whisper when both Melious models are configured.

Task agents now show their thinking model, model publisher, and serving provider directly in the AI summary. The identity opens a persistent setup sheet for choosing a profile or model, returning to the profile default, copying the category default, or pausing AI. Reports retain immutable attribution after setup changes, and automatic task-related updates can be disabled while Run now remains available.

AI profile and model choices now use one consistent design-system picker flow. Task-agent choices finish saving before the setup sheet closes, and their confirmation stays inside the task column instead of spanning the application.

Backfill Sync now updates both Missing counters as sequence-log rows resolve, keeping them in step with the inbound queue countdown during large backfills instead of waiting for the slower diagnostics refresh.

The energy-orb recording visualization now compiles only its production shader and reuses the loaded fragment shader as live audio levels change, avoiding prolonged stalls and recording crashes on affected Linux graphics stacks. Finishing a recording also dismisses its sheet exactly once before opening the saved entry, avoiding a nested-navigator teardown failure.

Task agents now use evidence-first inference by default with efficient models. The mode remains configurable in Settings → Advanced → Flags and uses an evaluated low-variance, temperature-zero path. The default Melious profile uses Qwen 3.5 122B A10B directly for task reasoning and keeps Mistral Small 4 119B for image recognition. Existing untouched Melious profiles move to Qwen automatically, while customized model choices remain unchanged. Qwen reports that match known harmful regression patterns receive a compact, bounded Qwen repair; clean reports remain single-pass. Selecting Mistral instead keeps Mistral responsible for task and checklist changes and adds an isolated Qwen report pass. Evolved and manually customized report instructions remain authoritative, each model call is tracked separately, and concrete multi-step plans become checklist actions without requiring a separate explicit checklist request.

Melious task agents now continue reliably after calling tools. Follow-up requests preserve the OpenAI-compatible assistant message shape expected by strict providers, so checklist updates and the final report are no longer interrupted after an otherwise successful tool call.

Task-agent reports now stay current after task changes. When an agent successfully changes task metadata or checklist state but omits its report call, Lotti requests a fresh report instead of continuing to display the previous state. True no-op wakes still reuse the existing report. Agent internals record whether the Qwen report pass was accepted, rejected, failed, not needed, or ineligible.

Failed task-agent inference is no longer recorded as a successful empty wake. Provider and connection failures reach the workflow failure path so retries and diagnostics reflect what actually happened.

Dashboard chart editing now saves when it should. Adding measurable charts in Settings → Dashboards immediately enables Save, measurable chart aggregation can be chosen before adding, aggregation and reorder no-ops no longer make the form look changed, chart rows expose clearer edit/remove and reorder affordances, and the chart sections and pickers now use the shared design-system layout.

Daily OS dictated plans keep task agents and titles in sync. Tasks created from a spoken Daily OS plan now get the category's default task agent, and task-backed planned blocks on the Day timeline update when you rename the task.

Daily OS now gives better feedback while turning a spoken check-in into a plan: drafting shows a staged progress trail, failures offer Retry and Back to decisions, the Day footer explains why blocks made it in, each block can show its own reason, and quick review actions let you accept the plan or ask for less, a lighter move, or more buffer without re-dictating from scratch. At larger text sizes, those refinements collapse into one Adjust menu so the footer stays reachable.

The AI Impact dashboard now visualizes the breakdown, not just tables. Separate by-category and by-model charts are shown together, each with a Share mode for how your mix shifts week over week — the favorite-models-over-time view. A Both / By category / By model picker narrows the page to one breakdown; By model hides every category name, so you can screenshot and share your model mix without leaking what your categories are called. A Requests metric and per-model unit economics (calls and cost per million tokens) join the KPIs, whose tiles are now the metric selector — tap a tile to drive the charts, and the selected tile shows how it moved versus the previous period, with rising cost/energy/CO2e flagged in a caution colour. The charts are interactive: tap a series (in the legend or a breakdown-table row) to isolate its trend, and tap a bar to scope the recent-calls list to that period. A note makes clear that cost, energy and CO2e are measured for cloud models only.

The AI Impact dashboard also includes a Running total chart mode for cumulative cost, energy, CO2e and token usage over the selected period. Voxtral transcription records token usage when the server returns it in final accounting chunks, and transcription calls whose provider reports no token, cost or energy metrics are labelled instead of leaving a blank ledger row. AI Impact also adds a model breakdown for the selected metric, using provider-native model IDs when available. When the provider reports data-center metadata, AI Impact groups environmental impact by country/data center and shows the renewable-energy share for each location.

Melious-hosted Voxtral audio models now use the chat audio endpoint, which reports token usage, cost, and environmental impact, instead of the transcription endpoint that only returns text. Category speech-dictionary terms are included in the chat prompt so Voxtral still gets spelling context.

The image viewer's save button now works on every platform: on iPhone and Android it saves the photo to your photo library, and on macOS, Windows and Linux it opens a native save dialog so you choose where the image goes. Previously it always tried to write into Downloads/Lotti, which failed with an error on iPhone and on the sandboxed macOS build.

Choosing an AI profile or model now works on phones. Tapping a choice in an AI picker — a category's default inference profile, a profile slot's model, or an agent template or soul — used to close the whole settings page instead of the picker, so your selection was never saved. The picker now closes on its own and keeps your choice.

Entry timestamps no longer get cut off on phones. In a task's linked entries, the header's date and time used to be truncated when the action buttons squeezed the row on a narrow phone. The timestamp now stacks the date over the time on two lines when space is tight, so the whole date and time stay readable.

The desktop sidebar is calmer when Tasks has lots of saved filters. Saved task filters now sit in their own capped Tasks section with a More row, tapping More reveals every saved filter, active filters stay visible, recording/timer/agent cards carry clearer status labels, agent rows can open their linked task directly, and the old tiny Outbox/Inbox footer is now one compact Sync strip. Daily OS and Insights sub-items now use the same grouped sidebar surface, so Time Analysis and AI Impact read as intentional secondary destinations instead of loose rows.

Keyboard and screen-reader flow is clearer across shared desktop controls. Saved task-filter rows can now be focused, opened with Enter or Space, renamed with F2, cancelled with Escape, and deleted with a two-step Delete/Backspace flow. Screen readers announce the row as a selected button with rename/delete actions, hidden delete controls stay out of the focus tree, glass overlay buttons now carry proper labels/tooltips, modal Back/Close controls are named, and live sidebar cards announce as actionable buttons with their linked title and elapsed time.

Habit and agent-heavy screens spend less time waiting on the database. Habit heatmaps now load only the latest completion per habit/day, and agent summary/feedback paths batch payload lookups instead of firing many individual reads.

The debug-only Onboarding animation gallery (Settings → Advanced → Maintenance) no longer leaves the floating bottom navigation bar stacked on top of it on phones. It now escapes onto the root navigator the same way other pushed debug/editor surfaces already do.

A new Settings → Recording Style page lets you choose the VU meter or energy-orb visualization for the mic — with the same live preview and "Try with your voice" toggle from onboarding — and the real recording screen now honors your choice instead of always showing the VU meter.

AI profile pickers only show profiles you can actually use. Default inference profiles are no longer seeded for providers you haven't set up: each bundled profile now appears only once a working provider of its type exists — connect Melious.ai and you get exactly the Melious profile, nothing more. Untouched leftover profiles for providers that were never set up (or have since been deleted) are cleaned up on the next launch; any profile you renamed, described, or rewired to another provider is kept.

The next-gen agentic DailyOS is now the only DailyOS. The "Use next-gen agentic DailyOS" toggle under Settings → Advanced → Config Flags is gone: the calendar tab always opens the voice-first, agent-led capture and reconcile flow, and the previous DailyOS surface (including its Set Time Blocks screen) has been removed.

The journal image viewer is calmer and easier to use. Tapping a photo now opens it over a dimmed version of the app instead of a stark full-screen shell, keeps a visible margin around the image, has persistent top-right Download and Close buttons, closes with Escape, and adds a bottom zoom control while preserving pinch-to-zoom and panning. Download saves the original image into Downloads/Lotti with a unique filename.

Lotti now shows what your AI actually costs — in money, energy, and CO2e. Every AI call (agent turns, transcription, image analysis, cover art, text generation) is recorded with its cost in credits, energy use, CO2 footprint, water use, tokens, and the data center it ran in — measured per call by Melious for Melious-hosted models. A new AI Impact dashboard (next to Time Analysis in the sidebar, and under Settings → AI → Usage & Impact) lets you switch between Cost, Energy, CO2e and Tokens, browse by week, month or year, and see stacked per-category charts, period totals, a ranked category breakdown, and a ledger of your most recent individual calls. Tasks that used AI carry a quiet header chip with their lifetime footprint, with the full breakdown a hover away. Consumption records sync across your devices, so the numbers cover everything, not just one machine.

The audio recording sheet now has a discard (✕) button next to Stop, in both standard and realtime modes. Tapping it asks for confirmation, then throws the recording away entirely — no audio entry is saved, no transcription runs and no task summary is generated — and returns you to the page exactly as it was before you started recording. Stop still keeps the recording and kicks off transcription and the linked task's agent as before.

Saved task filters now work on mobile and sync across your devices. The named filter presets from the Tasks page come to the phone: a slim rail under the Tasks header shows the filter you're on plus a couple of recent ones with live task counts and one-tap switching, and tapping "Saved" opens a "Saved filters" sheet — the full list to switch from, with an Edit mode to rename or delete and a "Save current filter as…" row; a hand-tuned, unsaved filter surfaces a "Custom" pill and an inline "+ Save" on the rail. Saved filters now sync between devices — create or delete one anywhere and it propagates — and a new Settings → Sync → Sync Entities → "Saved task filters" step pushes across the presets you already had. Filter counts are computed per device, so they always reflect what that device actually holds.

A guided first-time onboarding (behind the "New onboarding (FTUE)" flag in Settings → Advanced → Flags). With the flag on, a fresh install replaces the bare provider picker with a short, skippable, cinematic flow: a welcome that frames AI setup as "connect your brain"; a provider step (Melious.ai first, then Mistral, Gemini and Qwen, with OpenAI and Ollama behind "More options") that pastes a key and creates the provider, its known models and a ready-to-use inference profile in place; a quiet "connected" beat; a step to pick the life areas (Work, Fitness, Family, Friends, or your own) the AI should power — teaching that the provider is chosen per category; and a playful step to pick how recording looks (a modern energy orb or an analogue VU meter, previewed live — try it with your voice). It ends in the real payoff, without ever leaving the onboarding dialogue: a "Create your first task" step in the same panel where you speak a thought — recorded with the visual you just picked — or tap a starter suggestion (like "Plan my week") if you're not ready to talk. Your words become a structured task with a checklist, revealed right there in the panel as a glowing card ("Your first task is ready"); tapping it lands you straight on that task — already in progress, in the area you picked, with your original voice recording attached to it, and with Laura, the default task agent, already assigned and immediately at work — her first pass over your words lands as a summary with suggestions for you to confirm, just like after recording a voice note inside a task. Every area you pick during onboarding gets Laura as its default agent, so later tasks in those areas get an agent too. Areas you already have (like an existing "Work" category) are reused instead of duplicated — rewired to the new provider, but keeping any agent template you had chosen yourself. A "Rather type?" path, a one-tap retry, and a soft-landing title-only task when structuring fails keep it robust, and the whole flow honors reduce motion.

A first-class Events experience (behind the "Enable Events" flag in Settings → Advanced → Flags). Events — birthdays, trips, milestones — now get their own destination (under More on mobile, the sidebar on desktop) with a photo-led overview that groups your moments by time and filters by category, plus a redesigned detail page that doubles as a full inline editor: a photographic header where you rename the event, set its category, status and rating, and add or change a cover; an at-a-glance summary; a photo gallery you can tap into full-screen and swipe through; a timeline of the linked photos, notes, voice notes and time recordings (each opening its source entry; a time recording reads as a span with its elapsed duration); and the prep/follow-up tasks tied to the event. Add photos, notes, voice memos and tasks straight from the page — even a brand-new event shows what to do next instead of an empty screen.

An optional AI recap for events. Point a category at an event-agent template (Settings → Categories → AI defaults) and new events in that category get a quiet writing companion: once the event has a photo or a note, it weaves the linked photos, notes and voice memos into a short, warm recap shown on the event's detail page, with a refresh to rewrite it. It can also propose the occasional concrete follow-up — a thank-you to send, an album to share — which you accept or dismiss with a swipe; accepting turns it into a task linked to the event. It never touches your star rating or cover photo — those stay entirely yours.

AI settings now include Melious.ai as a dedicated EU-hosted inference provider. The provider setup can fetch Melious' live model catalog, including chat, reasoning, vision, audio, image, embedding and rerank models, and add any returned model as a saved Lotti model row instead of relying on a hard-coded static list. Large live catalogs are searchable in the Available Models section instead of expanding into one long page. New Melious setups also seed a ready-to-use default profile with Mistral Small 4 119B Instruct for thinking and image recognition, GLM 5.2 (a 1M-token-context reasoning model) as the high-end thinking option, Flux 2 Klein 9B for image generation, and Voxtral Small 24B for transcription — a speech-recognition model that takes your category's speech dictionary into account, so names and domain vocabulary come out right where Whisper guessed. Whisper Large v3 and Turbo are still created alongside for easy switching, and existing untouched Melious profiles move to the new GLM 5.2 and Voxtral defaults automatically.

Deleting an AI provider and reconnecting it later no longer leaves its profile silently broken. The seeded profile used to keep pointing at the deleted provider's model entries, so everything that resolves through it — structuring your first task, transcription, and agents like Laura — failed with "no inference provider configured" even after you added the provider back. Broken profile entries now heal automatically on every app start and immediately after connecting a provider (in onboarding or settings), so your first capture works seconds after the key step. Model choices you made yourself are never touched — only pointers that lead nowhere are repaired.

Flux cover art gets its own prompt path. The AI popup now includes a separate Generate Cover Art (Flux) action for task-linked notes and voice notes. It sends Flux models a short visual scene and mood brief instead of the full task JSON and related-task context, while keeping the same 16:9, center-safe thumbnail composition guidance as the regular cover-art prompt. Melious-hosted Flux 2 Klein 9B gets a clean image prompt for task covers, requests an explicit 16:9 1792 x 1008 canvas through Melious' FLUX dimensions, and new and untouched Melious profiles use it as their default image-generation model.

oMLX can now be used for local Whisper Large v3 transcription on Apple Silicon. The oMLX model catalog includes Whisper Large v3, Whisper Large v3 MLX, and Whisper Large v3 Turbo as audio-to-text models, and selecting one routes voice-note transcription through the local OpenAI-compatible /audio/transcriptions endpoint instead of chat completions. Untouched local oMLX default profiles now use Whisper Large v3 Turbo for transcription. oMLX provider settings also fetch the local /models endpoint in the Available Models section, so any model exposed by the running oMLX server can be installed directly from the provider edit page.

Mistral provider settings now fetch the live /v1/models catalog in the Available Models section, just like Melious and oMLX. Each model's capabilities — vision, OCR, audio transcription, reasoning and function calling — are mapped from Mistral's metadata, so you can search the full Mistral line-up and install any model directly from the provider page instead of relying on a curated static list.

Gemini and OpenAI provider settings now fetch their live model catalogs in the Available Models section too. Gemini reads Google's native /v1beta/models listing (display names, descriptions, token limits and the thinking flag) and OpenAI reads /v1/models, deriving each model's capabilities from its id while dropping embedding, moderation and text-to-speech rows. When a new Gemini or OpenAI model ships you can search for it and install it straight from the provider page instead of waiting for a curated update.

Provider detail pages now list your installed models above the searchable model catalog, so you see what you already have before scrolling on to add more (Melious, Mistral and oMLX).

Mistral OCR support: running Analyze Image with a Mistral OCR model (e.g. mistral-ocr-latest) now extracts the document's actual text. OCR models use Mistral's dedicated /v1/ocr endpoint instead of chat completions, so a scanned letter or form comes back as real Markdown text you can read and ask follow-up questions about, rather than a vision model's loose description.

Accepting or dismissing an AI suggestion is now smooth and calm instead of jumpy. The row you tap stays put and confirms in place — a clear filled badge with the plain word "Confirmed" or "Dismissed" and a light haptic — then gently collapses while the rest of the list slides up to close the gap; the pending count ticks down with the action. There's no longer a success popup at all (for single accepts or "Confirm all") — the motion makes success abundantly clear. "Confirm all" sweeps the list clean in one staggered motion with a single tap-feel. The swipe hint no longer nags: it plays once, as a single gentle nudge, instead of a repeating two-way wiggle. While a row is leaving, the rows sliding up briefly ignore taps so a fast second tap can't hit the wrong suggestion. Screen readers hear the verdict and how many suggestions are left, and with reduce motion turned on the rows update instantly with no sliding.

Checking off a checklist item now plays the same little spark burst no matter how it happens — a direct tap, an accepted AI "check off" suggestion, or a sync from another device — so completing an item always feels rewarding.

Completion celebrations are now yours to shape. A new master switch in Settings → Advanced → Animations turns every completion flourish on or off at once, and you can give each kind of moment its own style — choose from Sparks, Fireworks, Confetti, Embers and Bubbles for finishing a task, keeping a habit, and ticking off a checklist item (they start out as sparks, confetti and bubbles). Pick a surface to see the style it's set to, and the picker plays a preview as you choose; a "Try it" row fires each one on a dummy Done button, checklist item and habit before you commit. And the completion buzz now has its own switch, independent of the animation — keep the haptic with the flash off, or the flash with the buzz off.

You can now go further and customize each celebration style yourself. A full-screen playground (tap Customize on any style in Settings → Advanced → Animations) gives you that style's look — particle count, size, spread, and its own physics like gravity, twinkle, sway, spin and swell — grouped into Shape, Motion and Look, each control with a plain-language description. Drag a slider or tap its value to type an exact number, previewed live inside a sample checklist so you see how it reads in context rather than over a lone dot; Reset-to-default can be undone. Your changes persist and apply wherever that style plays. Each kind of moment can also be set to Random (a different style on every completion) or Combine two (two styles layered, re-rolled each time) for more novelty.

Dashboard charts with no data in the selected range now collapse to a compact one-line notice under their title instead of holding open a full-height empty card. On a dashboard with several charts, the ones that actually have data get the room, and you no longer scroll past tall blank panels to reach them.

Editing a note now has a calmer, clearer toolbar. Saving moved out of the card footer and into the editor toolbar: a pinned Save button that holds one spot the whole time you edit — quiet and greyed when there's nothing to save, and waking to a teal accent the moment you change something (the disk icon is always there, so the change reads as more than just colour). When you have unsaved edits, a discard control appears next to Save to throw them away and drop back to the saved text. The toolbar also adapts to width: on a roomy desktop window every formatting control is one click away, while on narrow screens it shows the essentials plus a "…" button that opens the rest.

New AI suggestions now ease into place instead of snapping. When a fresh proposal lands, its row grows open and the content below it glides down rather than jumping — and if the card has scrolled off the top of the screen, nothing on screen moves at all. The event recap and proposal cards and the daily-planning "learning" cards reveal the same calm way.

Charts no longer replay their grow-in animation on every refresh. The dashboard bar chart and the habits completion-rate chart used to re-animate each time their data refreshed or you changed the time range; now they update in place.

Reduce motion quiets more of the app. With reduce motion on, the looping pulse on the pending-review dot, the rate-session button and the voice-capture orb hold steady instead of breathing, and the full-screen "locking in" takeover resolves at once.

Scrolling the time-history strip at the top of the Day view is smoother on long histories — the background chart no longer rebuilds on every frame as you drag.

The template and soul evolution chats no longer jerk to the bottom while you're reading. If you've scrolled up to look back at earlier messages, a new reply (or the typing indicator) no longer yanks you down — the view only follows along when you're already at the bottom, and eases there instead of snapping.

Dragging a planned block on the Day timeline now settles smoothly. When you let go, the block eases into its snapped 15-minute slot instead of teleporting to it.

Checklist cards in the journal feed no longer grow a step taller a moment after they appear — their progress chip and bar hold their space from the first frame, so the list doesn't shuffle under you as you scroll.

Image import now keeps existing JPEG and PNG files unchanged, including transparent PNG screenshots. On platforms with HEIC/HEIF conversion support, ordinary high-efficiency images are converted to JPEG, while HEIC/HEIF files with alpha are converted to PNG so transparency survives.

Fixed: coding prompts generated from a task-linked audio note now attach to the parent task even when the note's task relationship has to be resolved from the link graph, so follow-up prompts can see the earlier generated prompt as task context.

Fixed: photos dragged into Lotti now keep the moment they were taken. They were being dated to the time of the drop; the importer now reads the original capture time from the image's EXIF metadata (and its GPS location, when present), falling back to the file's modified time only when the photo carries no timestamp. That fallback used to read as the drop time too, so dragging a batch of screenshots from a meeting stamped them all with the same time and out of order — dragged files are now read straight from their original location on disk instead of a copy, so the real modified time (and the original order) comes through.

Fixed: the celebration Style settings got a small polish pass. Each style's preview is now a single crisp play button instead of a blurry triangle and dot layered on top of each other, and the Tasks / Habits / Checklist items selector above it uses the same aligned segmented control as the rest of the app, so its rounded corners line up with the selected segment.

Fixed: an inference profile whose model's provider had been deleted no longer shows a garbled raw model id in its slots. The slot now reads "Model unavailable — its provider may have been removed" and keeps its clear button so you can reset the dangling reference.

Fixed: on phones, the back button on a settings sub-page (e.g. Advanced → Maintenance) could fail to return to the previous screen. It now follows the visible navigation stack — the same as the system back gesture.

Fixed: the entry header's action buttons (the favorite star and the overflow menu) were clipped at the top-right corner on narrow phones. The timestamp now shortens when space is tight instead of pushing the buttons off the edge.

Fixed: linked tasks now show the actual task status glyph. In-progress linked tasks use the same play icon as the task status pill and status picker instead of falling back to an open circle, and the link-task picker uses that same shared status icon set.

Fixed: task cover art no longer flickers or briefly vanishes while you resize the desktop panes. Dragging any pane divider — even the sidebar, away from the task detail page — used to re-decode the cover image on every frame of the drag; the detail page now reuses the already-decoded image while the width changes and keeps the current frame on screen when a larger decode is needed.

The search field in Settings → AI now matches every other search box in the app — one consistent design-system search instead of a one-off styled field — and its placeholder reads "Search providers, models, profiles…" instead of the internal "Search AI configurations…".

The first-time onboarding setup animation feels more organic. The welcome screen now grows an entangled, looping neural organism with dim tendrils, smaller offshoots and travelling activation tips instead of separate straight-line constellation clusters. Later setup steps keep a softer living backdrop, a lighter cloudy modal surface and calmer provider cards so the flow feels connected without fighting the form content.

The AI settings "add" button and card menus are clearer and easier to hit: the floating add button shows one unmistakable + on every tab instead of three different icons, the ⋯ menu on each card is a full-size touch target, and the add button no longer hides the last item in the list on phones.

Settings controls now speak the same visual language as the rest of the app. Save and Cancel buttons across the settings pages — AI providers, models and profiles, sync and labels — use the design-system button: quiet and greyed when there's nothing to save, waking to a teal accent the moment you change something (the same pattern as the note editor). The toggles, checkboxes and the light / auto / dark theme switch use the design-system controls too, with teal accents and consistent shapes in place of the old purple Material widgets. The category chips on a label now carry their category's colour as a soft tint instead of a heavy solid fill, and small status tags — a profile's "Desktop only", a sync node's capabilities — use the design-system badge. The AI model filters (provider, capability and reasoning) on the Models tab are design-system chips now, each provider keeping its colour on a small avatar dot. The Sync conflicts and outbox lists now sit on the same dark background as the rest of Settings instead of a near-black sheet (with their cards reading as elevated), and the Sync Outbox row shows its pending count as a clean badge rather than a postbox glyph with the number squeezed on top.

Choosing a model for a one-off AI run is calmer. When you run an AI action from the sparkle menu (transcribe a voice note, analyze a photo, generate a prompt or cover art) and you have more than one capable model, the picker no longer drops you into one long flat list. It now groups your models by provider — pick a provider (Anthropic, OpenAI, Gemini, Mistral, a local Ollama…), then a model within it — with a one-tap shortcut to your current default pinned on top. If you only have one capable model it runs straight away, and if all your models live under a single provider the picker skips straight to them. Cover-art generation now lets you pick which image model to use, too — previously it always used your profile's image model. None of this changes your saved profile; the choice applies to that one run.

The entry cards on a task's timeline got a whitespace-and-typography pass so the different entry types (text, audio, image, measurement, health, workout, habit, rating) read as one calm, legible family. The timestamp is now a quiet but readable caption instead of a faint, monospace-looking stamp, and every "label: value" line shares one treatment — a quiet label with the number itself as the bold, high-contrast value — left-aligned to a single content gutter. Measurements no longer print their note twice, "55 %" reads "55%", health and measurement values stop floating centered, the rating card now shows a number next to each bar (for example 80%), and faint header and footer controls (timestamp, duration, the overflow and expand icons, audio timecodes, the AI button) were lifted to a legible contrast. Cards also hug their content with one symmetric padding instead of reserving an empty band at the bottom.

The task details header was reworked for a calmer, more responsive layout. The status control no longer floats in empty space — it leads a two-lane metadata block (status, priority, due date and time estimate on the first lane, your labels on the second), with status and the due date carrying more weight than priority and tracked time. Every chip shares one height and style, the breadcrumb sits as a quiet eyebrow above the title, and the title binds tightly to its metadata. The title is now click-to-edit (no separate pencil button), and on narrow phones the due date and time estimate stay paired on one row. Chips read more clearly too: priority is spelled out (Urgent / High / Medium / Low) instead of the cryptic "P2", the time-estimate chip reads "tracked of estimate" in plain duration units (for example "0m of 1h" rather than a clock-like "00:00 / 01:00") with a tooltip, neutral metadata chips carry a defined outline so their edges stay legible, and a long label list collapses behind a tappable "+N" chip. The layout holds up across long wrapping titles, many labels, empty new tasks, narrow widths, and tasks with cover art.

Two spots on the task page are easier to hit precisely. The AI suggestions' reject control is now clearly separated from accept, so a mis-tap can't trigger the wrong one. Each Todo checkbox gets a 44px tap target that sits in a subtle outlined well, so the whole tappable area is visible before you touch it (and lights up on hover/press) — no more aiming at the tiny square. The drag-grip dots are quieter so they don't compete with the task text, and the empty checkbox is drawn with a higher-contrast outline.

The AI summary card reads as a slightly more vivid "assistant" panel — a touch more accent in its corner wash and glow so it no longer looks muted — with evened-up spacing: a smaller gap above (matching the other section gaps) and real breathing room below before the bottom action bar. The status / priority / label picker modals are tidier and more consistent too: each row highlights with a rounded, inset shape on hover or selection instead of a sharp edge-to-edge band, and the titles no longer mix styles (the stray trailing colon on the status picker is gone).

Accepting an AI suggestion that adds a to-do no longer makes the page jump — the view holds the AI proposals in place when a confirmed change grows the checklist above them — and it no longer flickers the checklist, since reloading rows keep their current state instead of blanking for a frame and checklist cards keep their identity when the list changes. Adding a checklist item no longer flashes a missing divider, since the separating line is now part of the new row. And confirming a proposal that checks off a checklist item no longer slides the AI card up from under your finger: the card stays pinned across the checked item's delayed row collapse so you can keep accepting proposals in the same spot, while still stepping aside the instant you scroll. Accepting an AI-suggested label also works now even when the task already has labels: previously, once a task carried three labels, any further suggested label was silently dropped on accept, whereas suggestions are now applied regardless of how many labels the task already has (a label you already have is still skipped as a duplicate).

Sync conflicts got a ground-up redesign. When the same entry was edited on two devices, you now see a full field-by-field comparison — title, body, category, dates, flags and more — with the exact words that changed highlighted, so you can tell what a choice would keep or discard instead of guessing. You can keep either version or combine them field by field, and a "recommended" hint points at the option that loses nothing. A "deleted on one device, edited on another" clash is shown as a clear, safe choice rather than a confusing diff. And new conflicts now raise a notification, so you find out right away instead of having to dig through settings.

The sync outbox page was redesigned to be clear instead of cryptic. It opens with a plain-language summary — "Everything's synced", "Sending 3…", or "2 couldn't send" — and items that failed to send finally explain themselves and reassure you they're still saved on this device. You can retry a single item or retry everything at once, and each item's technical details (payload size, retry count) stay tucked away until you tap its card, so the everyday view stays calm. Removing a queued item now clearly warns that the change won't reach your other devices.

The desktop sidebar's live-status area — the running timer, an active voice recording, and background agents — was redesigned to feel calmer and more cohesive while still reading at a glance. The old jumble of red, bordered, and monospace boxes is gone. A running timer is now a teal card and an active recording a red card, each with a coloured accent rail, the task name on up to two lines, and a big, easy-to-read elapsed time in its accent colour; the recording shows a gentle pulsing dot so you can tell it's live (it respects the system "reduce motion" setting). Background "Agents" sit just below in a quieter card. Hovering a shortened task name shows it in full, and at the very bottom the sync readout is now labelled "Outbox / Inbox" (instead of "tx / rx") and stays quiet until there's something to sync.

AI settings now include oMLX as a first-class local OpenAI-compatible provider. The Local Power profile defaults to Qwen 3.6 35B-A3B 4-bit via oMLX for both reasoning and image recognition. Sync-node capability detection also advertises reachable local oMLX instances for profile pinning.

AI settings also add a separate Local Gemma 4 (oMLX) profile backed by gemma-4-26B-A4B-it-QAT-MLX-4bit for both reasoning and image recognition, while keeping the Qwen-backed Local Power profile available as its own option.

Task and project agents now send leaner, more cache-friendly prompts to local models: open proposal details are no longer repeated in the same wake, linked task report timestamps are omitted, and trigger-token lists are rendered in a stable order.

The experimental task knowledge graph now keeps expanding as you walk through project tasks. When you walk from a project to one of its tasks, Lotti loads that task's own linked neighbourhood, adds the new nodes and links to the graph already on screen, and recomputes the merged layout so the world stays explorable instead of turning sibling tasks into dead ends.

The Task details page got a high-end, celebratory rework. The task title is the clear focal point, and the AI "Proposed changes" read as clean, colour-coded cards — on a phone each shows its change type above full-width text with visible accept/reject buttons (you can still swipe to confirm or dismiss), with a glowing sparkle badge and a clear "Confirm all" button. Your checklists now sit above the AI suggestions. Completing things is celebrated: checking a checklist item pops and strikes through left-to-right, and finishing a checklist or marking the task Done blooms a soft glow with a ring of sparks around the progress ring / status pill — tuned so it never covers the text it celebrates. Sections fade in as the page opens, everything respects the system "reduce motion" setting, and on wide screens the content sits in a centred reading column.

You can now switch the completion celebrations off: Settings → Advanced → Animations has three independent switches — for habit, checklist-item, and task completion — to turn off the glow, sparks, and pop for any of them. The brief completion haptic is unaffected, and completion itself works exactly the same; only the animation is skipped.

The experimental task knowledge graph now feels more physical: tapping or walking to a node turns the focused 1–2-hop neighbourhood into a short-lived local force simulation, with edge springs, local separation, damping, and a weak anchor back to the static layout. Walked-to nodes now get a stronger, lower-damping wobble so they keep calling attention after the camera lands, and desktop trackpads can now zoom the graph with a two-finger scroll gesture. Links stretch and settle without recomputing the graph, and the motion stops once settled and respects the system "reduce motion" setting.

The logbook (journal list) was redesigned to match the rest of the app. Every entry now uses one consistent card layout: a type icon on the left — its tile tinted with the entry's category colour, so the list colour-codes your life-areas at a glance — the entry's own content as the most prominent line, and a friendly relative date instead of a technical timestamp. Health, workout, measurement and survey entries appear with human-readable names and compact value chips — for example "Systolic Blood Pressure · 122 mmHg" and "Running · 32 min · 413 kcal · 5.6 km" — rather than raw data; checklists show their completion progress with a bar, and habit completions show a clear status. The logbook filter was rebuilt to match the Tasks page: each entry type is a labelled pill carrying its own icon, the starred / flagged / private toggles are clearer multi-select pills, and category pills show their colour.

The Habits tab was reworked to match the rest of the app: the same calm, light-on-canvas surfaces as Tasks and Time Analysis instead of the old near-black background, with a Time-Analysis-style header. A new summary card shows how many habits you've done today, how many are left, and your current streaks at a glance. Your overall consistency now reads as a scrollable heatmap — a month-labelled calendar of week columns where each day is shaded by how many of your active habits you completed that day, like a contributions graph. It spans the full width of the window and scrolls back through months and years with today pinned to the right edge; quiet (not-yet-done) days stay a plain neutral rather than looking like failures, and every cell announces its date and count to screen readers. The habit list is now lean and action-focused: each row shows its own streak, a clear "+" button to log it in one tap (turning into a green check once done), and you can still swipe right to mark it done or left to mark it missed. The recording dialog was rebuilt around a Success / Skip / Missed segmented picker with one Record button, and a linked dashboard now sits cleanly above the form. The completion-rate chart now opens with a headline — your 7-day average, whether it is up or down versus last week, and how far it is from your goal — above a smooth average trend line that climbs through a shaded "on track" band, with a quiet pointer to the one habit most worth a focus. Logging a habit is now a small, staged celebration — the check pops, a soft glow blooms on the row, a burst of sparks flies from the check, the streak ticks up, and finishing the day lights the summary card — all respecting the system "reduce motion" setting and announcing completion to screen readers.

Editing an entry's start and end time is simpler: you set the date once and the start/end times separately, instead of picking the full date on both pickers. One date wheel sits above paired start/end time wheels, with a live duration. If the end time is earlier than the start, it automatically rolls to the next day and shows a "+1 day" badge — so logging something past midnight needs no extra steps. For entries that span different days, an "Ends on another day" toggle reveals a separate end date.

Creating a project now opens a compact overlay — a bottom sheet on phones, a centered dialog on desktop — instead of taking over the whole screen. The fields are unchanged (title, category, target date), and the new project shows up in the list as soon as you save.

When the image provider turns down a cover art request, the modal now says the provider rejected it and shows the provider's own reason verbatim (for example "PROHIBITED_CONTENT") instead of a generic "Failed to generate image" — so it's clear the block is the AI provider's content policy, not Lotti, and you can reword the request and try again.

Every button across the app now uses one unified style, and modal action bars share one layout where the confirming action is the wide, dominant button and the cancel/secondary actions stay compact beside it. Disabled buttons now clearly read as inactive — a flat, greyed-out pill — instead of a faded version of their active colour. This covers every previously divergent surface, including the delete-confirmation dialog, the date/time and task due-date/estimate pickers, the journal entry date-range editor, the Matrix sync screens (setup, bundle import, device verification, and the maintenance modals), the AI settings screens (error/retry states, provider setup, and delete dialogs), health import, the agent editors, and habit completion.

Fixed: on phones, save and action buttons on several settings detail screens were hidden behind the bottom navigation bar, so the action couldn't be tapped — most visibly the Save button on the AI provider setup screen (for example after pasting a Gemini API key). These screens now keep the whole bottom edge: the AI provider connect/edit form, the agent template and soul editors, the sync conflict resolver, and the agent evolution chat input all stay clear of the navigation bar, so their actions are reachable.

Coding prompts generated from an audio note now attach to the parent task — the same way cover art does — instead of hanging off the individual audio entry. Because each coding prompt becomes part of the task, follow-up prompts can build on the ones that came before, so you can record a new note asking to continue from an earlier prompt and it has that context. A new "Code" filter pill above a task's linked entries lets you show or hide coding prompts, alongside the existing Timer, Audio, and Images toggles.

On Linux and Windows you can now import images from a native file dialog via the "+" create menu, and dragging images or audio files onto a task or entry now works on Linux — a drag-and-drop plugin conflict had been silently swallowing every drop, so Lotti now uses a single drag-and-drop system on every platform.

Experimental on-device text-to-speech is now available on Linux too: with the "Enable local AI summary playback" flag on, the AI summary card's play button reads a task's TL;DR aloud, synthesized locally with the Supertonic model — no cloud. Still off by default; the model (~400 MB) downloads once on first use.

On phones, the Sync settings list now follows the same order and layout as the desktop settings tree, so the two surfaces no longer disagree. The provisioned-sync QR pairing entry is the first row in the list (Provisioned Sync, This device, Backfill, Stats, Outbox, Conflicts, Matrix maintenance); the Sync rows keep their teal icons, and the Outbox row shows the teal postbox with its live pending-sync count badge — now on desktop too, not just mobile.

Category selection is now one consistent picker across the app: assigning a category (entries, tasks, projects, habits, dashboards, time blocks) opens the same searchable sheet and applies on tap, and the habits and dashboards category filters use that same sheet with an Apply button instead of toggling on each tap.

A task's labels now open in that same picker — a searchable, multi-select sheet scoped to the task's category (plus any labels already assigned), with an Apply button and the option to create a new label inline.

Search fields no longer sit in a darker box than their surroundings in dark mode: every search field (tasks, settings, the category and label pickers) is now a subtly raised field that matches its surface instead of a sunken dark well.

On macOS and iOS: experimental on-device text-to-speech reads a task's AI summary aloud — its TL;DR, or the full report when expanded — synthesized locally with the Supertonic model, with no cloud involved. Choose the voice, model, and reading speed under the new Settings → Speech page. Off by default; opt in via the "Enable local AI summary playback" flag. The model (~400 MB) downloads once on first use.

Settings (mobile): the Settings menu was rebuilt to match the desktop tree — the scroll-shrinking title header is replaced by a fixed header above a clean drill-down list whose rows (icon, title, and a full, no longer truncated description) are the same as the desktop sidebar, built from a single shared definition so phone and desktop read as one product. Tapping a section drills in (Definitions, Advanced) or opens it directly (AI, Agents, Sync, Theming); back returns one level instead of jumping to the top, and rows grow to stay legible at large system text sizes.

Settings: every settings page now wears one consistent header — the scroll-shrinking title is removed throughout (not just on the menu), and the section lists, editors, sync, and AI pages all use the same fixed title typography and the same back button in the same position instead of each page carrying its own header. The left gutter of the list rows was tightened on both phone and desktop.

Insights dashboards: the chart cards were rebuilt on the app design system — no more near-black chart boxes in dark mode, rounded evenly-spaced axis ticks with legible labels including the top value, a shared date-axis cadence with edge labels that no longer clip, bars and lines reaching the same right edge in one higher-contrast series colour (the Steps chart keeps its bars colour-coded by your daily step goal), a blood-pressure systolic/diastolic legend with a calmer 80/100/120 value axis, a single per-card caption (unit, description, or aggregation), a weight chart titled "Weight", and an explicit "No data in this range" state. The add-value (+) button on measurement and survey charts now stays inside the card on desktop instead of being pushed off-screen. The time-span selector now uses the shared design-system segmented control (the same one as the Daily OS plan switch and Time Analysis), the habit card matches the other chart cards (no more near-black box), and the chart cards are inset to align with the dashboard title instead of hugging the screen edges. The dashboard header is now a stable bar — the title and the time-span picker sit together and no longer shrink or scroll away — with a link beside the picker to edit the dashboard's definition (opening in a side panel on desktop, full-screen on mobile).

Measurement entry: logging a value (the + on a dashboard chart) was rebuilt on the design system — a large hero value field with the unit inline ("750 ml"), one-tap Quick-add chips for your most-used amounts directly below it, a clearly-editable observed-at row, an optional comment, and a Save button that stays put and enables once the value is a valid number (Enter saves too).

Habit completion: tapping a habit's row while viewing its dashboard no longer re-opens that same dashboard behind the completion sheet — the sheet shows just the completion form. Opening the habit from the Habits tab still shows the linked dashboard for context.

Settings: all definition pages (categories, labels, habits, measurables, dashboards) now share one design language. Lists get the same header, search, grouped rows, floating create button, and localized empty states; editors share a sticky bottom action bar floating on blurred glass with Save/Create (enabled once something changed), Cancel, and Delete with confirmation, Cmd/Ctrl+S keyboard save, design-system fields in titled section cards, and consistent "Edit habit"/"Edit category" titles without stray label colons.

Settings: creating a category now opens the same full create page as other definition types instead of a popup — it asks only for name, color, and icon, then lands in the new category's editor for the rest. The Projects section moved out of category settings (projects have their own page), and on desktop habit editing opens inline in the settings split pane.

Settings: dashboard editor save-and-copy moved to a header action, and saving with an invalid form no longer navigates away while silently discarding changes.

Time Analysis (desktop): the wide date-range row is replaced by a compact period stepper — pick a granularity (Day / Week / Month / Quarter / Year) and browse to the previous or next period with the arrows; the dashboard updates live as you step, with no dialog. Weeks follow your device region — starting on Monday across most of Europe and on Sunday in the US — both in the stepper's week periods and in the jump-to-date calendar grid. MTD and YTD shortcut pills stay on the row: one click jumps to the current month-to-date or year-to-date, and with Compare on they line up against the same elapsed days of the previous month or year.

Time Analysis (desktop): tap the period label to open a calendar and jump straight to any date's period; the dashboard updates live behind the sheet as you pick.

Time Analysis (desktop): a Compare toggle puts the current period side-by-side with the one immediately before it — the headline tile shows the change versus the previous period and the per-category table gains Previous and Change (Δ%) columns. The comparison is honest about in-progress periods, weighing the same elapsed days against last period's same days rather than a half-finished week against a whole one, and the change arrows stay neutral for sub-1% noise. The chart stays a single clean series and points to the table for the comparison instead of crowding in a ghost reference bar.

Daily OS Next: the day-planning conversation was redesigned around a stable voice orb — it stays put directly above the action bar in every state while the live transcript grows upward above it, reacts to presses with a visible ripple and press animation, and while recording its core breathes with your voice (with a slow idle pulse between words) under a stop glyph, then steps back after capture so the Review action carries the weight. Every action lives on the sticky bottom bar in every state, and a per-state headline narrates what is happening.

Daily OS Next: on desktop, day planning now opens in a full-height right side panel instead of a centered dialog, keeping the day visible while you talk; panel buttons size to their content.

Daily OS Next: the drafting wait replaced its shimmer placeholders with the AI thinking animation over a rotating narration of what the agent is doing, alongside yesterday's learning cards.

Daily OS Next: the Refine step was rebuilt on the same layout as Capture — it shows the current plan you are about to change, streams your words above the orb, and offers Revert / Looks good on the bottom bar.

Daily OS Next: copy and typography polish — a "Review" CTA instead of "Reconcile", a real headline on the review step, typographic apostrophes, and large accessibility text sizes no longer overflow the capture sheet on small phones.

Daily OS Next: the day view reads as paint-by-numbers — planned blocks are a faint sketch of their category color (dashed while drafted) and recorded sessions carry the full, alive color; the timeline opens centered on the now-line, which spans both lanes, and short blocks no longer clip text.

Daily OS Next: a calmer agenda — finished items collapse into one-line receipt rows, metadata became quiet icon+text instead of pill rows, and the capacity ring is a thin stacked category ring matching the legend with remaining time in the center.

Daily OS Next: the day page gained an Apple-style large-title header (quiet back chevron, weekday-first date overline, one left rail), first-run coaching that retires after one use, content that dissolves at the fold instead of being cut, a capacity card that leads with the time you have left and a receipt-style legend, and every concrete date now carries its weekday.

Daily OS Next: learnings the planner wants confirmed now surface on the day page as a quiet "things I noticed — review" chip plus a permanent "What I've learned" menu entry, on both mobile and desktop.

Light theme contrast: secondary text and the teal accent were too faint to read (about 2.2:1); light-mode secondary text is darker now and the teal accent chain is deeper, so captions, hints, and white-on-teal buttons meet accessibility contrast. Dark mode is unchanged.

The Daily OS planner now sees the last week in context when drafting a day: planned-vs-recorded time per category, missed sessions by name, and upcoming plans plus deadlines for the next five days. It also keeps a short note on how each day actually went, written as the day closes, and reads those notes back later — so after an overworked stretch it plans a gentler day instead of piling on. Sustainability over throughput.

Mobile: the bottom navigation bar no longer crams every destination into one row with shrinking labels. It fills with as many destinations as comfortably fit the window and text size: on narrow screens it shows Tasks, DailyOS (when enabled), and Logbook plus a "More" slot, with Settings and the remaining flag-gated destinations (Projects, Habits, Insights) in a More bottom sheet — that's also where newly toggled pages appear, and the Settings row shows its pending-sync count on the right like the desktop sidebar does. The More slot takes the active destination's name and highlight while a sheet destination is on screen. As the window gets wider, destinations move out of the sheet into their own slots one by one — always in the same order and positions — until everything fits and the More slot disappears entirely; a larger system font widens the labels and brings the overflow back sooner. Daily OS moved directly after Tasks across mobile and the desktop sidebar. The bar docks flush against the bottom screen edge with the home-indicator inset absorbed into the bar surface, and its top corners use the gentler card radius.

Mobile: opening a settings entity-definition editor — the detail or create page of a category, habit, label, dashboard, or measurable, or a project editor — now slides the bottom navigation bar smoothly below the screen edge, giving the editor the full height, and slides it back in when you leave; the list pages keep the bar in place. A running timer or audio recording indicator stays visible throughout, dropping to the screen's bottom edge while the bar is away.

New desktop "Time Analysis" dashboard under Daily OS, opened from a sidebar entry beneath the month calendar onto the full screen: see where your time went per category and per day, with quick range presets (1d, 7d, 30d, MTD, YTD, last month), a custom date range, a daily/cumulative chart toggle, headline totals, optional focus categories, and a precise per-category table. Range switching is instantaneous even with years of entries, and private entries stay hidden unless the private flag is on.

Time tracked on entries created before mid-2024 could show up as "Uncategorized" in time-by-category views; the category data is now backfilled once on upgrade.

Daily OS Next: tapping a recorded session on the Day timeline now reopens its task scrolled to — and briefly highlighting — that exact entry again, instead of dropping you at the top of the task.

Daily OS Next: the sidebar month calendar now starts the week on your device region's first weekday — Monday across most of Europe, Sunday in the US — read from the OS region rather than the app language, instead of always starting on Sunday.

Task and project lists stay snappier under sync: a task's project is now resolved from a denormalized, indexed column and batched across rows instead of one query per task, and the projects overview plus the saved-filter sidebar counts coalesce rapid update notifications into a single refresh.

The desktop sidebar's running-timer card now stays visible the whole time a timer is running, instead of hiding while you view the running task or after navigating away from the Tasks tab. The elapsed time and the quick jump-back button now persist in the sidebar everywhere — including alongside the task's own running indicator when that task is open.

Categories: a new opt-in "Day planning" switch controls which categories are available for selection in the day plan — nothing is available by default.

Projects: a new "Monitoring" status for projects that are not closed but have no time actively scheduled.

Task agents now maintain their own day-planning attention requests during normal wakes, resolving stale requests when tasks are done or no longer need scheduled time.

Slow-query logging now starts from persisted logging settings during startup, so enabled slow_queries and super_slow_queries files capture boot-time database work instead of waiting for the next settings toggle.

While the Daily OS tab is active, its desktop sidebar entry expands into a month calendar: today is highlighted, days with a Daily OS plan carry a dot, and tapping a day jumps straight to it.

Daily OS Next: a day with tracked time but no plan now opens on the Day timeline so recorded sessions are visible without drafting a plan first, with an honest "No plan yet" capacity strip and a "Speak a check-in" button into Capture.

Daily OS Next: a bounded "Today so far" card shows the day's recorded sessions on the Capture screen and on the empty Agenda tab, collapsing older sessions behind an expander.

Daily OS Next: agenda items and day blocks now show whether they are backed by a task (blue link badge that opens the task) or are standalone time blocks, and standalone titles can be renamed inline.

Daily OS Next visuals now follow the latest design handoff: a capacity donut replaces the linear meter, recorded sessions render in a neutral tracked treatment, drafted blocks carry a dashed outline, the commit sign-off composition was reworked, and typography across the feature is calmer.

Daily OS Next day planning now forces required draft tool calls through Gemini and Mistral providers and keeps fast completed drafts from being dropped while learning cards load.

The linked entries "Filter and Sort" modal now has a "Show flagged entries only" toggle that narrows the list below a task to flagged entries, updating immediately when the toggle or an entry's flag changes.

New "Agent fork healing" flag in Settings (off by default): agents whose histories diverged through multi-device use merge them back together at the next wake.

Agent memory compaction now runs by default for task, project, and day agents, and the Settings flag that controlled it has been removed.

Config flag changes from Settings now sync to your other devices when a flag is flipped, without broadcasting default startup flag seeding.

Label usage counts in the labels list no longer include deleted journal entries, and entries marked private only count while the "Show private entries" flag is enabled.

Task-agent suggestions now suppress verbatim duplicate proposals even when their underlying tool arguments differ, so identical checklist suggestions appear only once.

Daily OS Next capture wakes now retry with a forced parse step when the first model response skips parsing, so Reconcile no longer stays stuck with an empty "Here's what I heard" column.

The "Agent memory compaction" flag now also covers project and day agents: all three read their context from an append-only memory log and summarize its oldest entries into a rolling memory using their own model.

Saving an event now clears the unsaved-changes state, so the save button no longer stays visible after a successful save.

Buttons that customize the primary button style now apply their custom disabled color instead of silently falling back to the default.

New "Agent memory compaction" flag in Settings (off by default): task agents summarize older task-log entries into a rolling memory using their own model, keeping the wake context compact while recent entries stay verbatim.

Task agents now update their report only when its content would materially change, instead of re-publishing it on every wake.

Task agents can now propose archiving a duplicate or obsolete checklist item, confirmed through the usual proposal flow and reversible.

The agent conversation view now shows each wake's exact system prompt as an expandable row and labels milestone and retraction rows distinctly.

Task agents now fall back to a pending title-change proposal when the immediate initial-title write is blocked by category policy, instead of repeatedly reporting a policy-denied tool error.

Task detail pages now show running AI activity as subtle shader-based decoder bars integrated into the sticky action bar, replacing the separate Siri-wave strip above it.

Daily OS Next voice capture now wraps the record button with the dBFS-driven tension-loop shader while listening, and shows reviewed transcripts in a calmer fixed-height review panel.

Task due-date urgency now uses calendar-day comparisons, so overdue and due-today styling stays correct across daylight-saving transitions.

Plain-text journal and comment content with quotes, backslashes, or line breaks now stores valid rich-text editor data instead of interpolated JSON fragments.

CSS hex color parsing now rejects malformed strings with embedded valid colors, keeping fallback colors predictable for invalid input.

AI chat streaming now preserves split reasoning close markers and final soft line breaks when providers deliver responses one character or token at a time.

Settings → Advanced → Logging now has an individual on/off switch for every logging domain (sync, AI, chat, speech, persistence, database, agents, tasks, health, habits, and more), replacing the previous three fixed toggles. Errors are always logged regardless of these switches, and are mirrored into two daily files: a full error log and a PII-safe error log that records the error type only.

Backfill sync now distinguishes intentionally burned vector-clock counters (benign voided numbers in the monotonic sequence) from genuinely unresolvable entries, with a separate "Burned" count in the Backfill settings screen, so newly burned counters are no longer reported as data loss. Entries already marked unresolvable keep that label until they settle into the correct bucket as peers are re-asked.

Daily OS Next refine-by-voice now opens as a responsive Wolt modal over the current plan surface, and keeps the reviewed transcript visible with inline feedback when a proposal fails or produces no usable changes.

Daily OS Next measures the date controls, Agenda/Day switcher, and header actions before placing them, keeping the switcher inline whenever it fits and moving it below only on truly constrained widths.

AI popup skill runs can override the Gemini thinking effort for a single invocation after choosing the model, so one saved model row can still be used with different thinking budgets per use case.

Daily OS Next now ships the full voice-first agentic surface — capture, reconcile, drafting, day-plan, refine-by-voice, commit, and shutdown screens — behind the existing feature flag, with localized copy in all supported languages.

Daily OS Next now personalizes the greeting from Settings > Advanced > About, lets typed capture start from the idle screen, filters processing categories, wraps mobile task titles, compares planned and actual timelines with a shared scroll/zoom surface, folds idle midnight-to-midnight day gaps with a 24-hour time rail, shows recorded journal time in the Actual lane, keeps task-backed agenda titles in sync, refreshes without whole-page loading flashes, and avoids surfacing weeks-old overdue tasks in daily proposals.

Daily OS Next agenda rows now use a cleaner mobile-first layout with task cover art thumbnails, tighter metadata pills, token-backed progress, and task-backed Day timeline blocks and task-report links that open the linked task inside the app.

Daily OS Next drafting now carries approved new capture items into planning, counts buffers as scheduled time while excluding dropped blocks, labels due and overdue work relative to the selected plan date, and uses localized capture error copy.

Mobile Daily OS reconcile controls now reserve the bottom navigation hit area, and bottom navigation labels have additional breathing room on platforms without a home-indicator inset.

Sticky glass footers in Tasks and Daily OS now use a token-backed scrim so action controls stay readable when bright screenshots or light-mode content scroll underneath them.

Sync diagnostics and backfill stats put less load on the database, reducing sync-related stalls and improving responsiveness on busy machines.

Improved sync reliability: fewer unresolvable gaps and more dependable delivery of local edits across devices.

Matrix sync now recovers automatically from stale empty downloads, so media and JSON attachments arrive more reliably without manual retries.

Fixed: agent task suggestions stay stable while the agent is working — they no longer flash empty or reshuffle as the agent revises them, and acting on one suggested checklist item no longer makes the others disappear.

Gemini model settings now include a configurable thinking mode with minimal, low, medium, and high options; existing models default to low for faster inference unless changed.

Active audio recordings now show a prominent desktop sidebar card above the running timer, with a larger speech-weighted dBFS-reactive recording orb, red signal-reactive frame, subtle red shadow, elapsed time, and one-tap stop control so runaway microphone sessions are harder to miss.

Audio and image entry Actions menus on desktop can now reveal the backing file in Finder, File Explorer, or Files.

Daily OS day-agent capture/reconcile tooling now persists captured text, parses it into task decisions, links it to existing tasks, and applies triage actions through the agent backend.

Tasks navigation no longer shows the global in-progress task count badge in the sidebar or bottom navigation; saved filters remain the focused way to monitor task subsets.

Daily OS Next day planning now lets you edit capture transcripts before reconciliation, creates real tasks from new capture phrases, opens task-backed agenda rows, rejects new same-day draft blocks that start in the past, amends approved plans through per-change tracked diff approvals, replaces the cramped capacity donut with a linear meter, lets you review and edit refine transcripts before they reshape the plan, uses real audio transcription on the refine screen instead of a scripted sample diff, and prefers Mistral cloud speech recognition over MLX when both are configured.

Gemini-backed speech recognition, Daily OS day planning, and task-agent wakes now respond faster on interactive turnaround.

Agent batch lookups for latest per-agent reports and states now use ranked active-row indexes that avoid SQLite temp sorts during large project-agent wake context builds.

Sync now preserves local sequence mappings when recovering burnt vector-clock counters, reducing cases where peers can get stuck on unresolvable gaps.

Fixed: task-agent suggestions no longer disappear wholesale while an agent wake is running, and stale running-timer update proposals are automatically retracted if the timer stops before you accept them.

Fixed: agent workflow diagnostics no longer write suggestion argument values or raw exception text into runtime log files.

Fixed: the Create Category modal's colour picker no longer overflows on desktop — the hue slider used to be clipped off the right edge of the modal, leaving the colour ungrabbable.

Fixed: the task detail action bar no longer shifts or leaves faint ghost shadows behind the Track time, audio, checklist, and more-action buttons when time recording changes state.

AI popup menu now opens a model-override picker when you tap an Analyze Image skill, mirroring the existing Transcribe flow — the bottom sheet lists every image-capable model you've configured so you can route one specific photo to a different model without editing the inference profile. Single-model setups short-circuit to preserve the one-tap flow; a stale override falls back to the profile slot.

Upgraded Flutter to 3.44.0 and aligned the Flatpak Flathub manifest template with the repository FVM toolchain pin, so source builds submitted to Flathub use the same Flutter SDK as local and CI builds.

AI popup menu now opens a model-override picker when you tap Transcribe on a voice note. The bottom sheet lists every speech-capable model you've configured — the profile's default marked with a (default) badge and a check at the top, alternatives below — so you can route one specific transcription to a different model (e.g. cloud Mistral instead of local Voxtral) without changing the entire inference profile. When only one speech-capable model is configured the picker short-circuits, preserving the one-tap flow for the common case. A stale override falls back to the profile's slot rather than stranding the user.

Inference-profile model slot picker now has a search field at the top. Substring match runs against the model display name, the wire-level providerModelId, and the resolved provider label — so typing "Google" surfaces every Gemini-owned model even when the row text doesn't start with the provider name. When the query matches nothing, the picker shows the existing "No matches" empty state instead of leaving the list region blank. Clearing the query restores the full slot-filtered list.

AI Settings — the legacy "Select Provider Type" sheet has been folded into the modernized "Set up AI features" picker. Power users who previously dismissed the FTUE prompt, and the in-form provider-type switcher inside the provider edit page, now open the same modern modal in a non-FTUE mode that hides the subtitle, footer hint, and "Don't show again" button while surfacing every InferenceProviderType — including OpenAI-compatible, OpenRouter, Nebius, Mistral, and Whisper — alongside the curated branded tiles. One widget, one visual language, no provider type unreachable.

"Add Model" from inside a provider's detail page now preselects that provider on the new-model form, so the user no longer has to re-pick the provider they just came from. The top-level "+ Add model" FAB still opens a blank form where the user picks the provider manually. Edit-mode (existing model) is unaffected — the form continues to honor the model's stored inferenceProviderId and ignores any stray preselection arg.

Synced-notifications bell in the Tasks and Projects tab headers. The icon flips from outlined to filled and shows an unread count badge (capped at 9+) whenever there are unseen alerts, driven by a new Riverpod provider that listens on UpdateNotifications.updateStream so the badge stays in sync with the database. Tapping the bell opens an anchored popover that lists the pending alerts: each row shows the title and body, tapping deep-links into the linked task and marks the alert acted-on, and the dismiss icon (or a long press) retracts the alert. All entry points stay behind the existing enable_synced_alerts master switch and reuse NotificationRepository, so every change syncs to other devices through the existing Matrix sync pipeline.

MLX Audio is now macOS-only. The iOS Runner no longer links mlx-swift, mlx-audio-swift, or swift-huggingface and no longer registers the MlxAudio plugin, which strips the on-device STT runtime that triggered immediate OOM with the 1.7B Qwen3-ASR model on iPhone hardware and shrinks the iOS bundle. iOS now reports MLX models as unsupported the same way Android and Linux already did. Audio recorded on iOS still reaches MLX through the existing synced-audio auto-trigger flow on a paired macOS desktop — the sync-node capability probe already gates the mlxAudio capability on macOS, so deferred inference continues to work unchanged.

Category pickers now share the same look across the app. The task filter's Category sub-modal gains a search bar at the top (matching the Settings → Categories Definition page), and both the filter sub-modal and the category modal opened from the task definition page now anchor their action button inside a DesignSystemGlassStrip footer, so list rows scroll behind the blurred bar instead of being pushed off-screen. The task definition modal also swaps its LottiSearchBar (gradient-filled in dark mode) for the flat, border-only DesignSystemSearch used by the settings page.

Desktop slow-query hot paths now avoid several major sources of UI stalls: sync outbox claims and sync-sequence watermark reads use SQL shapes that match their partial indexes, editor draft restore has a composite draft lookup index, agent active-row reads gain dedicated partial indexes, and the agent/task summary paths resolve templates, active soul documents, task-agent links, and latest reports in batches instead of issuing per-row link and entity lookups.

Fixed: sync outbox polling now uses priority-first send-order paths for pending and expired in-flight rows, avoiding temp B-tree sorts in the hot dequeue loop while letting journal/link updates drain ahead of older agent work. Sequence-log watermarks are now persisted per host after a lazy first read, so hot gap detection reads one primary-key row instead of recomputing the contiguous prefix with a ROW_NUMBER scan over the sequence log. Inbound stranded-room pruning now also has a literal-status partial index over active queue rows, and journal sync diagnostics report rows written as a count instead of leaking SQLite rowids.

Fixed: incoming agent entity/link sync now respects vector-clock dominance before overwriting local agent state, while still recording skipped stale/equal payloads in the sequence log.

Fixed: habit completion reads now enforce last-write-wins per habit/day, so repeated success/skip/fail updates on the same date resolve to the newest persisted write instead of depending on database row order.

Fixed: Flatpak release generation now carries exact ObjectBox 5.3.2 offline source hashes and a CRLF-tolerant CMake patch, plus a PR-safe validation job that dry-runs Flatpak foreign dependency patches against the locked Pub packages after dependency updates.

Fixed: agent wakes no longer abort when synced duplicate model rows leave the first providerModelId match pointing at a deleted or unusable provider. Provider resolution now skips stale candidates and prefers the usable provider with the known matching provider type, while known-model backfill and FTUE setup stop seeding duplicate rows for the same provider-native model ID unless the existing row is orphaned and needs repair.

Task-agent proposal ledgers no longer surface retired suggestions as open work. Consolidating multiple pending change sets now marks pending items in the retired source sets as retracted, and the ledger reader filters historical resolved-parent/pending-child snapshots plus stale rejection or retraction decisions before the prompt and AI summary card see them. retract_suggestions also treats fingerprints already present in the resolved ledger as not_open rather than not_found, avoiding repeated model retraction loops.

Fixed: task-agent suggestion notifications now enforce one active bell row per task. Fresh agent waves still get durable change-set-seeded rows, but the repository serializes same-task notification mutations, retracts older open rows before surfacing the latest pending count, and bulk-clears every open suggestion row when the user or agent resolves the proposals. Tapping a suggestion notification now also focuses the task-agent proposals section, including when that task detail is already open.

Synced notifications data layer: a separate notifications.sqlite store, Freezed notification entities, Matrix sync payloads for full alerts and state updates, backfill coverage, and macOS/iOS scheduler plumbing behind the new enable_synced_alerts flag.

Automatic AI inference pickup on capable desktops when a mobile device syncs an audio entry. Each node broadcasts a sync node profile (display name, platform, detected capabilities — MLX Audio, Ollama, Voxtral, Whisper) over Matrix and maintains a local directory of peers. Inference profiles gain an optional pinned device: when a mobile-recorded audio entry arrives via sync and its responsible profile is pinned to the local host and the profile is fully local (every populated model slot resolves to MLX Audio, Ollama, Voxtral, or Whisper), the desktop runs the existing transcription skill and nudges the wake cycle — no manual transcription, no cloud routing. Pinned host offline = entry stays untranscribed; the user can re-pin. New AI Settings "This device" page edits the local display name, shows detected capabilities, and lists known peer nodes. The inference profile edit page exposes the Pinned device selector, filtered to peers that advertise the capabilities the profile actually needs.

Live API-key verification on the AI provider connect form. As soon as you stop typing in the API key or Base URL field, the form checks the credentials against the provider's API and shows a status strip below the Base URL with one of three outcomes: a spinner while the check runs, a green confirmation with the number of models the key can see and the response time, or a warning row explaining what went wrong (invalid key, network error, timeout, unreachable host) with a Retry button. Covers Gemini, OpenAI, Anthropic, Mistral, Alibaba, OpenRouter, Nebius, and Ollama out of the box — no more saving the form and hoping the key works.

AI Settings delete confirmations now use the same design-system toaster that the checklist row uses (warning tone, 5-second countdown bar, Undo action), replacing three custom hand-rolled SnackBars for provider, model, profile, prompt, and skill deletions plus the failure path. The provider cascade list, previously rendered as a custom bullet block inside the SnackBar, now collapses into the toast description so long lists ellipsize naturally. All copy moved into the new aiDeleteToast localization keys across English, Czech, German, Spanish, French, and Romanian (informal register).

Profile cards in AI Settings now pin the overflow menu to the far right of the card header — matching the provider cards — instead of letting it drift next to longer profile names.

Alibaba Cloud (Qwen) promoted to a first-class FTUE option. The pick-provider modal now carries a fifth tile for Alibaba with the NEW badge, sitting between Anthropic and Ollama, and the zero-providers state card adds a matching fifth chip in the same position. Alibaba also gets its own brand-orange accent token and a "Qwen models · multimodal · long context" tagline so its tile and cards no longer fall back to the neutral interactive accent. Translations land in all six locales (informal tone).

MLX Audio (local) provider scaffolding for embedded Apple Silicon speech. AI setup now offers MLX Audio, seeds Voxtral, Qwen3-ASR, Parakeet, and Qwen3-TTS model rows, prompts for model installation, and shows native download progress on both model overview and provider detail surfaces. Post-recording transcription routes through a guarded Swift channel. AI-summary playback remains wired through the same channel on macOS but is hidden behind the default-off enable_ai_summary_tts config flag while local TTS is evaluated. The iOS target does not link MLXAudioTTS yet because its Moss TTS target is not archive-safe on iOS; iOS speakText returns unsupported while STT remains linked. Intel macOS and builds without the MLX Audio Swift SDK keep compiling and report the feature as unsupported instead of loading Apple Silicon-only libraries.

MLX Audio now also offers Qwen3-ASR 1.7B 4-bit and 8-bit model rows for local post-recording transcription tests on macOS and iOS. First-run MLX Audio setup now lets users choose which local STT model to install, with Qwen3-ASR 1.7B 8-bit preselected because it is materially faster than Voxtral Realtime for post-recording transcription. Batch transcription prefers configured MLX Qwen3-ASR models so speech-dictionary terms can be passed as Qwen prompt context; the realtime code path remains in place but its UI toggle is disabled until live transcription can use comparable biasing. MLX model download status is now held in a shared progress store so overview cards, provider-detail cards, and the modal render the same live percentage and the progress modal can be reopened while a download is running. Speech recognition can also fall back to a configured audio-to-text model directly when no applicable inference profile is available, which keeps local MLX STT usable on mobile without requiring a desktop-only profile. The native bridge now refuses transcription against missing or partial MLX models instead of starting an implicit background download from an inference call, and logs memory-stage diagnostics around model load and generation for crash investigation.

AI Settings Profiles tab Active badge now reflects whether the profile is the winning candidate for at least one configured provider — the same rule the provider detail page already uses for its Active profile section. Previously the badge was wired to profile.isDefault, which the seeder stamps on every shipped profile, so every seeded card lit up the green badge regardless of whether the user had actually wired the underlying provider. The picker logic moved into a shared util so both surfaces consume the same definition. Configured mirrors AiProviderCardStatus.statusFor returning connected: cloud providers need a non-empty API key (drafts are skipped), and Ollama needs a non-empty base URL plus at least one model row — the badge can no longer light up while the underlying provider card reads Invalid key or Offline.

The Local Power (Ollama) seeded profile now uses qwen3.6:35b-a3b-coding-nvfp4 (35B MoE / ~3B active, NVFP4 quant, 22GB download, 256K context, text-only) as the thinking model, with qwen3.5:27b retained as the image-recognition model. The Qwen 3.6 coding MoE is also added to the known Ollama model list so it can be selected from the model picker.

Category tags now pick black or white text based on the background brightness instead of a fixed palette colour, so the label stays legible on dark category colours (e.g. the seeded Ollama charcoal #0F172A) and bright ones alike.

The AI provider setup-result modal (the post-FTUE "{Provider} is connected" sheet) now ships a single "Start using AI" CTA instead of pairing it with a secondary "Review setup" button. The CTA fills the row on mobile-width surfaces and pins to the right with a comfortable cap on desktop / tablet dialog widths, so the one-button footer reads as a deliberate primary action at every breakpoint.

Added: Voxtral (local) tile in the AI Settings pick-provider modal, carrying the same DESKTOP ONLY badge as Ollama. Picking it routes to the connect form preselected to Voxtral with the default base URL (http://localhost:11344) prefilled and no API key required. Previously the picker only listed Gemini, OpenAI, Anthropic, and Ollama — there was no UI affordance to add a Voxtral provider, even though the rest of the runtime (repository, default URL, known models, chip + visual) had supported it for some time.

Fixed: adding a second provider after tapping Don't show again on the FTUE pick-provider modal no longer strands the user on a generic-OpenAI-prefilled connect form. The dismiss flag was routing every subsequent Add tap to the create form with no preselected type, and the form defaults that case to genericOpenAi — so users who set up Gemini first and then wanted Ollama saw an OpenAI-compatible setup with no surfaced way to switch types. The handler now routes dismissed users through the legacy ProviderTypeSelectionModal which lists every InferenceProviderType including Ollama, Voxtral, Whisper, OpenRouter, Nebius, and the generic OpenAI fallback, so the multi-provider setup flow (e.g. Gemini then Ollama) works the same regardless of whether the dismiss flag is set.

Fixed: agent wake-cycle deadlines now survive app restarts as executable work. Persisted nextWakeAt rows are restored into the in-memory wake queue, so a deferred 06:00 wake that becomes due while the app is closed runs after the next launch instead of lingering in the sidebar as stale. Completed subscription wakes also stop writing cooldown-only nextWakeAt rows when no follow-up job is queued, so the Wake Cycles list only shows work that can still run.

Fixed: speech recognition and other entry-level AI skills now run on standalone audio, text, and image entries that have no parent task, using the entry category's default inference profile. Previously the AI popup-menu trigger silently no-oped whenever an entry had no linked task, so users with a category configured for Ollama + Voxtral could open the menu and tap Transcribe with no feedback and no transcription. The popup also hides skills that require the full task context (cover art, coding/design/research prompts, the in-Task-Context transcription and image-analysis variants) for standalone entries — the menu only offers what the entry can actually run.

AI Settings FTUE pick-provider modal. Tapping the Add provider button on the AI Settings page now opens a centered AiPickProviderModal first instead of jumping straight to the empty connect form. The modal carries a Set up AI features title, a one-line subtitle, and four big provider tiles (Gemini RECOMMENDED, OpenAI, Anthropic NEW, Ollama DESKTOP ONLY) with radio-style selection. Footer hint pins the reassuring Your API key is stored locally copy plus a secondary Don't show again and a primary Continue button. Picking a tile and hitting Continue routes to the connect form preselected to that provider type. Tapping Don't show again writes a settings flag (AI_PICK_PROVIDER_DISMISSED) so subsequent FAB taps go straight to the form.

DRAFT badge on half-configured provider cards and on the provider detail header. A cloud provider with no API key yet renders a secondary-toned outlined DRAFT badge next to the provider icon on the AI Settings cards and inline with the display name on the detail page header. Local providers (Ollama, Whisper, Voxtral) never need a key, so they are never reported as drafts.

Shared back-affordance for the AI Settings detail pages (provider detail, inference model edit, inference profile form). On mobile or pushed stacks the back button pops; on the desktop master/detail panel where the page sits in the panel slot it falls back to beaming /settings/ai. Fixes the back button does nothing regression on the desktop surface that previously left users stuck on a detail page with no exit.

Inference profile form chrome aligned with the rest of the AI Settings v5 pages. Scaffold and AppBar now use the AI Settings surface tone (background level 01), the AppBar is flat (elevation 0), the title uses subtitle1 typography, and the page padding is token-driven.

Add provider connect-form chrome redesigned to match the typed three-step flow. The legacy Add Provider SliverAppBar title is replaced in create mode by a chrome that stacks a breadcrumb row (Settings, AI Settings, Add provider, provider name; shown on viewports at least 720 px wide), a step indicator (Choose provider, Connect, Review with Connect highlighted), and a provider-tinted hero card carrying the localised Connect provider headline and tagline. Below the form the legacy FormBottomBar is swapped for a three-button footer: Back to providers (back-arrow tertiary), Save as draft (secondary), Save and continue (primary, keeps the existing FTUE setup workflow). Edit mode keeps the legacy chrome unchanged.

Mobile responsiveness for the new chrome. The connect form's breadcrumb row and the tappable Choose provider step both drop on phone-sized viewports. The header card and step indicator stay; the footer's three buttons reflow onto multiple rows via Wrap instead of overflowing.

API-key "Get a key at <console>" hint on the connect form is now a real link target — taps wire through url_launcher to open the provider's console in the system browser, with https:// prepended for the bare-host URLs stored in aiProviderKeyConsoleUrl. The hint is also marked as Semantics(link: true) and underlined so screen readers announce it as a link.

Connect-form breadcrumb root crumb now reads Settings (using the canonical settingsV2DetailRootCrumb key, same as the Settings V2 top-crumbs widget) instead of the unrelated Theming label that previously surfaced. Romanian CTAs were retoned to the formal Salvați register to stay consistent with the rest of the Romanian AI Settings flow, and the base-URL hint replaces the stilted punctul final oficial with punctul final implicit.

Sync stack hot-path cleanup driven by the 2026-05-10/11/12 desktop slow- and super-slow-query logs. BackfillRequestService now short-circuits its 2-minute periodic body when the sequence log has no actionable rows (eliminates ~347 no-op ticks/day each running 5 sync_db queries). getPendingBackfillEntries inlines its status set as literal IN (0, 3) so the planner stops falling back to SCAN outbox (357 hits/day, avg 226 ms, max 1.8 s). The marker-clamp probe inlines its status set the same way, matching the active-room partial index (was up to 862 ms per commit/abandon). AgentRepository gains a bulk getEntitiesByIds; the project and task agent workflows replace per-id Future.wait fan-outs with one IN-list query plus the existing getLinksToMultiple + getLatestReportsByAgentIds pair (was 2 484 + 2 203 slow hits/day). QueuePipelineCoordinator debounces AttachmentIndex.pathRecorded into a 100 ms accumulator and flushes through a new bulk InboundEventQueue.resurrectByPaths, folding bursts of N writer-lock transactions into one SELECT + UPDATE (was 222 super-slow hits/day). sync_db v21 adds two literal-status partial indices for outbox claim ordering (pending: created_at + id; expired-sending: updated_at + created_at + id), removing the temp B-tree from the hot send loop. Agent database v8 adds idx_wake_run_log_created_at, turning the getWakeRunsInWindow scan + temp B-tree into an in-order index walk. MatrixSyncMetricsPanel's on-screen poll widens from 2 s to 5 s, cutting the GROUP BY status, producer pressure (was 223 hits/day).

AI Settings page redesigned. The page header now carries the title, a subtitle paragraph, an inline search field, and a green Add provider button; the floating action button is gone. The tab row bakes counters into each label (Providers N / Models N / Profiles N) instead of a separate counter strip. Providers and profiles render as a 2-column responsive grid of cards with a colored icon top-left and a hairline-divided status row at the bottom — provider status is one of Connected with a model count, generic Invalid key with an inline Fix link, or Offline with the Ollama hint. Models render as a single-column list with capability chips and no on/off toggle. The zero-providers state replaces the v1 empty-state placeholder with an FTUE banner (Start setup CTA) plus a single wrapper card containing four compact provider chips (Gemini, OpenAI, Anthropic, Ollama) that each open the connect form preselected to that provider.

Tasks Filter sticky footer no longer renders the Clear all and Save pills as floating text labels on dark mode. The button's inner box was 44 tall while its slot enforced a 56 minimum, so under the glass-blur footer the painted pill drifted out of alignment with the centered text and at low alpha against the dark sheet the silhouette washed out entirely. Both heights now share a single design-system action-button minimum, and the non-highlighted variant carries a 1 px border so the pill stays visible against the gradient overlay; Apply keeps its solid accent.

AI Settings FTUE modals redesigned. After connecting a provider, the setup preview lists each model the wizard will create as a checkbox row the user can untick to skip; models the provider already owns show in a read-only Already added section so re-running the wizard does not pretend they are new. Ollama and providers whose preset is already configured skip straight to the result modal. The result modal shows a compact summary — provider is connected, models added, profile created, test category created or reused — with Review setup and Start using AI buttons. Both modals use the existing app dark and light tokens instead of the design's near-black, and pick up the per-provider accent from the AI provider color tokens.

AI Settings setup wizard now covers Anthropic and Ollama alongside the existing Gemini / OpenAI / Mistral / Alibaba flows. Anthropic setup seeds Claude Sonnet 4 (reasoning) and Claude Haiku 3.5 (fast) plus a new Anthropic Claude default inference profile bound to a fresh Anthropic test category. Ollama setup installs the test category bound to the existing Local Ollama profile and intentionally creates no model rows — Ollama serves whatever the user has pulled locally, so the upcoming connect modal will enumerate the local server and let the user pick from what is actually installed.

Design-system color tokens for AI providers added under colors.aiProvider with light and dark variants for Gemini, OpenAI, Anthropic, and Ollama. Used by the upcoming redesigned AI Settings surfaces so per-provider accents stay consistent across mobile, desktop, and modal layers.

AI Settings provider detail page. Tapping a provider row on the AI Settings page now opens a dedicated detail page instead of dropping the user straight into the edit form. The page shows a provider-tinted header strip with the display name, tagline, and derived status pill; a Connection card with the masked API key (last 4 visible), base URL, and display name plus an Edit action; a Models section that lists the provider's own models with an Add model button; an Active profile section that surfaces the inference profile most strongly tied to this provider's models, hidden when no profile references them; and a Danger zone that routes through the existing AI config delete service so cascade-delete + confirmation + undo snackbar match the rest of the AI settings. The bottom of the page pads by the bottom navigation bar's occupied height so the danger-zone card never slips behind the nav on mobile.

Provider card Fix affordance now auto-focuses the API key field. When a provider's status is invalid-key, the Fix link routes through the detail page with focus-api-key set, which immediately pushes the edit form with a focus node wired to the API key field — the user lands directly on the field that needs editing in one tap. A regular card tap still opens the detail page without auto-pushing so users who want to inspect models or profile before editing don't get bounced.

Card overflow menus do the right thing. The three-dot icon on Provider, Model, and Profile cards used to render a disabled IconButton on top of a tappable card — tapping the icon just forwarded the tap to the card itself. Each card now accepts a menu actions list and the AI Settings page passes Edit and Delete rows; Delete runs the existing AI config delete service so cascade-delete + confirmation + undo snackbar are consistent with the rest of the settings. Cards without a populated menu list (e.g. the cards embedded in the provider detail page) hide the icon entirely instead of showing a non-interactive affordance.

Inference model edit page redesigned to match the v1–v3 visual language. The old SliverAppBar with a colorScheme.surface background is replaced by a clean AppBar with a text Save action (the bottom form bar is gone — Cmd+S still saves), a provider-tinted header strip that reads the model name and owning provider inline, and two design-system sections (Identity, Capabilities) rendered as level-02 cards on a level-01 page background. Provider, input modalities, and output modalities use a shared selector field that styles a read-only text input as a tap-to-open dropdown and tints the trailing caret amber when the field is empty so unset required selections are visible at a glance. All form copy is now localised across all six supported locales — previously the page shipped hard-coded English on every label.

Card text on the Models and Profiles tabs no longer truncates on mobile. The model card stacks the display name, the monospaced provider-model id, and the capability chips vertically — previously the name and id sat inline on one row and both ellipsised at narrow widths. The profile card lets the profile name, description, and each task-to-model slot wrap to multiple lines instead of clipping; slot rows are top-aligned so the icon + slot label stay flush with the first line of a wrapped model name. The inference profile form's body padding now includes the bottom navigation bar's occupied height so the last form section clears the nav on mobile.

AI Settings desktop master/detail dispatch. The AI panel in the Settings V2 registry was promoted from a plain page body to a multi-kind dispatcher so the right pane on desktop now swaps to the provider, model, or profile detail page in place when a row is tapped (or when the user beams to /settings/ai/provider/<id>, /settings/ai/model/<id>, or /settings/ai/profile/<id>) — previously the detail page was pushed as a fullscreen route over the master/detail shell, hiding the sidebar. The three typed URL patterns handle both surfaces: on desktop the panel slot reacts to the selected-settings-route value notifier, on mobile the location builder pushes the detail page on top of the AI Settings page so the back gesture still returns to the list. The AI Settings navigation service now beams to the matching typed route instead of calling Navigator.push directly, and the Fix-flow rides the provider URL with a focusApiKey=true query parameter — the AI panel dispatcher reads that query off the live route and rebuilds the detail page with focusApiKey set so the edit form auto-pushes with the API key field focused regardless of which surface the user came in on.

AI Settings desktop sidebar shows Providers, Models and Profiles as their own leaves under "AI Settings". Previously the three views lived only as tabs inside the AI Settings page body and the sidebar carried a single legacy "Inference Profiles" leaf that pointed at the V1 profile list — the v3 redesign moved profile rendering into the tab body but the legacy leaf was never updated. The settings tree now mirrors the three tabs as three leaves, each panel renders the AI Settings body pinned to its tab with the in-pane TabBar hidden, and the ai-profiles panel is repointed from the V1 profile list to the v3 Profiles tab body so a desktop user sees one consistent profile list whether they reach it via the sidebar or the AI Settings page directly. Clicking the AI Settings parent row itself also renders without the TabBar — the page-level default tab is already Providers, so the parent landing lands visually identical to the Providers leaf instead of briefly flashing a duplicate tab strip before the user picks a leaf. On mobile the page still ships its TabBar — the sidebar does not exist there, so the tabs remain the only way to flip between the three views.

AI Settings "Add" affordance is a per-tab floating action button. The inline "Add provider" pill in the page header is gone — it was hard-coded to provider creation even when the user was looking at Models or Profiles, and it duplicated the FAB pattern the rest of the settings surface already uses. The page now drives a DesignSystemFloatingActionButton in the Scaffold's floatingActionButton slot, wrapped in the bottom-nav FAB padding so it clears the nav bar on mobile. Its semantic label, handler AND icon swap per active tab — bolt for Add provider, psychology-alt for Add model, tune for Add Profile — so the gesture always creates the right kind of config and the FAB glyph names what's about to be added.

The page header bar is now just the search field. The v3 redesign shipped a subtitle paragraph + a custom design-system text input here; both removed in v4. The subtitle was redundant with the page title + sidebar leaf, and the custom input used a different placeholder than every other search field in the app. The header now reuses the AiSettingsSearchBar wrapper around the app-wide LottiSearchBar so the styling and hint copy match the rest of the settings surface.

Models tab regains the pre-v3 filter strip in full. The v3 redesign hooked up the filter service to filter by provider, capability and reasoning but never shipped the UI for any of them. The strip now reuses the existing AiSettingsFilterChips widget so the Models tab gets the same chrome the rest of the app already uses: provider-tinted pills (colored leading dot + matching border + dark accent-tinted background pulled from the per-provider color tokens), capability chips (Text / Vision / Audio) plus a Reasoning toggle in a neutral Material FilterChip style, and an appearing Clear filters action when at least one filter is active. The chips sit in a Wrap so the row stacks across multiple lines on narrow viewports instead of horizontally scrolling.

Provider card status row right-aligns the model count tail flush against the card's right edge. The v3 layout split the remaining width between a Spacer and a Flexible Text, which parked "3 models · last used 2m ago" in the middle-right of the card instead of at the edge. An Expanded with end-aligned text now collapses the gap so the tail snaps to the right margin; the Ollama-hint variant on the offline status branch got the same treatment.

The Task action bar's inset stop circle now persists the running timer entry's dateTo to the moment of the tap before clearing the timer service. Previously the handler called TimeService.stop() directly, which only cleared in-memory state and left whatever dateTo was last written on disk — typically minutes behind the actual stop tap — so the recorded session was short by the elapsed-but-unsaved tail. The handler now routes through EntryController.save(stopRecording: true) for the running timer entry, mirroring the entry-editor stop button.

Slow-query log on a real desktop device flagged four hot paths that all stemmed from query/index mismatches. The InboundQueue stats poll ran four separate aggregates with full table scans and a temp B-tree because no index covered (status, producer); the v20 schema adds a (status, producer, enqueued_at) composite and the poll collapses to one GROUP BY query that streams index-only entries. The project task rollup query fell back to a generic browse index plus a temp B-tree because it omitted task = 1 even though every Task write sets it, so the planner could not match the v40 partial index dedicated to this aggregate; adding the redundant predicate streams the rollup directly. The checklist-items-for-task lookup materialised every ChecklistItem the device had ever seen and filtered in Dart, which dominated the agent hot path; it now does two indexed bulk-by-id lookups against the parent Checklists' linkedChecklistItems list. The sync sequence log cache used a single global five-minute timer that wiped every host's watermark whenever any host had been active recently, which produced repeated 200 to 500 ms slow getLastCounterForHost queries; the cache is now per-host so an inactive host stays cached until it is actually queried again.

The Projects tab "+" button now opens the project create page directly inside the Projects tab via /projects/create instead of beaming through /settings/projects/create. On desktop the old route landed on the Settings V2 root because no projects panel is registered there, so the create flow was unreachable. The same path swap is applied to the inline "New project" button on category pages so deep-links with a prefilled categoryId continue to work.

The Categories list "+" button on Definitions → Categories now opens the category create modal directly instead of beaming to /settings/categories/create, which on desktop bounced the user back to the Settings V2 root. The modal stays inside the current tab and the list refreshes via the shared category stream once the new entry is persisted.

The Save / Create row on the project create page is no longer hidden behind the bottom navigation pill on mobile. The page's bottom bar is now padded above the pill on phones and remains flush at the bottom on desktop where the sidebar replaces the pill.

Project create no longer publishes a Saved successfully toast on the projects tab. The freshly-created project shows up in the list immediately on pop, which is sufficient confirmation for a one-shot create flow and avoids the Material FAB lift a floating SnackBar would trigger on the projects list. Error toasts on the create page itself are unchanged and still dock above the form's bottom action bar.

The project create form now exposes a category picker between the title and target-date fields. The picker is seeded from the route's categoryId query parameter so the inline "New project" button on a category page still pre-selects the right category, while users opening the form from the Projects tab "+" can pick a category up front instead of having to backfill it after creation.

Sync conflict resolution screen rebuilt as an inline-diff picker. Tapping a conflict row opens a dedicated page with a back chip, title, and amber count pill in the header; an amber summary banner that names the entity type, how long ago the two sides diverged, and which fields differ; and two diff cards (local in teal on the left, remote in blue on the right) where each side's title is rendered as a word-level diff with tokens unique to local tinted green, tokens the remote dropped struck through in red, and tokens the remote introduced tinted blue. Each card carries the side's timestamp + per-side vector-clock counter plus a category icon, word count, and audio duration when available. A picker pill row mirrors the selection (Use this device / Use from sync, plus Edit and merge on desktop) and a sticky glass footer holds Cancel and Apply with helper copy that reads back the chosen consequence in plain English. Below 768 px the cards stack vertically, the picker drops to two pills, and the footer surfaces Edit and merge as a left-side text link.

Conflict detail page now opens correctly on desktop. The Settings V2 panel for sync conflicts was registered as a list-only body, so a row tap updated the URL but the right-hand pane kept rendering the list — only the mobile navigation stack was wiring the detail. The panel now dispatches by conflict id so the desktop pane swaps to the resolution view when the URL gains an id, matching the categories / labels / dashboards / measurables flows.

Linked-entries activity log on a task now sorts entries by each entry's dateFrom instead of the link's own createdAt, so the "Newest first" / "Oldest first" toggle reflects the timestamps shown in the row headers. Previously two entries linked in the same session could appear in an order that contradicted their visible times because their links shared a createdAt and the list was sorted by that field.

AI summary card header (the AI summary / agent name row) keeps its wake / refresh affordances and Read more pill inline alongside the title on every viewport instead of stacking them underneath on cards narrower than ~360 px. The title block uses an Expanded so it soft-wraps to a second line if the controls really need the room; on a phone-sized card with the wake-cycle countdown active the pill also switches to a tighter compact width so the inline cluster reads less crowded. Previously the header dropped the entire control cluster to a second row even when only the refresh icon + Read more pill were present and would have fit alongside the title comfortably.

Toast notifications triggered from the task details page (e.g. "Change applied" after confirming a proposed change) now float above the sticky action bar on every platform instead of being pinned to the screen / window bottom edge, so the confirmation reads as belonging to the task view it came from. The page wraps its Scaffold in a nested ScaffoldMessenger, scoping toast calls fired from inside the subtree to that messenger — Flutter then floats the SnackBar above the bottomNavigationBar slot automatically. Previously this was gated to macOS / Linux / Windows; on mobile the action bar would cover the toast docked at the screen bottom.

Sync Conflicts list page restyled to match the agents listing visual language. The legacy card chrome is gone; each row is now a hover-aware inline strip that pairs a tone-driven status badge (success for resolved, danger for unresolved) with an entity-type badge, the creation timestamp as the row title, and an 8-character mono prefix of the conflict id on the trailing edge with the full id revealed via tooltip. The full vector clock — previously wrapping two lines of monospace text inside every row — is no longer surfaced in the list and stays available on the conflict detail page where the merge view actually needs it. Below 600 px the row collapses to a two-line stacked layout so phone-width viewports stay legible. The shared monoMetaStyle helper that used to live inside the agents feature was lifted into the design system so any feature that needs an Inconsolata mono cell pulls from a single source.

Sidebar running-timer card now hides itself only when the timer's parent task is the same task currently open in the desktop task-details pane and the user is actually on a /tasks/<uuid> route. The detail page's sticky action bar already shows a running indicator, so duplicating the title in the sidebar would be noise — but the card still surfaces on every other tab (Habits, Settings, …) because the selected-task notifier is sticky across tab switches and the action bar isn't visible there. The show/hide flip runs through a combined AnimatedSwitcher + AnimatedSize (~220 ms, easeInOut) so the card fades and the surrounding sidebar collapses smoothly instead of popping. The stream is seeded with the current running entity so a session already running is rendered on first frame instead of flashing through a hidden state.

Sticky action bar's running "Track time" pill gets a touch more breathing room on the leading edge: the inset stop circle now sits 8 px from the pill border (was 4 px) so it no longer crowds the edge while the elapsed digits tick.

Audio recording player restyled to match the green Figma audio card. The play/pause control is now a soft circular pill drawn on the design-system surface token with the high-emphasis text color for the glyph; the previous gradient + drop shadow + animated progress ring are gone. The waveform's played bars use the brand teal interactive token (#2BA184 in light mode, #5ED4B7 in dark mode), with a thin teal scrubber line drawn at the playhead and bars widened to 4 px with 3 px spacing for parity with the Figma reference. The fallback progress bar (used while the waveform is still resolving) follows the same tokens, with the unplayed track now reading from the decorative level02 token instead of an alpha overlay on onSurfaceVariant. The play/pause button drops a step in size (40 px compact / 48 px standard) so it no longer dominates the card.

Task details page now has a sticky action bar pinned to the bottom in place of the floating action button. A primary "Track time" pill starts a new timer when idle. While a timer is running on the open task the pill morphs into a live elapsed-time readout with an inset stop circle on the leading edge — tapping the pill body navigates to the running timer entry (matching the desktop sidebar's timer card), and only the inset stop circle stops the timer. The duration uses the same tabular-figures / slashed-zero / cv02–04 font features as the sidebar timer; under one hour it's compacted to mm:ss and only expands to hh:mm:ss once a session crosses the hour mark. Four round affordances cover the remaining frequent inline actions: record audio (immediately after the pill — turns red with a white glyph while a recording for the open task is active), add checklist, import image, and more actions (opens the previous menu for long-tail items, including capture-screenshot on desktop platforms that support it). Capture-screenshot is no longer a top-level affordance. On narrow viewports the row stays on a single line by dropping affordances in priority order: image first, then checklist; both remain reachable via the more menu. On mobile the bar takes over the bottom edge entirely: the app shell's bottom navigation pill is hidden whenever the active beamer route is /tasks/<uuid>, letting the action bar dock flush against the home indicator.

Agent UI/UX refinements: the AI summary card's outer glow is trimmed to a soft tinted edge, its underlined subtitle now reads the agent template name (e.g. "Task Laura") instead of the generic kind label, the Confirm-all button pins to the right edge of the proposals header, and the cards inside the agent internals panel (Reports / Conversations / Observations / Activity) sit on the AI panel's row token so the dark backdrop reads as a unified surface. Settings → "Pending Wakes" is renamed to "Wake Cycles", its countdown is now zero-padded MM:SS (or HH:MM:SS once over an hour) with tabular figures so digits no longer breathe, refresh keeps previously-loaded rows on screen instead of blanking to a spinner, and a "Running now" block at the top of the page surfaces currently-executing wake instances with a live elapsed pill. The desktop sidebar Wake Queue gains an Ongoing block (live duration since wake start), only shows scheduled wakes due within the next hour (anything farther out is hidden from the sidebar entirely), drops the per-row letter avatar, uses smaller mono font with ellipsis, prefers the linked task or project title as the row label, and the WAKES header is now an open-in-new link straight to the full Wake Cycles page.

Desktop running-timer is now an inline sidebar section that sits above Settings, replacing the bottom-anchored floating indicator. The new panel shows the running task title (up to two lines, in the design-system caption style), a ticking HH:MM:SS counter using Inter with tabular figures, slashed zero, and the open-digit variants for 4, 6, and 9, plus a stop button. Tapping anywhere on the body navigates to the running task; tapping the stop button stops the timer. The mobile bottom-nav overlay is unchanged. Sidebar nav-item vertical spacing was tightened from 24 px to 16 px (a 33 % reduction) to keep the rail feeling balanced with the new section in place.

Task detail "Linked from" no longer surfaces parent projects. Tasks link to their project as organising context, but listing the project alongside other linked entries adds noise; project entries are now filtered out unconditionally.

Settings → Agents → Souls re-skinned onto the same shared listing shell that Instances and Templates already use. The previous ModernBaseCard column is replaced by the shared toolbar primitives: search and Sort by Name / Recent / Oldest. Each row shows the soul name with a hue-tinted initial-tile avatar on the leading and the active version as a compact `vN` mono cell on the right. The deep-link to the soul detail and the create-soul FAB are unchanged.

Settings → Agents → Pending Wakes re-skinned onto the same shared listing shell. The legacy stacked card column is replaced by a denser row layout with the same toolbar primitives: search, an optional Type filter (only when both pending and scheduled records exist), Group by All / Type, and Sort by Due soonest (default) / Due latest / Name. Each row shows the linked task or project title (or the agent name when no subject is attached), agent kind and wake type pills, and a live countdown chip that ticks once a second; the absolute due timestamp surfaces as the chip's tooltip. Internally the per-row Timer is replaced by a single page-scoped ticker so the page can scale to many wakes without spawning one timer per row; the 24h wake-activity chart that used to sit on top of this tab now lives only on the Stats tab.

Fixed the task filter modal's Save button: it now applies the current modal draft, saves it to the sidebar, and closes the modal as a single action. Previously, edits made inside the modal before tapping Save were silently dropped from the persisted filter, and the modal stayed open afterwards.

Task filter modal action bar now uses the new "Apply filter" glass footer: a full-width frosted-glass strip flush to the bottom of the modal, with a hairline divider on top and right-aligned Clear all, Save, and Apply filter buttons. The last filter section gains comfortable breathing room above the footer; long localized labels still fit because the buttons can grow past their default width.

Settings → Agents → Instances has been redesigned. The previous filter strips and card list are replaced by a denser, faster-to-scan layout: the toolbar now exposes Filters (multi-select for Type, Status, and Soul), Group by (Soul / Type / Status), Sort (Recent / Oldest / Name), and a live search field, with a result counter on the right. Active filters render as removable chips below the toolbar with a Clear all affordance. Rows show the instance name, template, ID, type and status pills, and the time of the last activity, grouped under a collapsible header that surfaces the active count and total per group. The page now uses background level-02 to match the rest of the settings surface, the AppBar reads "Agent Instances" only on this tab, and the layout adapts on narrow widths so the toolbar wraps and rows stack title / template / pills onto separate lines. The search field paints its focus state on the outer border.

Internal: extracted the Instances scaffolding into a shared `lib/features/agents/ui/listing/` layer so the Templates, Souls, and Pending Wakes tabs can be re-skinned through the same primitives in the next pass. The Instances page is now a thin adapter over the shared shell; no user-visible change for this tab.

Sidebar gains an opt-in inline Wake Queue. When the new "Show sidebar wake queue" config flag is enabled, pending agent wakes surface directly on the desktop sidebar above Settings: a small WAKES header with the queue count, the next two upcoming wakes shown as compact agent + ETA rows, a per-row × button to cancel the wake, and a link into the full Pending Wakes view. ETAs render as "now" when due, mm:ss within an hour, and "Xh MMm" beyond, switching to a warning colour inside the last five minutes. The block self-collapses to just the header when the queue is empty so the rail never feels stuck. The sync activity LED indicator has been re-laid-out as a single fixed-width row pinned to the very bottom of the sidebar, with each numeric column reserving room for multi-digit counts (right-aligned inside the slot) so the LEDs and labels never reflow as the outbox or inbox depths change.

Settings → Agents → Templates re-skinned onto the shared listing shell — same toolbar, search, optional Kind filter (only when more than one kind is present), Group by Kind / All, and Sort by Name / Recent / Oldest as the Instances tab. Each row shows the template name, model id, kind pill, and the active version as a compact `v{N}` mono cell on the right. Templates with a pending review keep their visual cue, now as a purple-tinted leading icon instead of a positioned dot.

Task details page: a new unified AI summary card replaces the previous AI summary panel and decision activity strip. One deep-teal-tinted-navy surface now hosts the agent's TLDR, an inline expandable Goal / Achieved / What's left / Learnings report under a Read more / Show less pill, the actionable proposals list with swipe and button confirm-or-reject (and a Confirm-all batch), a collapsible History toggle for resolved proposals, and a recent-activity footer capped at six rows. The wake-cycle controls — running spinner, run-now refresh, countdown pill, and cancel-timer — sit directly in the card header.

Tapping the agent name, the footer avatar, or the "Open agent internals" pill opens a new agent internals panel. On wide screens it slides in from the right at a comfortable 600 to 800 pixel width over a darkened scrim. On narrow screens (phones in portrait, slim split-view windows) the same panel renders as a full-screen modal that slides up from the bottom, so the header stays on screen and the body is comfortable to read on small devices. Either way it hosts the same five tabs as the standalone agent detail page: Stats, Reports, Conversations, Observations, and Activity. The agent detail page now shares the exact same body widget as the panel.

Design-system tokens were added for the AI surface itself and for the proposed-changes kind chips (Add, Update, Remove, Priority, Estimate, Status, Label, Due), each in foreground and surface-tint variants. The activity row's relative time labels (now / minutes / hours / days / weeks ago) are now properly localized in all supported languages. A follow-up doc captures the typography density gap surfaced while building this card so the remaining hand-tuned line-height overrides can be replaced with a Compact density tier in the next pass.

Fixed a layout regression where checklist items on devices with a top safe-area inset (notched iPhones) were pushed far below the Open / Done / All filter strip. The body's list now opts out of the default safe-area padding behavior, so the first item sits flush under the filter divider on every form factor.

Linux geolocation rewritten as a dual-mode D-Bus client. Inside the Flathub sandbox Lotti calls org.freedesktop.portal.Location, so it now appears under GNOME Settings → Location → Permitted Apps. Outside the sandbox (flutter run, developer builds) it talks to org.freedesktop.GeoClue2 directly, because the portal rejects unsandboxed callers with Access denied. Note: GeoClue itself still depends on a working WiFi-based backend; on Ubuntu 24.04 the default Mozilla Location Service URL returns 404 (MLS was deprecated in 2024) and Lotti will silently fall back to IP geolocation until you point GeoClue at a working backend such as BeaconDB.

Settings root list is shorter and easier on new users. Habits, Categories, Labels, Dashboards, and Measurables are now grouped under a single "Definitions" entry that opens a dedicated sub-page on mobile and expands as a Definitions branch in the desktop settings tree. Config Flags moved into the Advanced sub-page next to Logging, Maintenance, and About. Public deep-link URLs are unchanged, so existing bookmarks keep working.

Task details page: linked entries section now uses an activity-filter pill row (Timer / Audio / Images) above the entries to toggle which activity types are shown. Checklists keep their dedicated section at the top of the page, so they are not part of the activity filter.

A "Newest first / Oldest first" trigger on the right of the activity bar opens a sort and filter modal that reuses the same exclusive-choice pill chrome and palette as the task list filter modal. The modal also exposes a "Show hidden entries" switch.

Linked entry cards now use the same design-system card and padding values as the task list card, replacing the prior modern-card treatment. The audio player no longer wraps itself in a second card and sits flush inside the entry's section card. Card top padding is tighter so the trailing IconButtons in the entry header provide the visual breathing room without doubling it.

Checklist card header padding tightened, the collapsed pill no longer wastes space at the bottom, and the chevron is now a proper icon button with Collapse / Expand tooltips so it gains a hover state matching the menu button next to it. The "Checklists" subheading on the task details page was removed; the per-task sort menu still appears when there are two or more checklists.

Extracted the exclusive-choice filter pill from the private task filter sheet into a shared design-system widget so the task filter modal and the new linked-entries filter modal render the same chip — fill cross-fade, accent border alpha tween, constant border width, 400 ms animation.

Linked tasks section on the task detail page is redesigned to match the Figma spec: a single expandable card with a count badge in the header, per-row "to"/"from" direction glyphs (info-blue / success-green), status circles, and dividers between rows. The overflow menu retains the existing link/create/manage actions.

The AI assistant menu now appears on text journal entries. Skills that consume entry text (coding-prompt generation, image-prompt generation, cover-art generation) work the same way whether the source is a typed note or a voice recording's transcript.

New built-in Generate Design Prompt skill turns task context plus the entry's notes into a UI/UX design exploration prompt that defaults to five functional prototypes (override-able from the entry text), enforces design-system alignment when one is mentioned, and surfaces clarifying questions up front. Output is two-section Markdown ready to paste into Claude, Figma Make, or v0.dev.

New built-in Generate Research Prompt skill produces a structured Markdown research brief (Background, Research Questions, Scope, Deliverables, Source Preferences, expected output format, open questions) ready to paste into Claude with Research or ChatGPT Pro with Deep Research.

Built-in skills are now defined in code under lib/features/ai/skills/built_in_skills.dart and read via skillRegistryProvider instead of being seeded into the AI config DB. This removes the seeding round-trip and lets skill content stay in lockstep with the code that uses it.

Outbox post-drain settle window raised from 250 ms to 1500 ms and lifted into SyncTuning.outboxPostDrainSettle. Bursty edits (rapid typing, imports, multi-entity flows) now coalesce into the next bundle instead of shipping one bundle per write, so the outbox sends fewer, fuller trains while keeping the first-departure latency unchanged.

Faster task-list, projects, and inbound sync queries via new SQLite indices and tighter sync transactions. New partial index idx_journal_tasks_status_priority_date streams the open-tasks list ordered by (task_priority_rank, date_from DESC) without falling back to a temporary B-tree, even when many categories are selected. New covering idx_linked_entries_from_id_hidden_to_id resolves the bulk linked-time-spans query index-only on the linked side. New idx_inbound_event_queue_status_enqueued lets the queue-stats COUNT(*) + MIN(enqueued_at) poll seek by status and pick MIN from the index instead of scanning the full queue ledger. claimNextOutboxBatch no longer scans the outbox: the original status = pending OR (status = sending AND updated_at < cutoff) predicate is now two indexed seeks merged in Dart, each picked up by the existing actionable partial index.

Sync apply for journal entities holds the journal writer lock only around the actual writes. Cross-database awaits (sync-sequence log recording, pre-write journalEntityById reads) now run outside the journal transaction so concurrent readers no longer queue for hundreds of milliseconds per applied event.

Removed the per-open self-heal block that re-issued CREATE INDEX IF NOT EXISTS on every database connection. With drift's read-pool the block ran nine times per launch (writer plus eight read isolates) recovering from an incident that has not occurred in production. beforeOpen is now just PRAGMA foreign_keys = ON; if a migration is ever interrupted on a future device the next schema bump will repair it.

Inbox backfill no longer hangs for ten minutes per agent-bundle row. Removed the agent wake-cycle bundling layer that coalesced per-wake agent writes into a SyncAgentBundle. With generic dequeue-time outbox bundling in place the wake-bundle envelope was redundant — and after the outbox bundler started claiming text-only rows in batches it became actively harmful: bundled SyncAgentBundle rows shipped a manifest whose envelope-only entries no longer pointed at any uploaded attachment, leaving inbound rows stuck in the 10-minute pending-attachment wait until they were skipped. Agent writes now hit the outbox directly as SyncAgentEntity / SyncAgentLink rows and flow through the same bundling path as journal entities. The SyncAgentBundle wire variant remains parseable so messages from peers that predate this change still decode; the receiver no-ops them and any children missing locally resurface via the existing per-(host, counter) backfill path.

Reduced idle CPU usage after starting and stopping task timers. Inactive desktop and mobile navigation tabs now disable tickers for their cached IndexedStack children, and task/project agent countdowns update only their small countdown pill instead of rebuilding whole report sections in hidden tabs. Running-timer task icons also rebuild only when the linked task changes.

Inbound sync rows waiting for missing attachment or agent-bundle JSON now use a bounded 10-minute wait with long backoff instead of either retrying forever or being skipped by the generic attempt counter too early. If the attachment is still missing after the grace window, the row is abandoned and normal backfill recovery can handle the long tail.

New sidebar Sync activity indicator (variant D4a). When the show_sync_activity_indicator config flag is enabled, the desktop sidebar gains an ambient two-row monospace strip just above Settings: tx <outbox-depth> / rx <inbox-depth>, each with a 5×5 LED that flashes for ~140 ms per packet committed on that channel. Tap navigates to Settings → Sync; while the flag is on the legacy red Settings badge is suppressed so the count is shown in exactly one place. Default off; opt in via Settings → Config Flags.

Task agents can now propose user-reviewed edits to historical time entries linked from the current task. The wake prompt exposes editable non-running entry IDs with their current time range and text, the new update_time_entry tool validates task ownership and excludes the live timer, and the suggestion row renders a current-to-proposed diff before confirmation.

create_time_entry completed sessions now allow any valid endTime > startTime range, including future and midnight-spanning blocks. Running timers keep the existing today-only and not-in-the-future restrictions.

DailyOS due-task hot path (getTasksDueOn / getTasksDueOnOrBefore) now reads a denormalized due_at INTEGER column on journal instead of json_extract(serialized,'$.data.due'). The partial idx_journal_tasks_due_open is rebuilt on the column so the planner streams ORDER BY due_at ASC straight from the index without per-row JSON parsing, eliminating the planner-fragility that required the previous INDEXED BY pin plus JSON-fallback safety net. The due_at shadow is populated by toDbEntity on every upsert and back-filled for every existing task with a non-null data.due — including completed and rejected tasks — by the v41 migration. The serialized JSON payload is unchanged; the column is purely a query-acceleration shadow.

DailyOS calendar prefetch (sortedCalendarEntries) now coalesces concurrent per-day callers into a single union-range DB round-trip with client-side filtering, modeled on the existing _coalesceOpenTasksDueUpTo pattern. Slow-query telemetry showed 22+ identical date-range queries firing in the same second during multi-day prefetch; the wave collapses them into one read.

retireExhaustedRequestedEntries and retireAgedOutRequestedEntries now flip rows in pageSize-bounded batches, each in its own transaction, so a large backlog never holds the sync-DB writer lock through a single multi-second UPDATE. Previously a stuck-row backlog could pin the lock for ~1.9 s, starving concurrent reads.

Improved sync reliability between devices.

Task detail header redesigned (Option B): a tiny breadcrumb (Category / Project) above the title carries the "where am I?" info, and a single horizontal pill row below the title carries the actionable metadata — priority (tinted), due date (outline, urgency-coloured, muted when unset), estimate (filled with progress bar; tinted when overtime; muted when unset), and labels (filled with color dot, long-press shows description). The status select is rewritten with a per-status 18% alpha tint and pinned to the right edge of whichever wrapped row it lands on via a custom render-box layout, falling onto its own right-aligned line only when it doesn't fit on the last leading row. All chips use the caption type ramp. Adds DsPill / DsGhostChip / DsDividerDot design-system primitives shared across the header and the tasks list. Active filter chips on the tasks list are aligned to the same caption type ramp, and their remove icon is bumped to 20 px. The task list now hides the trailing status pill on every card when the filter has narrowed to a single status (it stays when zero or 2+ statuses are selected, where it disambiguates rows). The "Add Checklist" affordance moves off the inline section header and onto the FAB's create-entry menu as the first item; the checklists section now collapses entirely when the task has none, and gains breathing room above when populated.

Outbox message bundling, gated by the new use_outbox_bundling config flag (default off). When enabled, OutboxProcessor claims a contiguous run of consecutive text-only outbox rows up to SyncTuning.outboxBundleMaxSize (50, tuneable up to 100) in (priority, createdAt) order and ships them as a single SyncMessage.outboxBundle envelope delivered as a sidecar JSON attachment under /outbox_bundles/<uuid>.json. Media-attachment rows always travel alone — the batch claim stops one row before the next attachment. Receivers download the sidecar via the existing attachment-ingestor pipeline and unpack it through OutboxBundleUnpacker, dispatching each child through the per-type apply path used for individually-delivered messages. Bundle children carry their own originatingHostId so receiver-side sequence tracking does not regress. Per-child fault isolation rethrows any IOException for the whole-bundle retry path, while non-IO errors on a single child are logged and skipped. Path-traversal hardening rejects sidecar paths outside /outbox_bundles/ before disk writes. Bursty workloads (agent suggestions, checklist creation, sync backfill replay) drop to roughly 1 Matrix event per ~50 rows. See ADR 0015 for the design and rollout details.

Categories settings list now matches the Labels / Dashboards baseline. A DesignSystemSearch field above the list filters rows by name (case-insensitive substring); a "+" floating action button at the bottom-right opens the existing /settings/categories/create route. The legacy in-header "Add Category" text button is gone — the FAB is the canonical create affordance now and uses the design-system circular FAB component already consumed by the Tasks tab. The no-match empty state echoes the active query verbatim (No categories match "foo") so users know what they typed.

Settings sidebar order: Sync now sits directly below Agents in the Settings V2 tree. Agents and Sync are both runtime / system concerns and read better as a pair than separated by the taxonomy leaves (habits / categories / labels).

Settings V2 desktop now exposes the provisioned-sync (QR pairing) entry point. The Sync branch was previously leafless on V2 desktop, so the ProvisionedSyncSettingsCard that the mobile SyncSettingsPage already renders had no equivalent surface — provisioned setup was effectively unreachable on desktop. The Sync branch now declares a landing panel that hosts the same card inside SyncFeatureGate + DesignSystemGroupedList so the visual treatment matches the rest of the V2 detail pane.

Settings list-page FABs now use the design-system circular FAB component (DesignSystemFloatingActionButton) — the same visual primitive the Tasks tab already consumes — instead of raw Material FloatingActionButton. Migrated sites: Labels, the shared DefinitionsListPage host (Dashboards / Habits / Measurables, via the public FloatingAddIcon helper), AgentSettingsPage (Templates + Souls tab FABs), InferenceProfilePage, and the AI settings per-tab FAB. The previously-extended AI FAB drops its inline per-tab text label in favour of the circular shape; the per-tab label survives as the semanticLabel so screen readers and hover tooltips still announce "Add Provider" / "Add Model" / "Add Profile" correctly. Categories already adopted the DS FAB in the parity commit above.

DesignSystemToast grows two new affordances and becomes the shared toast surface for the migrated call sites. ToastAction(label, onPressed) renders an inline call-to-action that inherits the tone's border color, and a tone-coloured countdown progress strip along the top edge drains over countdownDuration / initialCountdownProgress. BuildContext.showToast learns matching action, countdown, replaceCurrent, and clearQueue parameters; a parallel ScaffoldMessengerState.showDesignSystemToast extension lets async callbacks that may outlive the calling widget (e.g. swipe-to-dismiss onDismissed, where the row is removed from the tree before the toast fires) capture the messenger up-front and still surface their toast. replaceCurrent: true only hides the in-flight SnackBar; clearQueue: true drops every queued item so terminal-status toasts (e.g. "all confirmed") supersede in-flight per-item toasts.

Migrated ScaffoldMessenger.showSnackBar call sites that were semantically tone-coded notifications now go through DesignSystemToast: checklist swipe-to-delete and swipe-to-archive (warning tone, countdown, Undo action — replaces the old showCountdownSnackBar helper), checklist correction-capture pending toast (success tone, countdown matches the save delay, Cancel action), Agent Suggestion confirm / reject / confirm-all (success / warning / error tones based on result, with strings + messenger captured before the await so the toast still fires after the row is unmounted by the suggestion list rebuild — confirm-all and per-row result toasts use clearQueue: true so terminal status replaces any in-flight per-item toasts), and Sync's Backfill Catch-up-now / Retry-skipped / Retry-all-skipped actions (success on completion, error on throw). The legacy CountdownSnackBarContent widget and showCountdownSnackBar helper are gone with their last caller. Out of scope: the AiConfigDeleteService cascade-deletion SnackBar (custom rich body) and the saved-task-filter pill toast (custom rounded chrome) keep their bespoke chrome for now.

Config Flags page now has a keyword-search field above the list. The DesignSystemSearch input filters flags by their localized title or description (case-insensitive, whitespace-trimmed); a centered empty-state message replaces the list when no flag matches. The filter logic is a pure filterDisplayedFlags function, unit-tested in isolation. Design-system spacing tokens add breathing room around the field and between the field and the list. The new enable_whats_new flag joins the user-toggleable list (with localized title, description, and icon) so the What's New tree leaf can be hidden from the UI without editing the database.

Config Flags page polish: the search field is now pinned at the top of the page while only the list of rows scrolls beneath it (FlagsBody becomes Column[fixed search, Expanded(scrollable list)] inside a SliverFillRemaining host). DesignSystemListItem grows a subtitleMaxLines parameter (default 1, preserves existing behavior); flag rows pass null so long descriptions like "Generate AI summary for task actions" wrap onto a second line instead of truncating with ellipsis. Hovering a row hides the divider above and below it so the hovered row is never bisected by a hairline, mirroring the task-list polish. Page gutter and vertical spacing tokens give the search and the rounded card container consistent breathing room.

Backfill Sync settings page rebuilt around the Option C "compact ledger" design: a welded status row (Inbound queue · Missing · Skipped) at the top, a leader-dotted Sync statistics ledger, an Automatic backfill toggle, and a single collapsed Advanced recovery group containing every manual recovery action (Catch up now, Retry skipped events when present, Manual backfill, Reset unresolvable, Re-request pending, Ask peers for unresolvable, Retire stuck entries). All visuals are driven by design-system tokens — DesignSystemButton, DesignSystemToggle, tokens.colors.*, tokens.spacing.*, tokens.radii.* — so the page reads as part of the rest of Settings V2 instead of a one-off.

Settings V2 (tree-nav + detail pane) is now the canonical desktop chrome. The enable_settings_tree config flag, the legacy desktop column-stack layout, and the "Disable Settings V2" escape-hatch button are gone; SettingsRootPage now dispatches mobile to the single-page SettingsPage and desktop to SettingsV2Page with no flag observation. Mobile is unchanged.

Settings V2 Agents tab is now URL-driven and the sidebar tree mirrors what used to live in the in-page tab strip. Each tab gets a dedicated tree leaf under Agents in the same order as the legacy TabBar (Stats, Templates, Instances, Souls, Pending Wakes) and the templates / instances / souls panels are wrapped in DetailIdDispatch so the "+" FAB and row taps swap the right-hand panel between list / detail / create. The in-page tab strip is hidden on desktop — exposing both navigation surfaces caused the URL → tree → URL feedback guard to leak across rapid tab clicks (silently swallowing subsequent sidebar / FAB / row beams) and let the sidebar selection drift out of sync because a top-tab click never expanded the parent branch. The body still resolves its content from the URL, so dropping the bar is purely additive; mobile keeps the legacy setState-driven push-stack model. DetailIdDispatch forces StackFit.expand on its AnimatedSwitcher so Scaffold-based panel bodies receive bounded constraints and lay out their FloatingActionButton the same way they would unwrapped.

Category selection modal now closes itself when a row is tapped on mobile and narrow desktop. The bottom-nav redesign opens these modals on the root Navigator (above the bottom nav), but the picker callbacks were popping the per-tab nested Navigator the page lives in rather than the root Navigator that hosts the modal — so selecting a category left the picker stuck open. The four affected callers (DesktopTaskHeaderConnector category picker, CategorySelectionIconButton, CategoryField, AddBlockSheet) now name their builder argument modalContext and pop with Navigator.of(modalContext).pop() — the same pattern already applied to the estimate / due-date / priority pickers.

Settings V2 detail surface consolidated to a single page-title surface. The full breadcrumb path (e.g. Settings › Sync › Backfill Sync) now lives in the page header at Heading 3 typography — non-leaf segments are tappable and call SettingsTreePath.truncateTo(depth), mirroring the click rules of the old in-pane crumbs. LeafPanel now returns the cached IndexedStack directly: the in-pane crumb trail, the Heading-3 leaf title, and the outer step6 / step5 Padding gutter are all gone, so registered panels fill the detail pane edge-to-edge.

Sync conflict resolution moved out of the Advanced branch and into the Sync branch in the Settings V2 tree. The leaf id is now sync/conflicts and the panel registry key is sync-conflicts. The Beamer URL stays at /settings/advanced/conflicts (and the conflictId / conflictId/edit subroutes are unchanged) so existing deep links and the legacy column-stack layout keep working. The Sync branch is now always visible regardless of enableMatrix: the matrix-only leaves (backfill / stats / outbox / matrix-maintenance) are still flag-gated, but Conflicts stays reachable so legacy or local-only conflicts can always be resolved.

Task agents now react immediately to recorded audio. Brand-new task agents on a blank task no longer surface a "wake in 2:00" countdown — the orchestrator skips the throttle deadline while the agent is awaiting content, and the content gate keeps the agent from running until real content arrives. The moment a transcription finishes (cloud or realtime), the task agent is nudged via a manual wake that bypasses the standard throttle, so the user does not wait through a 2-minute window after speaking. Subsequent typing edits still go through the normal 2-minute coalescing throttle. Implemented via a new WakeReason.transcriptionComplete and an awaitingContent mirror in WakeOrchestrator, populated by TaskAgentService on creation and restoration.

Review polish for Settings V2: the tree view and detail pane now share a single tree + index via a SettingsTreeScope inherited widget so the five gating flags are watched only once per page mount and the two surfaces can never disagree on the tree shape. Leaf panel bodies are kept mounted across sibling-leaf switches via an IndexedStack cache so scroll position, filter state, and in-flight loaders survive navigation between, for example, agents/templates and agents/souls. The panel registry replaces its ad-hoc _scrollable(...) wrapper with a declarative SettingsPanelSpec so bodies that own their scrolling can't be accidentally double-wrapped. The URL sync bridge's single-shot guard becomes a counter so overlapping rapid taps don't leave the URL → tree guard in a wrong state. The width controller splits its user-intent flag from the persisted-load-race flag and guards against state writes after dispose. Duplicate settings node ids are now reported via a pluggable callback so release builds don't silently swallow authoring mistakes, and beamUrlToPath canonicalizes URLs by stripping query strings and fragments before prefix matching. The legacy /settings/maintenance URL is kept as an alias that still renders the MaintenancePage.

Bottom navigation bar polish: the sync outbox badge on the Settings tab now sits in the top-right of the icon to match the Tasks badge, and the audio and time recording indicators dock flush against the visible nav-bar pill instead of floating above it.

Saved filters for the Tasks tab. Build a filter (status, priority, category, agent, etc.) in the Tasks Filter modal, tap the new Save button next to Apply, give it a name, and pin it under "Tasks" in the expanded sidebar. Saved filters live in SavedTaskFiltersController (Riverpod, keepAlive: true), persist as a JSON list under SAVED_TASK_FILTERS in SettingsDb, and surface as a treeview with active-state highlight, hover-revealed two-tap delete, double-click inline rename, drag-to-reorder, and a "Tasks · {filter name}" indicator in the tasks pane header. Activating a saved filter applies it via JournalPageController.applyBatchFilterUpdate while preserving the ephemeral search query.

Desktop linked-task navigation no longer takes over the full window. Tapping a linked task from a task's details now pushes onto a per-pane stack inside the right-hand details area, leaving the task list pane visible. The back arrow at the top of the task details only appears on desktop when a linked task is on top of the stack, and clicking it pops back to the previous task instead of being a no-op. Mobile navigation is unchanged.

Agent wake cycles now sync as one bundled Matrix payload instead of emitting one outbox row per agent entity/link mutation. AgentSyncService wraps wake execution in a zone-local AgentWakeSyncInterceptor keyed by the wake run, buffers only agent entity/link messages, deduplicates by id, preserves superseded child vector clocks via coveredVectorClocks, and flushes a descriptor-backed SyncAgentBundle to the outbox when the wake exits. Receivers resolve the bundle attachment, apply entities before links through the existing agent sync handlers, and record each child payload in the sequence log so the convergence and backfill contract stays unchanged while wake traffic collapses to one Matrix message.

runInWakeCycle is reentrant-safe (nested calls reuse the active interceptor) and routes nested-transaction post-commit messages into the wake buffer so multi-transaction wakes still ship as a single bundle.

The success-path bundle flush swallows and logs outbox failures via DomainLogger instead of failing the wake run — the database writes have already committed, and maintenance and backfill paths can resurface the committed rows. The failure-path flush continues to attempt one final bundle send before re-throwing the original wake error.

The interceptor's merge step only carries forward the superseded clock (previous.vectorClock), since OutboxService prepare steps already add the current clock to coveredVectorClocks downstream and the receiver's filter strips it again before pre-marking covered counters.

New attachment family /agent_bundles/<wakeRunKey>.json is recognized by isAgentPayloadPath, the matrix stream helpers' extractJsonPathFromEvent, and the queue-apply adapter's transient attachment-error filter. Wake run keys are URL-encoded in bundle file paths to keep them within the documents directory.

Linux: emojis no longer render as tofu in agent reports, journal text, or any widget consuming a design-system text token. The token generator now emits a fontFamilyFallback chain (Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji) on every TextStyle so widgets that bypass the ThemeData-level fallback still resolve the correct emoji glyphs. The global theme's emoji fallback was widened from Linux-only to all non-web platforms.

Matrix verification emoji sequence now wraps onto multiple lines on narrow phone viewports. The 7-emoji row was overflowing horizontally on Samsung devices in portrait, cutting off the last cell. VerificationEmojisRow now uses a Wrap layout so the cells flow onto a second line when the screen width is constrained.

Resync Settings (Sync, Maintenance, Re-sync messages) now has an Entity types section with two checkboxes — Journal entities and Agent entities — both on by default. Unticking Agent entities lets the user bypass the agent-entity sweep when catching up a fresh device, where the agent corpus can otherwise enqueue around 20k entries and dominate the backfill cost.

Task Agent now sees the active running timer when one is running. If the timer is for the task being woken, the agent gets full details (timer id, started, live tracked range, elapsed minutes, current entry text) and can propose a richer description via the new update_running_timer tool instead of stacking a parallel create_time_entry — user-gated, replaces the timer entry text outright on approval, and keeps the in-memory TimeService snapshot in sync with the persisted entryText, dateTo, and updatedAt. If the timer is for a different task, only the live tracked range is exposed (no id, no other-task identity, no entry text) so the agent can avoid proposing create_time_entry intervals on this task that overlap with what is already being tracked elsewhere. Source-task ownership is checked before the timerId comparison so the active timer id is never echoed across task boundaries.

create_time_entry no longer rejects completed sessions whose start day is earlier than the wake day. The agent can now log a session the user dictates from yesterday or further back; the same-day constraint between startTime and endTime (no entries spanning midnight) and the not-in-the-future cutoff at wake time are preserved.

PersistenceLogic.updateJournalEntityText now returns false when its catch block fires, mirroring the contract of updateJournalEntity. A caught exception during the update no longer surfaces as a silently-true result with only a logged exception, so callers (including the new update_running_timer flow) can rely on the boolean to decide whether to proceed with downstream side effects.

Task Details typography pass: the entry editor, AI summary (TLDR plus expanded report), Task Agent reports/conversations markdown, linked-task titles, and agent suggestion items now pull font family, sizes, and weights directly from the design-system tokens. The editor body and agent markdown body share body.bodySmall (Inter, 14pt, w400); editor headings map to heading.heading3 / subtitle.subtitle1 / subtitle.subtitle2; linked-task titles use subtitle.subtitle2.

Code blocks gain a subtle theme-aware surface (background.level02 lifted by the surface.enabled overlay), a 1-px low-emphasis border, and DS radii (radii.xs inline / radii.s block). The Task Agent markdown checkbox is now compact, non-interactive (no hover overlay or click cursor), and shares the checklist row's radii.xs rounded shape, low-emphasis border, and interactive.enabled fill.

The AI Coding Prompt and AI Image Prompt card on Task Details now renders both its TLDR summary and its expanded full-prompt body through the shared AgentMarkdownView, so its typography, links, and code-block surfaces match the agent report and entry editor (body.bodySmall body text, design-system heading mapping, low-emphasis checkbox style) instead of the package-default GptMarkdown styling.

VectorClockService now advances its persisted counter only after the associated write and outbox enqueue both succeed. A reservation API plus a zone-based scope wrapper bumps the in-memory watermark synchronously so concurrent reservations stay collision-free, but only commit persists to SettingsDb; release rewinds the in-memory watermark when the reservation was the latest. The known burn call sites in PersistenceLogic (createDbEntity, updateDbEntity, updateJournalEntity, createLink) and AgentSyncService (upsertEntity, upsertLink, insertLinkExclusive, and the outermost runInTransaction) are wrapped in this scope, so an applied=false rejection, a transaction rollback, or an exception between getNextVectorClock and outbox enqueue rolls the counter back instead of burning a gap that only backfill could close.

Outbox processor now atomically claims the next row (pending → sending) instead of reading it as pending and sending with a stale snapshot. Under the old path a merge that fired during the hundreds-of-milliseconds send I/O would update the row in place, the processor would still send the pre-merge payload and mark the row sent, and the merged coveredVectorClocks — including the old VC the merge existed to preserve — were silently abandoned. The result was scattered single-counter holes on receivers that only backfill could close. With the atomic claim, merges' CAS-on-pending update no longer matches the in-flight row and the merged content spills into a fresh pending row that still rides its own Matrix event.

Adds the first slice of Settings V2 behind a new enable_settings_tree feature flag (desktop only, default off): a tree-nav + detail-pane alternative to the current multi-column Settings layout. The domain layer (node model, flag-aware tree builder, URL↔path index with greedy longest-prefix matching for panel-local UUIDs), the state layer (path notifier implementing the spec's four click rules, plus a resizable-column width notifier with clamp and debounced persist under a distinct storage key), and the chrome (56 dp header, locale-backed tree view, draggable resize handle with drag / double-tap reset / arrow-key and shift-arrow nudges / Home-to-default, plus a detail placeholder carrying a persistent "Disable Settings V2" escape-hatch button) all ship here. Real leaf panels follow in later steps — turning the flag on today shows the tree and returns a "panel not yet implemented" state for each leaf until those land.

BackfillRequestService now skips analysis and dispatch while the bridge coordinator is mid-walk (forward-reading fresh timeline events from the last applied event id). Gaps observed during the walk may be closed by events still in the pipe, so the periodic timer and nudge() wait for the walk to conclude before asking peers for anything — preventing bogus ~100-entry requests that raced ahead of the inbound path. Manual Full Backfill bypasses the gate so user actions are never silently dropped.

Sync V2 is now the only inbound pipeline. The use_inbound_event_queue config flag, its Flags-page toggle, localized strings, and the suppressLegacyPipeline switch on MatrixService are gone. QueuePipelineCoordinator is a required constructor argument, the consumer's live ingestion is always suppressed, catch-up routes unconditionally through the coordinator's bridge, and the legacy connectivity-driven forceRescan coalescing plus the _maybeStartQueuePipeline flag-branching are removed.

The checklist "Add a new item" pill border now lights up on focus. After the previous fix silenced the themed inner outline, the outer pill stayed visually static on tap and lost its editable affordance. The outer 1 px border now cross-fades between the decorative hairline (idle) and the interactive accent colour (focused) over 200 ms, while the border width stays pinned at 1 px so the pill never breathes and sibling rows don't shift.

Settings list rows now match the task list's subdued treatment. The default activated-row fill moved from the saturated surface-active colour to a shared design-system helper (the interactive accent at 12% opacity, the same source the task-list palette now consumes), so selection reads as a gentle hint rather than a loud block. The divider between any two rows fades to transparent whenever either one is hovered or active — keeping its 1 px of reserved space so hover never causes the column to jitter — mirroring the task-list behaviour where an interacting row is never bisected by a partial-width line.

Fixed the checklist "Add a new item" pill sprouting a second outline when focused. The inner TextField only disabled its default border, so the app-wide focused/enabled/error borders from InputDecorationTheme still overlaid themselves inside the already-pill-shaped container on tap. Every state-specific border variant plus the themed fill are now explicitly neutralised on the decoration, so the field stays visually flat inside its pill in all focus states.

Desktop Settings is now a horizontally scrollable multi-column layout instead of a two-pane list + detail. Every meaningful level of the route tree renders as its own column, so drilling from Sync into Backfill adds a third column on the right instead of replacing the Sync sub-menu. Columns share a single fixed width, the rightmost column expands to fill remaining viewport, and the row becomes horizontally scrollable with an auto-scroll to the newly-added column when the stack overflows. Mobile keeps the single-page push navigation fallback.

Queue-pipeline InboundWorker now fans the adapter's prepare phase out across the whole batch via Future.wait. Prepare is I/O-bound (attachment downloads, gzip decode, JSON decode) with no shared state, so running it in parallel collapses each batch's prepare critical path to the slowest entry instead of the sum. Apply still runs sequentially inside journalDb.transaction to preserve the writer-lock discipline, and prepared payloads are cached by eventId so apply consumes each one exactly once. Directly addresses the cold-start catch-up throughput cliff where every entry waited on its predecessor's attachment download before its own prepare could begin.

Fixes stuck sync_sequence_log rows blocking the watermark indefinitely. A row could slip into 'requested' status via the backfill-response-hint path or age out of the active backfill window before hitting the request-count cap, then sit non-terminal forever and prevent the contiguous prefix from advancing — causing every new event on the same host to re-emit the same gap range through gap detection. A new age-based retire runs alongside the existing exhausted-retire on every backfill sweep: any missing/requested row older than 7 days is promoted to unresolvable regardless of request_count.

Prunes sent outbox rows older than 7 days so the outbox table no longer grows unbounded. Error rows are kept forever so persistent failures remain inspectable; pending and sending rows are never touched. Observed growth before this change: hundreds of thousands of rows accumulated over months, a direct contributor to slow outbox enqueue/dedup queries and heavier WAL checkpointing. The sweep runs at startup after a short grace window and every 24 hours thereafter.

Fixes agent_links upsert failing when a sync-incoming soul_assignment or improver_target link arrives with a new id but the same from_id or to_id as an existing active row. The partial unique indexes threw SqliteException(2067), apply was classified retriable, retries exhausted after 10 attempts, and the queue row was silently abandoned. upsertLink now preemptively soft-deletes the colliding active row before inserting the new one under the same transaction.

New "Ask peers for unresolvable entries" diagnostic action on the Backfill Settings page. Flips every unresolvable sequence-log row back to missing so the normal backfill sweep re-asks peers — covers the case where the originating host is dead but a currently-alive peer still has the payload. Complements the narrower "Reset Unresolvable" action, which only resets rows whose entry_id is already known locally.

New "Retire stuck entries" diagnostic action on the Backfill Settings page. Runs the age-based sequence-log retirement with a zero-length amnesty window after a confirmation dialog, marking every currently-open missing or requested entry as unresolvable. For the case where a user has identified stuck rows blocking the watermark and wants immediate recovery without waiting for the periodic sweep.

Reconnect bridge now attempts a forward-walk from the last applied event id via the Matrix /context + /messages?dir=f APIs, instead of walking the SDK's cached backward timeline that typically predates the gap window. Backward walk remains as a fallback. The intent is to let a client close reconnect gaps from the server directly without depending on a peer being online; behaviour is unverified in production and needs observation.

Outbox drain no longer stop-and-go-crawls through large backlogs. The per-runner-pass cap was lifted from 20 items to 2000, and the processor now fetches just the head-of-queue plus a cheap "hasMore" probe instead of 10 rows per call (throwing 9 away). Together, a thousand-row outbox that previously took ~50 runner re-entries with 9000 wasted row reads now drains in one runner pass with zero waste.

Queue pipeline now drops self-echoed events at the live-timeline ingress. Every message this device sent via the outbox came right back through Matrix's /sync on the same room, and the queue was re-enqueuing, re-preparing, re-applying and re-downloading every one of them — which made outbox throughput look pathologically slow under a large drain. The coordinator now consumes the event ID from SentEventRegistry before touching the queue or the attachment ingestor.

Reconnect bridge no longer exits prematurely when the Matrix SDK's local timeline cache has not loaded the wake-up window yet. The history walk now keeps paginating past the boundary for a bounded number of extra round-trips when each page's events are all duplicates/filtered-out, so the SDK has a chance to pull more history into its cache. Paired with this, the queue coordinator records a "barren bridge" signal whenever a reconnect walk finishes without accepting anything, and the next sequence-log gap detection triggers a one-shot unbounded history walk to close the hole aggressively instead of waiting for the normal backfill cadence.

Restores the task title edit affordance in the new DesktopTaskHeader. The read-only title now renders a trailing pencil icon next to the label, and empty titles display a localized "No title" placeholder in the same tappable slot so users have an obvious target to open the inline editor. Task list rows render the existing "(untitled)" label in the design-system error color and italic so missing titles stand out rather than silently collapsing the row.

Adds Phase 0 sync observability for the planned Inbound Event Queue redesign. MatrixStreamSignalBinder now records two additive probes on the sync room: a sync.limited log line with prevBatch, event count, and the time gap since the previous sync response whenever the Matrix server returns timeline.limited == true, and an onTimelineEvent.ordering summary every 100 events tracking strict reorderings and same-timestamp ties. Both route through the MATRIX_SYNC log domain into the dated sync log file. No behaviour change; data from ~48 hours of real use validates the two load-bearing SDK assumptions before the queue refactor starts.

Fixes the desktop UI freezing during Matrix sync. The per-event apply loop in MatrixStreamProcessor used to hold the SQLite writer lock while awaiting attachment downloads, gzip decodes, and disk reads — on a 20-event catch-up slice this blocked user-driven journal saves for seconds at a time. SyncEventProcessor now splits into prepare (all I/O, no DB writes) and apply (pure DB writes); the pipeline runs prepare for a chunk in bounded-concurrency batches (4 at a time) outside the transaction, then opens a single transaction to apply the pre-resolved results. Outbox send-side gzip encode is also offloaded to a worker isolate for payloads above 2 KB. A regression test guards the invariant that every prepare completes before the writer transaction opens.

Fixes live sync stalling until force-restart. The live-scan in-flight guard could stay set indefinitely if the apply pipeline hung on an unbounded Matrix attachment download — every subsequent timeline signal then coalesced silently and was dropped. All attachment downloads are now wrapped with a 45 s timeout that converts a hang into a retriable FileSystemException, and a stuck-scan watchdog releases the guard after 90 s so the pipeline recovers on its own rather than requiring a restart.

Reduces sync log volume by roughly 40% at info level. The outbox send path used to emit about ten info lines per successful send across four subdomains; a single capture at the outbox processor now summarises the send with type, subject, retries, elapsed ms, and remaining pending queue depth. Per-event attachment.observe and attachmentIndex.record lines are gated behind a verboseLogging flag on AttachmentIngestor and AttachmentIndex; production wires this to false so steady-state and pagination-burst line counts drop, while tests keep the flag on to preserve existing per-event assertions. Failure, retry, and circuit-breaker diagnostics are unchanged.

Sync signal sources consolidated. The live timeline only subscribes to append triggers (onNewEvent, onInsert); onChange, onRemove, and onUpdate had no legitimate driver in a single-user append-only sync model and are no longer wired. Their counters are dropped from the metrics snapshot and the liveScan.summary breakdown. The AppLifecycleRescanObserver widget was removed because the 30 s wake detector and connectivity-driven rescan already cover app resume; it was producing the forceRescan.skipped noise seen in recent logs.

Adds a stateful inbound sync queue behind the USE_INBOUND_EVENT_QUEUE settings flag (default off). When the flag is on, live events, the limited=true bridge, and the new "Fetch all history" and "Catch up now" actions route through a Drift-backed queue with a single drain worker per room; per-room markers live in a new queue_markers table so commit and marker advance are atomic and monotonic. Encrypted events are held in a decryption pen until the Megolm session key arrives, so pre-decryption ciphertext never lands in the queue. The legacy live-scan pipeline is suppressed when the flag is on, keeping the two paths mutually exclusive. Sync Settings gains a flag-gated queue depth card plus Catch-up-now and Fetch-all-history actions. Pipeline-tagged log lines let the Phase-2 validation gate compare apply rates across the two paths.

Fixes three queue-pipeline gaps flagged by the design review: saveRoom now re-seeds the queue marker for the new room and prunes rows from previous rooms; the coordinator fires a background bridge pass on start so reconnects that do not flag the timeline as limited no longer silently drop events; and the flag-off drain waits for retriable, decryption-pending, and noRoom rows to mature up to a 30-second bound instead of returning as soon as no rows are ready at call time.

Task detail header rebuilt against the desktop Figma:

  • New DesktopTaskHeader replaces the pinned title sliver and legacy TaskHeaderMetaCard, with an inline capsule-style multi-line title editor and three explicit rows for title, classification, and metadata.
  • Figma priority / status / project / due-date / work-category chips; estimate chip with live progress bar and overtime styling; assigned-label chips with a leading color dot.
  • Subdued placeholder chips for every empty state ("No project", "unassigned" category, "No due date", "Add Label") open the corresponding picker when tapped.
  • Due-date urgency is tri-state: orange today, red overdue, subdued otherwise.
  • Task title now persists in the app bar in subtitle2 once the header scrolls out of view.
  • AI Task Summary, Task description, Linked Tasks, and Checklist cards render on a flat TaskDetailSectionCard surface so they visually match the task list.
  • TaskLabelsWrapper and the per-chip wrappers that fed the old meta card are removed; shared modal content widgets (status, priority, category, project, due date, labels) are retained and reused.
  • Task language selection moves from a flag pill in the header to a "Set language" entry in the pinned app bar's triple-dot menu; the currently selected language's flag renders inline next to the action and opens the same language selection modal as before.

The desktop navigation sidebar can now be collapsed to a narrow icon-only strip via a menu icon next to the logo. Destination labels become tooltips in the collapsed state and the brand logo hides to free up horizontal space. Drag-to-resize is disabled while collapsed so labels never get clipped at an intermediate width, and the divider still paints its hairline so adjacent panes do not shift across the transition. The collapse flag and the last expanded width are persisted, so re-expanding restores the exact prior divider position and the state survives restarts.

Priority / status / label pills in the task filter sheet no longer "breathe" when toggled. The pill used to widen its border from 1.0 to 1.5 px on selection, which nudged every sibling chip in the Wrap by 1 px per edge on each toggle. The border width is now pinned at 1.5 px in every state and a 400 ms easeInOut animation cross-fades the border and fill colour alphas between deselected and selected, so the outer dimensions of every chip are identical at every frame and neighbours never reflow.

Sync startup no longer does every step twice. The connectivity-driven forceRescan and the consumer's runInitialCatchUpIfReady used to race into _attachCatchUp() concurrently because neither acquired _catchUpInFlight for its run, producing two catchup.waitForSync passes, two backfill.start fetches, and two ordered replays of the same event slice. _attachCatchUp() is now the single owner of _catchUpInFlight and the deferred-live-scan flush, short-circuiting concurrent runs with a catchup.skipped (in flight) log. All other entry points now defer to it instead of managing the flag themselves; the obsolete bypassCatchUpInFlightCheck parameter is removed.

Pre-history gap handling no longer logs per incoming event. Hosts carrying a permanent unresolved prefix used to re-emit largeGapDetected, gapDetectedRange, recordReceivedEntry detected N gaps, and apply.*.gapsDetected for every catch-up event, dominating the desktop sync log. The sequence service now suppresses those lines on incremental extensions of an already materialised range and returns only the newly materialised subrange to callers. A fresh idle restart now logs tens of lines instead of 400 KB.

Removed the redundant start.catchUpRetry catch-up on every startup: the signal binder's 150 ms follow-up runGuardedCatchUp only runs when the initial catch-up has not yet completed. Once catchup.initial.completed fires, the retry is skipped instead of kicking a second full _waitForSyncCompletion + event-replay pass.

Connectivity bootstrap no longer duplicates the startup rescan. connectivity_plus emits the current state synchronously on subscribe, which used to schedule a forceRescan racing the dedicated startup rescan. The listener now swallows the first emission while still recording the connectivity signal for metrics.

DailyOS mobile fix: the DailyOS page no longer surfaces "Failed to load timeline" and "Failed to load budgets" on devices where the v39 migration's partial expression index is missing. The open-task due-date query retries once without the index pin, and beforeOpen recreates the missing indexes on every launch so affected devices self-heal.

Outbox / sync DB: removed a 40–600 ms main-isolate blocking query triggered on every outbox enqueue (including each image paste or drag-and-drop). getLastSentCounterForEntry used to compute MAX(counter) against an index that did not include counter, forcing SQLite to read every matching row from the heap for hot entry_ids. The v11 schema replaces idx_sync_sequence_log_host_entry_status with a covering idx_sync_sequence_log_host_entry_status_counter, the query is rewritten as ORDER BY counter DESC LIMIT 1 for an index-only scan with early terminate, and the sequence service now caches the last-sent counter per (hostId, entryId) with LRU capacity 2048. Follow-up lookups for the same entry hit the cache and skip the DB entirely; the cache is kept consistent by refreshing it on recordSentEntry. Removes the multi-second UI freeze observed when pasting or dragging images.

Sync: eliminated the dominant source of redundant work on devices that carry a permanent pre-history gap in the sequence log. Previously, every incoming event on such a host re-ran a multi-chunk scan of the sync_sequence_log table plus a batch-insert pass over thousands of already-materialized rows, and emitted four INFO log lines per event. The sequence log now memoizes the highest counter already materialized as a missing range per host and short-circuits the entire pass when the observed range is already covered; when the observed counter advances, only the incremental delta is scanned and logged. This removes the main cause of severe mobile UI blocking on slow sync queries and the bulk of the daily sync-log volume on desktop.

Sync: missing or requested rows whose backfill request count reaches the per-entry cap are now retired to the terminal unresolvable status automatically at the start of each backfill cycle. Without this, a permanently unresolvable counter — a pre-history entry, a purged payload, or a mapping whose payload vector clock is permanently behind the requested counter — kept the contiguous-prefix watermark in getLastCounterForHost stuck forever, which in turn forced gap detection to re-enter on every subsequent event for the same host. The watermark now advances past these rows and gap detection stays quiet.

Sync attachments: the matrix SDK's "File is no longer cached" error used to be emitted as a full exception with stack trace on every replay of an evicted attachment event, with zero recovery value. The ingestor now records the event id the first time this happens and short-circuits subsequent attempts immediately, collapsing bursts of hundreds of error entries per day to one info line per eviction.

Sync: duplicate in-flight descriptor fetches for the same attachment event are now deduplicated. Two text events referencing the same jsonPath within a single catch-up or live-scan wave previously each launched an independent download, decrypt, and decode; they now share a single future keyed by the index key and descriptor event id.

Outbox: the sendNext.state and dbNudge observability lines are now coalesced. They emit on state transitions and at a 30-second minimum interval instead of once per tick, removing the majority of steady-state outbox log lines without changing enqueue or send behavior.

Agent suggestion panel now surfaces the reasoning behind resolved proposals without cluttering the list. A collapsed "Recent activity" strip shows the three most recent ledger entries (newest-first) with verdict icons — check for confirmed, X for rejected, undo for agent-retracted — and when a rejection or retraction carries a reason it lives behind an info icon whose tooltip reveals the text on tap or hover. The strip stays hidden entirely when there is no resolved activity. A "Confirm all" action sits next to the pending badge whenever more than one open suggestion is pending.

Initial-language auto-apply: set_task_language now bypasses the deferred-confirmation flow when the task has no language set yet, so the agent can pick the language silently on first use. Re-tagging a task that already has a language continues to flow through the standard change-set approval path.

Suggestion rows no longer display the raw snake_case tool key beneath the human summary — the tool name was developer-facing noise.

Task agent: the mandatory update_report tool call at the end of every wake is now a hard guarantee instead of a prompt-only request. When the model stops without calling it — a routine failure mode for weaker local models such as Qwen 3.6 served via mlx-vlm — the workflow now issues one additional inference pass with tool_choice pinned to update_report and a direct reminder message, forcing the final report. ConversationRepository.sendMessage and the underlying inference layer gained a threaded toolChoice parameter that overrides the default auto selection policy; the override is currently honored on the OpenAI-compatible path and silently ignored by the Gemini/Ollama/Mistral sub-repositories, which still benefit from the retry's pointed user message. The task-agent scaffold and the seeded report directive also now lead with a non-negotiable "final step" instruction so compliant models need no retry at all.

Initial-title auto-apply: when the task agent calls set_task_title on a task whose title is still null or empty, the title is applied immediately without a user-approval prompt, so a freshly dictated task lands with a meaningful name instead of an empty-looking suggestion waiting in the panel. Once a title is present the tool reverts to the standard deferred confirmation flow, and a second silent-abort guard inside TaskToolDispatcher no-ops any race in which a manual edit, synced edit, or previously-confirmed proposal populated the title between the LLM emitting the call and the dispatcher running.

Task agent suggestions are now surfaced in a single consolidated panel on the task detail page instead of two disconnected cards, and the agent itself can autonomously retract its own stale proposals. On every wake the agent receives a unified proposal ledger listing every suggestion it has ever made for the task, grouped into open vs. resolved entries and carrying stable fingerprints. A new immediate retract_suggestions tool lets the agent withdraw proposals that are no longer relevant (the task state already matches them, the user made the change manually, or they duplicate another open proposal) without any user prompt — the item simply disappears from the active suggestion list, leaving an auditable trail alongside user confirmations and rejections. Dedup now excludes retracted items from its basis so the agent can cleanly re-propose after the task context materially changes, while user rejections remain sticky.

Sync pipeline: removed duplicate-work in inbox attachment handling and sync-family logging. AttachmentIndex.record now dedupes per eventId so repeated observations from live scan, catch-up, and backfill passes become no-ops instead of thrashing the per-path slot between events sharing one relativePath. SyncEventProcessor and SyncSequenceLogService no longer emit each log line twice — DomainLogger is the single emitter and falls back to a direct sync-domain capture when no domain logger is wired. Descriptor catch-up skips events whose relativePath is not in the pending set, so the per-run scan no longer records ~1000 unrelated events into the attachment index. Removed the per-tick OUTBOX enqueueRequest() done log, which fired on every debounced wake and carried no signal.

Sync pipeline: the per-event apply loop in MatrixStreamProcessor now runs inside a single JournalDb.transaction, so a slice of N sync events commits once instead of N times. Drift coalesces journal-table stream emissions to one notification per slice, collapsing the reader/writer lock contention that produced multi-second waits behind otherwise-cheap id IN (?) lookups during large catch-up replays. Per-event error handling is unchanged: individual apply failures are still caught locally and scheduled for retry, so the transaction only rolls back when a commit genuinely fails.

Desktop task switcher: switching between open tasks in the desktop split layout now crossfades the detail pane instead of cutting abruptly. The transition is a 480 ms easeInOutCubic fade driven by an AnimatedSwitcher keyed on the selected task id, so it fires only when a genuinely different task is opened — reloads and in-place data updates for the currently open task do not trigger the animation.

Desktop navigation sidebar: the Tasks and Settings notification counts now render as a design-system number badge in a dedicated trailing slot on the right of each row instead of a Material Badge overlapping the icon and label. Vertical spacing between sidebar items is now 24 px to match the Figma layout. Sidebar rows are no longer pinned to a fixed 48 px height — each row grows with its label, so increasing the OS or app text scale no longer vertically clips "Projects", "DailyOS", "Insights", "Logbook" or "Settings". The mobile bottom-nav preserves its existing overlay badge.

Database schema bumped to v39 with two new partial indexes on the journal table. idx_journal_tasks_due_open is keyed on the JSON-extracted due date for open tasks so the due-date query streams straight from the index without an external sort, and idx_journal_task_status_private covers countInProgressTasks and similar global task-status counts with a narrow index instead of scanning the full task set. Both partials carry type = 'Task' AND task = 1 AND deleted = FALSE so they stay consistent with the other task indexes and SQLite's theorem prover reliably proves coverage for the paired queries.

Fix a P0 bug that prevented AI-proposed time entries from being confirmed from the task "Proposed changes" panel. The approval-time validator previously rejected any create_time_entry whose startTime or endTime fell after the originating wake timestamp, which left suggestions like 11:13–11:48 or 11:00–13:00 stuck as pending with a "Failed to apply change" toast whenever the agent rounded or estimated a session past the wake instant. The wake timestamp is still used for the same-day check (so after-midnight approvals keep working), but the "not in the future" cutoff no longer applies at approval time — the user is the authority when confirming. endTime must still land on the same day as startTime.

Desktop tasks and projects surfaces are aligned with the Figma design system. Sidebar, task list, task details and projects list share the deeper background/01 surface while task cards sit on background/02, and dark-mode text tokens were raised to the Figma-specified opacities (high 100%, medium 80%, low 64%) so headlines, subtitles and timestamps read with the correct contrast without changing type weights. The selected task row now uses the Figma surface/selected token for a subtler highlight, and task group headers and counts use the caption token for a lighter hierarchy. The task title strip and its sliver app bars render on background/01 with no elevation so the header no longer reads darker than the body.

The sidebar drops the legacy "+ New" quick action, always uses the filled settings glyph, and swaps the Ionicons/MDI nav glyphs for Material rounded/outlined equivalents (Tasks, Projects, DailyOS, Habits, Insights, Journal, Settings). The Insights nav tab now reads "Insights" (English/en-GB) and "Einblicke" (German).

Task list filter chips use the design-system chip component and render inline under the search bar, with priority chips carrying a leading priority glyph. Tasks and projects filter triggers use filter_list_rounded to match the Figma funnel glyph. Tasks and projects headers are pinned outside the scroll view so the title stays static and pull-to-refresh only drags the list below it. The floating action button is now a rounded-24 teal surface matching Figma, and the journal and task details FABs were swapped from Flutter's default circular FAB to the design-system FAB so list and details FABs share the same shape and bottom-right anchor.

Optional gzip compression for JSON sync attachments over Matrix, gated by a new config flag that is off by default. Receivers always decompress when the encoding marker is present on an attachment event, so turning compression on for a single device stays compatible with peers on this release. Only .json attachments are compressed; media files are already on compressed formats and skip the branch.

Raise the open file descriptor soft limit to 10,240 at startup on macOS and Linux. The legacy 256 limit inherited by GUI apps on macOS was trivially exhausted under real-world load, which under slow-network conditions manifested as sporadic EMFILE errors on the Matrix sync pipeline and cascading DNS lookup failures until the app was restarted.

Startup now logs the soft/hard limits and the adjustment outcome, and EMFILE failures on the attachment save path are annotated with the current descriptor limits so future file-descriptor-pressure incidents are self-diagnosing.

Task filter modal redesigned with the design system filter sheet. All filter modals now use Wolt modal sheet for consistent adaptive presentation. Selected filter chips show contextual icons for status, category, and label. Priority glyphs updated to match Figma designs.

Categories, labels, dashboards, measurables, and habits list pages now use design system list items in a grouped container, matching the settings page visual style. Maintenance, logging domain, sync settings, and sync maintenance pages likewise updated. Settings page uses a 3-column desktop layout for wider screens.

Project one-liner: AI-generated summary subtitle on project list cards, giving an at-a-glance status for each project. The project agent now produces a dedicated one-liner field in its report, separate from the longer TLDR summary.

Removed the gamey theme and all gamey-styled widgets. Standard Flutter widgets and existing modern cards are used instead.

Resizable panes in desktop layout: drag dividers between the navigation sidebar and content area, and between the list and detail panes, to adjust widths. Pane sizes persist across sessions.

Tasks desktop split view now keeps the current loaded list window mounted until refreshed pages resolve, which reduces visible flicker during task saves and other live updates while preserving regrouping after sort changes.

Dashboard list page redesigned: the old SliverAppBar top bar has been removed and list items now use rounded grouped cards with design system tokens for a modern, consistent look.

Task list improvements: AI one-liner subtitle shown below each task title for at-a-glance progress, red recording indicator on actively-tracked tasks, and live in-place data updates when editing in the detail pane.

Removed animated page transitions to eliminate visual flicker during list loads and refreshes.

Desktop mode: responsive layout switches from mobile bottom navigation to a persistent left sidebar when the window is wider than 960px, with all navigation destinations and Settings pinned at the bottom.

Desktop split-pane view for Tasks, Projects, and Dashboards: list and detail views shown side by side with reactive selection and active item highlighting in the list pane.

Checklist filter tabs now include Open, Done, and All. Initial collapse animation on checklists is disabled to prevent jank on slower devices.

Task filter modal: replaced with the design system version, now includes project filter (grouped by category), agent assignment filter, and search mode toggle (desktop only). Cover art is now always shown on task cards.

Bottom navigation rollout: every main app tab now uses the Widgetbook design-system bottom navigation shell instead of the legacy Spotify-style bar, with the floating pill centered consistently across the app.

Mobile bottom sheets and Wolt modals now open on the root navigator on narrow screens so they render above the floating bottom navigation and block tab switching while a modal is active.

Tasks and Projects now share the same design-system floating action button, and the shared bottom-navigation spacing now lifts floating action buttons and recording indicators clear of the navigation chrome across list, detail, and settings surfaces.

Task status selection redesigned: a vertical list of rows with icon, label, and a trailing checkmark on the active status replaces the old chip grid. Icons and colours now match the design reference exactly.

Checklist widget redesigned: progress ring shown in the header when checklist items exist, filter tabs with highlighted selection, plain add-item field, pencil-only edit trigger for items, and fully localized AI suggestion and Share labels.

Progress ring and three-dot menu are hidden when there are no checklist items. Checklist item rows now expand to accommodate multi-line editing and larger system text scales.

Standalone soul evolution: dedicated 1-on-1 sessions focused on personality refinement, aggregating feedback from all templates sharing a soul. Accessible via the soul detail page with its own review page and session history.

Tasks tab migration: added a new design-system browse page behind the enable_tasks_redesign runtime flag. The new route keeps the existing infinite-scroll paging, current filter modal/model, create-task flow, and task-detail navigation while rendering sort-aware grouped sections.

Tasks tab redesign: aligned grouped cards more closely with Figma by switching to the actual task-status glyphs, inset dividers, priority-section header treatment, tracked-time metadata, and a filter-modal search-mode control in place of the inline full-text/vector toggle.

Tasks tab polish: replaced the provisional priority glyphs with the actual Figma P0 to P3 icons and restored the intended breathing room below the search row.

Tasks and projects grouped cards: both tabs now share the same hover and selection row-surface behavior so active rows blend over adjacent dividers consistently, while task category chips now use the same category tag component as projects and the task rows have slightly looser spacing.

Bottom navigation migration: the redesigned Tasks tab and the Projects tab now render the Widgetbook design-system bottom navigation bar, while the remaining tabs keep the legacy Spotify-style navigation during the rollout.

Desktop zoom: Cmd+/- keyboard shortcuts and View menu items for zooming the app UI in and out, with Cmd+0 to reset. Zoom level persists across sessions.

Token usage Stats tab in Agents Settings: iOS battery-usage-inspired dashboard showing 7-day and 30-day token consumption with interactive bar charts, average vs. today comparison, per-model breakdowns, and per-template source activity with high-usage alerts.

Wake activity chart migrated into the new Stats tab for a unified view.

Soul evolution UI: standalone soul evolution page with an interactive evolution catalog, soul selector, and a conversation-based refinement workflow for iteratively shaping agent soul documents from templates.

Pluggable soul document: soul documents can now be customized per agent template.

One-on-one v2: redesigned agent one-on-one conversation experience.

Manual planning flow: new "Set time blocks" step for manual daily planning.

Proposed changes card: removed inline confirm/reject buttons; users now swipe or use "Confirm all".

Settings page restyled to use design system list items. Context menu aligned with Figma design.

Projects tab improvements: task rows show agent one-liner summaries, follow-up tasks inherit the parent project, and scroll behaviour is smoother.

Fixed agents self-notification loops and projects page flickering.

Agents settings now include a Pending Wakes dashboard with a live badge count, per-wake countdown cards, and per-card deletion for deferred and scheduled wakes.

The Agents Instances tab now shows a compact task-agent fleet summary under the filters, including current totals for all, active, dormant, and destroyed task agents.

Task-agent wake prompts no longer inject sibling-task TLDR directories, and the related-task drill-down tool now stays defined in the registry while being hidden from the LLM until a stronger retrieval path is in place.

Projects detail task summaries: project-task rows now show the latest task-agent oneLiner subtitle between the task title and metadata, matching the current Figma spacing and typography on mobile and desktop layouts, and open project detail pages now refresh automatically when a task-agent report finishes.

Task-agent reports: the update_report contract now requires a dedicated oneLiner tagline alongside the TLDR and full report so task cards can show a concise current-state summary without reusing the longer report text.

Projects detail data path: highlighted task rows now bulk-load the latest task-agent reports for all linked task IDs in one repository call, avoiding N+1 report queries on larger projects.

Projects list grouped cards: category group containers now render the same subtle bordered card treatment shown in the current Figma list designs, instead of relying on background fill alone.

Projects detail live refresh: when related-task updates reload the derived project detail record, the page now keeps the previous content mounted until the new record resolves, avoiding full-page flicker and scroll-position jumps.

Projects detail scrolling: the top-level detail route now renders the task panel through a sliver-based lazy list, which keeps large project task lists steadier during fast downward scrolling instead of eagerly laying out every task row.

Follow-up tasks now automatically inherit the project of the parent task they were created from, both from the UI and from the agent follow-up task workflow.

Design system navigation: the mobile detail back control is now a reusable component with the intended regular-weight label styling, so detail pages do not drift into heavier back-button text.

Projects detail task statuses: project-task rows now use the Figma-aligned colored status glyphs for in-progress, done, on-hold, blocked, and related task states instead of flattening every status icon to the same gray tone.

Projects detail task typography: project-task titles are explicitly kept at regular body-small weight, and the duration plus status line now uses one shared compact caption text style.

Projects detail task list: task rows now let long task titles wrap across multiple lines and keep duration plus state metadata underneath, with extra vertical breathing room in the Project Tasks header.

Projects list spacing: widened the grouped project-row horizontal inset so titles, metadata, and status pills sit with the intended breathing room inside each card.

Projects detail redesign: the top-level Projects flow now opens a new design-system-aligned detail page at /projects/:projectId, with editable category, due date, and status controls, a health-band header, manual agent refresh, an expandable AI report, and the current project-tasks card.

Projects detail data path: the new detail surface now builds from live project, task, category, and project-agent state while reusing the same shared component tree in the app and Widgetbook. Project-task rows now open task details directly, while the older settings-scoped project views remain in place for category-driven flows during the rollout.

Projects detail UX polish: category and due-date pickers are now reachable even when no value is set, the empty-state report copy only appears when both summary and full content are absent, and expanded reports strip the leading H1 title that the UI already renders above the report section.

Projects visual polish: grouped project rows, progress rings, and project-task rows now match the linked Figma spacing more closely, with progress colors driven by completion level and the mobile detail title reduced to the intended heading size.

Projects tab search: the live top-level Projects page now supports local substring search over the grouped list, and the shared design-system search field keeps typed text stable across rebuilds while centering the search text correctly on mobile and desktop surfaces.

Task agents now receive parent-project context on wake when a task belongs to a project, including the latest project-agent TLDR and full report body so task recommendations can align with project-level priorities and blockers.

Task agents now also receive a bounded directory of related tasks from the same project, using stored sibling task-agent TLDRs plus logged time spent, and can inspect one of those sibling tasks on demand through a new read-only drill-down tool scoped to the current wake context.

Projects tab: the new top-level Projects tab now ships behind the enableProjects feature flag with the intended design-system mobile layout. The live tab and the Widgetbook mobile reference now mount the same sliver-driven header, grouped category sections, and floating create action, while the search field stays disabled pending the later vector-search follow-up.

Projects filters: the Projects tab and Widgetbook showcase now share the same design-system filter modal, nested field-selection sheet, and state model for project-status and category filtering instead of keeping separate mock-only filter behavior.

Projects tab reactivity: grouped project snapshots now refresh automatically when relevant project, task, category, or private-visibility updates arrive, so status changes such as Active to Completed are reflected in the UI without reopening the page.

Projects now show a compact health band at a glance in both the tasks-page project header and project detail page based on the latest project-agent report.

Linked task activity now marks project summaries stale for the next 06:00 local-time digest, while app state also exposes stale status and active project recommendations for upcoming project health dashboard surfaces.

Direct edits to a project and task linking changes now use the short deferred project-agent wake path, while other task-level activity stays stale-only until the next scheduled digest unless you refresh manually sooner.

Projects now also have a top-level tab behind the enableProjects feature flag, reusing the existing bottom navigation and loading grouped project/category data through a single batch overview path.

Chinese AI Profile: added Qwen 3.5 Plus model and Chinese AI inference profile for Alibaba Cloud with multimodal capabilities (text, vision, audio, image generation). Simplified FTUE setup by removing automatic prompt creation — AI capabilities now use skill-based automation via inference profiles.

Project agents now track pending project activity in synced state, skip dormant daily digests to save tokens, and show stale summaries in the tasks-page project header until the next 06:00 refresh.

Project detail pages now show the current project-agent report inline, let you trigger a manual refresh, explain when no project agent exists yet, and return to the originating category instead of the top settings page.

Confirmed project-agent next-step proposals now persist as active project recommendations that supersede older guidance and can be resolved or dismissed from the project detail page.

Design system Tabs: added a new Widgetbook-first Tabs component with small/default sizes, token-driven interactive states, optional counter and icon slots, and focused widget/widgetbook coverage.

Design system Calendar picker: added a Widgetbook-first calendar picker with month rail navigation, token-driven monthly range cells and weekly date cards, plus focused widget/widgetbook coverage.

Design system Progress bar: added a Widgetbook-first determinate progress bar with default and chunky variants, optional header content, token-driven fill and track treatments, and focused widget/widgetbook coverage.

Design system controls: tightened accessibility for unlabeled controls, added real tooltip behavior and better truncation to toggles, reset transient interaction states on disable, added a disabled state to split buttons, and now enforce the same visible-label-or-semantics contract across chips, tabs, dropdowns, and split buttons.

Categories list redesign: new tile layout with colored icon badges, task count subtitles, favorite stars, and private/inactive status indicators. Batch query for better performance.

Voice-driven time tracking: the task agent can now create time tracking entries from voice dictation, supporting both completed sessions with start/end times and running timers. Entries require user approval before being applied.

Removed the prompt tab and prompt editing page from AI settings. Prompts are now managed internally.

Removed the entire tag concept (generic, person, and story tags) along with all related UI, sync infrastructure, services, and repositories. Database tables left in place to avoid migrations.

Projects UI: full project management interface with create/detail pages, project picker for tasks, category integration, health header on tasks page, and project-based task filtering. Each project auto-creates an AI agent for analysis and reporting.

Projects feature flag: all project UI gated behind enableProjects config flag (default off). Expandable health header with project/task counts. Interactive status picker on project detail page.

Matrix sync catch-up: fixed two bugs that prevented cold-restart catch-up from paginating server history correctly, ensuring reliable message delivery after app restart.

Category AI defaults: categories can now define a default inference profile and agent template. New tasks inherit the profile for speech-to-text/image analysis, and get an agent auto-assigned that waits for content before activating.

Fixed: Notifications now properly honor the notification config flag. Previously, "tasks in progress" and general notifications were sent even when notifications were disabled.

Cover art skill: image generation now runs as a background skill via the unified skill pipeline, with fire-and-forget workflow that auto-imports the generated image and assigns it as task cover art.

Reference image selection: linked-task cover art images are now discovered automatically via bidirectional task graph traversal (with link icon overlay), and the selection limit has been increased from 3 to 5 images.

Cover art modal: stays open after triggering generation with Siri waveform progress animation; dismissible without stopping background generation.

Automatic image analysis: newly generated cover art images automatically trigger the image analysis skill, just like a manual photo drop.

Inference profiles: new "Thinking (High-End)" model slot for tasks where quality matters more than speed/cost (e.g. coding prompt generation). Falls back to the regular thinking model when not configured.

AI popup menu: skills now appear in a dedicated top section above legacy prompts, with two-section layout and profile-based skill triggering.

Automatic AI processing: only profile-driven automation runs automatically for audio transcription and image analysis. The legacy category-based automatic prompt fallback has been removed.

Category details UI: removed the "Automatic Prompts" configuration section. Existing data remains in the database for backward compatibility.

Skill inference status: SkillInferenceRunner now updates InferenceStatusController so the Siri waveform animation shows during skill-driven inference.

AI popup visibility: the AI assistant button now appears when either skills or legacy prompts are available for the current entity.

Preconfigured prompts: stopped seeding audio_transcription and audio_transcription_task_context legacy ASR prompts.

Sync catch-up: reconnect recovery is now timestamp-first. The client pages backward until the stored timestamp boundary is visible, then replays forward with bounded overlap instead of depending on exact event-id re-anchoring.

Sync markers: local lotti-... echo ids are no longer persisted as durable remote read-marker ids. Server-assigned Matrix event ids are still kept for remote marker state, while timestamp progress remains the canonical local catch-up anchor.

Sync pagination: timestamp-first catch-up now keeps paging even without a stored durable event id, and Matrix history requests now honor the configured page size instead of silently using the SDK default page size of 30.

Sync recovery: automatic backfill now waits until an ordered replay batch settles, and startup keeps live scans deferred while timestamp-boundary catch-up is still incomplete. This cuts redundant repair chatter for offline reconnect bursts.

Database diagnostics: all Drift-backed databases now log slow queries into daily slow_queries-YYYY-MM-DD.log files when the logging domain is enabled.

Database indexes: new dedicated indexes for task due-dates, date-sorted task lists, journal browse, definition lists, linked-entry lookups, sync sequence scans, outbox queue scans, and agent database queries. Index-adding migrations now safely recreate existing indexes.

Journal query improvements: common browse queries use simplified fast-path SQL, task filters use EXISTS predicates instead of CASE branches, linked-child lookups use direct joins, and all-starred/all-private paths bypass redundant filters. Empty selections short-circuit before hitting SQLite, and bulk id-based fetches use an unsorted path when order is not needed.

Task progress: task-card progress lookups now batch estimates and linked work time spans across visible task IDs through lightweight queries instead of loading full entities.

Settings database: reads and writes now use a direct Drift executor instead of a background-isolate hop, and same-value saves return early. Settings-key lookups are cached in-process with concurrent cold reads coalesced.

Config flags: JournalDb keeps a shared in-memory config-flag snapshot so per-flag consumers no longer re-query SQLite after bootstrap. Startup listeners watch only the flags they need.

AI configs: type-based config watchers derive from a shared in-memory snapshot instead of re-querying ai_config.sqlite, and label-definition visibility checks use explicit private-status filters.

Daily OS: the unified day view now ignores unrelated database notifications instead of reloading its full bundle on every update.

Sync inbox: replay of the exact same attachment event no longer re-runs attachment observe/download/write work unless the local file is missing or empty, reducing unnecessary agent payload I/O during catch-up.

Sync logging: sync-family info logs now go to the dedicated sync daily log instead of inflating the general app log, while sync errors remain visible in both places.

Sync diagnostics: receiver-side signal logging now emits catch-up and live-scan summaries with source breakdowns instead of one log line per raw scheduler callback.

Sync backfill follow-up: re-request paging now walks past already queued oldest rows, in-flight backfill requests suppress duplicates, and zombie-file cleanup only deletes files that resolve inside the local docs directory.

Sync reliability: marker-missing catch-up no longer replays a bounded recent tail as successful backlog. Host progress now stays on the highest contiguous resolved counter, large gaps are fully materialized for backfill, and newly detected missing work nudges automatic backfill immediately.

Sync convergence: reconnect catch-up now keeps paging until it either finds the stored Matrix marker or reaches the stored timestamp boundary, then replays that ordered historical slice instead of turning an ordinary offline backlog into redundant backfill requests.

Agent sync startup: when agents are enabled, app startup now keeps agent initialization alive so incoming agent backfill can resolve before any entry or agent screen is opened.

UI polish: replaced the intrusive automatic rating modal with a pulsating star icon button next to the timer. Fixed provider state mutation during build, RenderFlex overflow, and realtime transcription stop race condition. Removed the label assignment snackbar (now redundant with change sets).

New task filter: filter by agent assignment (All / Has Agent / No Agent) in the Task Filter Modal. Quickly find tasks that still need an agent assigned. Zero performance overhead when the filter is in its default state.

Sync fixes: exact backfill hits are now validated against the payload's current vector clock before resend, preventing stale exact mappings from resending a payload and then declaring the same counter unresolvable. When the stored sync marker cannot be found, catch-up now falls back to a bounded recent tail instead of replaying the entire visible room snapshot.

Removed legacy checklist updates and task summary system — conversation-based processing replaced by agent system. New TaskSummaryResolver with unified fallback logic. Agent report selection now picks the most recently assigned agent. Recorder no longer blocks on transcription inference.

Local inference fixes: conversation headers now show the actual model name during and after runs. Tool call counts are accurate for all tool types. Resilient JSON parsing for local models. Token usage recorded for Ollama. Prevented tool repetition loops — non-batch deferred tools can only be called once per wake, with guided responses listing remaining tools. Raised default max turns from 5 to 10.

Fixed macOS crash on quit: use POSIX _exit(0) via FFI instead of Dart exit(0) to prevent VM teardown racing with native threads (mpv, SQLite). Explicitly dispose media_kit Player before exiting. Added 35 new category icons. Polished the icon picker with Material 3 styling. Fixed change set UI stability, label assignment rate limiter, follow-up task handler, and database UNIQUE constraint crash.

Qwen 3.5 local inference: added 9B and 27B models via Ollama with native multimodal, reasoning, and tool calling. New "Local Power" profile for higher-end devices. Updated default local profile to Qwen 3.5 9B. Removed superseded local models. Fixed Ollama streaming tool call index bug that merged multiple tool calls into one. Added automatic model backfill and profile drift detection on startup.

Fixed macOS crash on close: skip SQLite database close entirely before exit(0) to avoid SIGABRT in sqlite3_close_v2 during VM teardown. SQLite WAL mode ensures data integrity without explicit close.

Task agent follow-up task creation with deferred confirmation. Fixed checklist migration placeholder resolution, copy-before-archive ordering, and cascade rejection of dependent items. Added structured domain logging for production diagnostics.

Vector search distance telemetry: search result cards now show a color-coded cosine distance badge during vector search mode, and distance distribution is logged for threshold calibration.

Fixed sync backfill: agent entities and links are now included in sequence log population. Added self-request guard to prevent hot-loop. New "Reset Unresolvable" action recovers stuck entries. Host activity cache improves sync performance.

Agent-proposed labels are now individually confirmable or rejectable instead of all-or-nothing. Rejecting a label automatically suppresses it so the agent will not re-propose it.

Added an ObjectBox-backed embedding store POC for approximate nearest-neighbor search.

Switched the current vector backend toggle to the ObjectBox path for macOS benchmarking, including the required sandboxed macOS app-group configuration.

Unified embedding generation: select multiple categories at once with a Select All toggle. Vector search is now available on the journal tab alongside tasks. Removed the separate "Re-index All Embeddings" action.

Refactored the embedding pipeline behind a backend-neutral store interface to prepare alternate vector backends without another large call-site migration.

Fixed embedding backfill failing for entries with code, URLs, or long unpunctuated text by lowering the chunk target to 256 tokens for safer headroom against the model's 512-token context window.

Sequence log backfill now includes agent entities and agent links alongside journal entries and entry links, closing sync gaps for agent data.

Fix duplicate checklist suggestions: the AI task agent no longer repeatedly proposes items that already exist on the task, were previously confirmed, or were explicitly rejected. Pending proposals are now included in the agent's LLM context to prevent re-proposing items already queued for review.

Add one-time backfill of vector clocks on agent entities and links via the Sync Maintenance modal, enabling cross-device sync for records created before the clock-stamping fix.

Fix cross-device agent sync: task agent provider now reacts to sync notifications so agents appear on other devices without restart. Maintenance re-sync now includes agent entities and links within the selected date range. Removed unused collapsible section from linked entries UI.

Sync stability fixes: break backfill amplification loop by responding with hints instead of unresolvable flags for superseded counters. Agent entities and links now properly record vector clock counters in the sequence log, eliminating phantom gaps that triggered endless backfill requests and outbox spikes.

Overlapping document chunking for vector search: long transcripts and agent reports are split into overlapping chunks so every part is semantically searchable. New Re-index All maintenance action rebuilds embeddings with the improved chunking strategy.

Enhanced agent observations with priority and category fields. Task agents can flag critical grievances and excellence notes for self-correction across wakes and prominent surfacing in 1-on-1 ritual sessions. New high-priority feedback GenUI card renders grievances and excellence notes inline in evolution chat.

Outbox priority queue: user-initiated actions now sync before bulk operations during large resyncs. Three priority levels (high/normal/low) ensure responsive UX. Sync health reporter logs periodic outbox and sequence counters when domain logging is enabled.

Simplified audio recording modal: removed Checklist Updates and Task Summary checkboxes. These prompts now always use category defaults when configured. New system setup no longer populates these automatic prompts on categories. Removed automatic task summary infrastructure (scheduled refreshes, smart triggers, countdown UI); summaries are now agent-managed on demand.

Agent template settings UX: sticky 1-on-1 review button in bottom bar when form is clean, Save/Cancel only when dirty. Full-height directive text areas, clearer profile selector label, and delete action moved to Stats tab. Restored the 1-on-1 review chat FAB so the interactive conversation is always reachable from the review page.

Voice transcription in evolution chat: mic button with batch and realtime recording modes. Transcript populates the text field for editing before sending.

Vector search testing UI: toggle between full-text and vector search on the tasks page with timing feedback. Controlled by a feature flag.

Split agent template directives into separate general and report directive fields for cleaner evolution. Agent reports now support a structured TLDR field shown in collapsed view with full report expandable below.

Meta-improver agent: recursive self-improvement layer that evaluates and improves template-improver agents. Runs monthly rituals focused on improver effectiveness, directive churn, acceptance rates, and session trends. Includes evolution session feedback extraction, directive churn detection, and recursion depth policy enforcement (capped at depth 2).

Agent no longer proposes redundant changes that match the current state. Checklist items, estimates, priorities, due dates, statuses, and titles are filtered at proposal time with corrective feedback to the LLM. Cross-device sync of confirmed/rejected change sets now works reliably.

Inference Profiles: named configuration bundles grouping model assignments per capability slot. Profiles replace direct model references on agent templates and instances. Includes profile management UI, two-page agent creation modal, and six seeded default profiles.

Agent now learns from past user decisions: confirmed, rejected, and deferred proposals are fed back into the wake context, so the agent avoids repeating rejected suggestions and builds on confirmed preferences. Also fixed redundant label assignment proposals for tasks that already have 3 or more labels.

Agent sync now uses file-attachment pattern (same as journal entities), preventing failures when agent payloads exceed Matrix's 60KB text event limit. Existing inline messages remain backward-compatible.

Domain-specific logging with PII-safe sanitization and per-domain toggles in Settings > Advanced > Logging Domains. Defensive fixes for agent wake orchestrator reliability. Agent UI refinements: Beamer-native back navigation, responsive token usage table, improved report controls with countdown timer.

Checklist user sovereignty: track who last toggled each checklist item (user or agent) and prevent the AI agent from overriding user-set states without a substantive reason citing post-dated evidence.

Aggregate token usage tracking per template with tabbed detail page (Settings / Stats / Reports) showing per-model summaries across all instances and per-instance breakdowns with lifecycle badges.

Added token usage section on agent detail page showing aggregated input, output, thinking, and cached token counts per model with grand totals.

Added bulk-delete button for old AI task summaries with a confirmation dialog showing the count of summaries to be deleted.

Task-agent linked task context now uses latest linked task-agent reports instead of legacy summaries. Persisted throttle-state refresh now routes through update notifications, and MTTR chart loading de-duplicates linked task lookups with concurrent resolution.

Settings > Agents page with Templates and Instances tabs, kind and lifecycle filters. Expandable TLDR agent report on task detail page. Agent default model changed to Gemini 3 Flash. Report format aligned with task summary structure.

Alibaba Cloud (Qwen) as AI inference provider with 5 models including text, vision, reasoning, audio, and image generation variants via DashScope API. Qwen3 Omni Flash for audio transcription.

Outbox payload size tracking: records total payload size (JSON message + file attachment bytes) for each outbox item, displays size in the outbox monitor, adds daily volume aggregation for sync analytics, and visualizes 30-day outbox throughput in a bar chart.

Fix task agent automatic trigger broken after throttle optimization: fixed deferred drain silently dropping when deadline expired, added safety-net periodic timer for stuck queue recovery, and fixed startup hydration race cancelling deferred drain timers. Fix agent template model selection not persisted when editing.

Evolution chat: multi-turn GenUI conversation for reviewing agent template performance and approving rewritten directives. Evolution dashboard with mini charts (success rate, wake history, version performance, MTTR trend). MTTR now measures true task resolution time. Labels in agent reports. Fix assign_task_labels crash and countdown timer digit jitter.

Agent tools for task language, status, and label assignment. Correction examples and label context injection into agent prompts. Defer-first 120s throttle for bursty edit coalescing. Standardized report structure. ASR re-trigger for parent task notification.

Agent throttle gate: 5-minute cooldown between automatic agent wakes to reduce token consumption during rapid task mutations. "Run Now" button and countdown timer on task agent chip. Throttle deadline persists across app restarts.

Fix reference image selection not rendering in cover art generation modal.

Agent templates: full-stack feature for reusable agent templates with database, service, state, and UI layers. Template evolution workflow with LLM-assisted 1-on-1 review of performance metrics and directive rewriting. Inference provider resolver and settings navigation for templates.

Provider filter for category prompt selection. Collapsible text entries in linked-entry context. Agent cross-device sync via Matrix with zone-based transaction isolation. Desktop crash-on-exit fix via graceful service disposal. Reference image grid overflow fix.

Agent cross-device sync via Matrix. Agent entities and links synchronize across devices with wake subscription restoration. Sync maintenance UI supports agent re-sync steps. Zone-based transaction isolation buffers outbox messages until commit, with nested transaction and rollback support.

Agent running-state feedback with reactive spinner indicators on task page and agent detail page. Tool call arguments and results now persisted and viewable in expandable activity log cards. Conversation view groups messages by wake cycle. Post-execution drain timer ensures signals during execution are not lost.

Task Agent: persistent AI agents that maintain task summary reports and perform incremental metadata updates via tool calls (estimates, due dates, priorities, checklist items, titles). Gated behind feature flag with dedicated agent database, wake orchestration, fail-closed category enforcement, and agent detail inspection page with activity log and lifecycle controls.

Real-Time Transcription: Live transcription via Mistral Voxtral WebSocket API with ~2s latency, showing subtitles as you speak. Mode toggle in both AI chat and journal audio recorder. Native WAV-to-M4A conversion on iOS and macOS.

Checklist Layout & AI Context: Swipe backgrounds now extend edge-to-edge for a polished look. Archived checklist items are now properly marked in AI prompts, so the AI understands they are not active work.

Archive Swipe Gesture: Swipe right on checklist items to archive them, preserving historical context without marking as completed. Archived items are excluded from completion metrics and hidden in Open filter mode. Swipe left to delete (unchanged).

Flutter 3.41.1 Upgrade: Upgraded to Flutter 3.41.1 (Dart 3.11.0).

WAL Mode & Read Pools: Enabled SQLite WAL mode, busy_timeout (5s), and synchronous=NORMAL for all databases, preventing lock errors during multi-isolate access. Added a read pool of 4 isolates to JournalDb for offloading heavy reads. Added background and directory provider parameters to database constructors, preparing for actor-based sync.

Sync Throughput: Removed artificial 200ms per-message delay from outbox enqueueing and reduced idle threshold from 3s to 1.2s, so sync resumes sooner after user interaction.

Notification-Driven Streams: Replaced Drift table-watcher streams with notification-driven streams for all entity types, eliminating redundant DB polling and preparing for isolate-based sync. Fixed sync deserialization so unknown enum values from newer devices are logged and skipped instead of retried indefinitely. Fixed config flag init order, late-subscriber tag replay, and theming sync race condition during controller initialization.

Native M4A Audio: Removed M4A-to-WAV conversion for Mistral transcription. All providers now accept M4A natively, eliminating the FFmpeg dependency and file size quota issues. Updated Voxtral model to reflect Transcribe V2 capabilities (13 languages, up to 1 GB / 3 hours per file).

Sync Verification Follow-up: SAS emoji verification now updates reliably on both devices, refreshes device keys on completion, and triggers a sync rescan so synchronization resumes immediately without restarting apps. Post-verification trust status now refreshes automatically for a short window so stale "unverified device" indicators clear without manual refresh, and desktop provisioning auto-advances from the QR step to the final status page once trust state is updated. The legacy manual Matrix setup wizard has been removed from Settings; provisioning is now the single onboarding path while keeping emoji/SAS verification in the provisioned flow. Disconnect now shows an explicit confirmation dialog and closes the status modal after successful deletion. Logging performance has also been improved by batching routine log file writes instead of forcing a disk flush for every line.

Matrix Provisioning Wizard: New sync onboarding flow that lets a desktop device paste or scan a Base64-encoded provisioning bundle, log in, join the sync room, rotate the password, and display a QR code with updated credentials for a mobile device to scan and complete setup. Also includes flexible ratings model improvements where session ratings are now driven by a catalog registry instead of hardcoded questions. Sync room creation now enforces encryption in the initial createRoom request and names rooms with the creating username for easier administration.

DailyOS Migration and Navigation Fixes: The old Calendar tab has been removed and replaced by the DailyOS tab. The classic calendar day view has been removed and the /calendar route now always opens DailyOS. Tapping a time recording no longer navigates to a session rating instead of the parent task. Session ratings and timer entries now inherit their parent task's category, and the old calendar/DailyOS feature toggles were replaced with a single DailyOS page flag.

Task Time Fix: When multiple linked entries overlap in time (for example a gym trip that contains a fitness workout), the task progress view previously summed their durations independently, inflating the displayed time. It now merges overlapping time ranges into their union — the same algorithm that already powers the accurate Time Budget view — so task progress and budget views show consistent, correct durations.

Collapsible Linked Entries: Image and audio entries linked to a task can now be individually collapsed and expanded. When collapsed, a compact preview shows a thumbnail or mic icon with duration alongside the date for quick identification without scrolling past large media. The "Linked Entries" section header also collapses the entire section with a smooth animated transition. Collapse state is saved per link and synced across devices.

Session Ratings: When you stop a timer that ran for at least one minute, Lotti can now prompt you with a quick rating modal to capture how productive, energized, and focused the session felt, plus a challenge-skill balance check. Ratings are persisted as journal entities linked to the time entry with full sync support. The feature is behind a new "Enable Session Ratings" toggle in Settings, disabled by default.

Czech Language Support: Lotti is now available in Czech (čeština) with full coverage of all ~1360 UI strings. Platform locale declarations for iOS, macOS, and Windows have also been updated to include all supported languages (Czech, Spanish, French) that were previously missing from the native manifests.

AI Prompt Optimization: Single-speaker audio transcriptions no longer include an unnecessary "Speaker 1:" prefix - speaker labels now only appear when multiple voices are detected. Checklist generation is now snappy regardless of the AI model: when models like Gemini Flash split items across multiple function calls, they are coalesced into a single batch write for instant UI updates instead of incremental per-item rendering. Image analysis now returns URLs as proper Markdown links and automatically infers https:// when the browser hides the protocol.

Automatic Image Analysis Fix: Images imported via the photo library or camera roll now correctly trigger automatic AI image analysis when configured on the category. Previously, only clipboard paste and drag-and-drop imports triggered analysis, requiring users to manually open each imported image. Screenshots also now trigger automatic analysis.

Gamey Design System: A brand-new vibrant visual theme that transforms the app with playful gradients, glow effects, and animations. The Gamey theme includes a full color palette with feature-specific colors, a gradient system with reward tiers (gold/silver/bronze) and neon effects, glow effects at multiple intensity levels, and spring-based animation utilities. A complete set of themed widgets - cards, FAB, settings cards, icon badges, progress bars - all adapt automatically when the Gamey theme is active. The existing theme infrastructure is untouched; the Gamey theme layers on top via GameyThemeBuilder.apply().

Bug Fixes: Fixed double-tap on Gamey FAB, proper dropdown behavior in theme selection, localized task status labels, correct parameter passing in settings cards, and reliable animation state handling.

Cover Art Reference Images: When generating AI cover art for a task, you can now select up to 3 images linked to that task as visual references. The AI uses these images to match the color palette, lighting mood, aesthetic, and materials in the generated cover art. For example, if your woodworking task has photos of your project, the generated cover art will incorporate those textures and atmosphere. A new selection step appears before generation - tap images to select them, or skip to generate without references. If a task has no linked images, this step is automatically skipped.

Bug Fixes: Deleting an image that's used as task cover art now properly clears the reference. Button layout in the image generation modal no longer overflows on smaller screens.

Daily OS No-Budget Display: Categories without budgeted time now display a cleaner, more compact UI. Instead of showing redundant "0m / 0m" with "0m left" badge plus a separate warning line, categories with no budget now show a single right-aligned "No time budgeted" badge. When time has been tracked against an unbudgeted category, the display shows "Xm / 0m" alongside the badge instead of confusing negative remaining time. All status badges are now consistently right-aligned across budget cards for visual harmony.

Daily OS Timeline Drag-and-Drop: Planned time blocks can now be moved and resized with intuitive touch gestures. Long-press a block to enter drag mode - drag the body to reschedule the entire block, or drag the top/bottom edges to adjust start/end times. Blocks stay within their visible timeline section and snap to a 5-minute grid. Small blocks use move-only mode to avoid cramped resize handles. Visual feedback includes elevated styling, real-time time labels, and duration indicators. Blocks overlapping compressed regions must be expanded first before dragging.

Audio Transcription Speaker Fix: When transcribing recordings with multiple speakers, the AI no longer hallucinates speaker names. Previously, the model might guess identities like "John:" or "Sarah:" based on voice characteristics or training data. Now speakers are correctly labeled as "Speaker 1:", "Speaker 2:", etc. The speech dictionary is used strictly for spelling corrections of domain-specific terms, not for identifying who is speaking.

Daily OS Header Visual Refinements: The time history header now has a cleaner, more polished design. The selected day indicator compactly wraps just the weekday abbreviation and day number instead of extending down over the stream chart. Weekend days use the same compact styling for visual consistency. Vertical dividers between days have been removed for a cleaner look, and the chart is better positioned below the day labels. Selection boxes are wider for improved touch targets and visual balance.

Daily OS Quick Task Creation: Each time budget row now has a "+" button that instantly creates a task with the category pre-assigned and due date set to the selected day. Tap the button and you're taken directly to the task detail screen for immediate editing. This reduces friction when planning tasks during your daily review - no need to navigate to the tasks screen, create a task, then assign a category and due date separately.

Daily OS Time History Header: A new horizontally scrollable header replaces the arrow-based day navigation. Tap through days to see a timeline of your productivity, with a sticky month label showing the visible months and selectable day segments with visual selection highlighting. The header supports infinite scroll to load more history (14 days at a time) and includes a Today button for quick navigation back to the current day. Day labels and budget status indicators are visible at a glance. Performance improvements avoid full stacked-height recomputation on each history load unless the scale changes. The stream chart now scales to the maximum daily total with a 6-hour minimum.

Daily OS Timeline Past Task Indicators: Tasks completed on a different day than the one you're viewing now show a faded checkmark (45% opacity) instead of a hollow circle. This makes it clear at a glance whether a task was completed on the viewed day (full checkmark) or later (faded checkmark). Also removes the italic text styling for completed tasks and now shows P2 (Medium) priority badges alongside all other priorities.

Daily OS Time Budgets UI Redesign: Slim two-row header design takes up significantly less vertical space. The first row shows category name with a circular task completion indicator and expand/collapse toggle. The second row displays time recorded vs planned, a fixed-width progress bar (now using consistent green/red colors instead of category colors), and status text. Progress bars align in columns for a cleaner table-like appearance.

Focus Mode Auto-Collapse: When you're inside a planned time block, the matching category's budget card stays expanded while other categories automatically collapse. This helps you focus on the current activity without manual toggling. You can still manually expand or collapse any category as needed.

Bug Fixes: Fixed a Riverpod state management issue in the focus mode provider that could cause stale data. Added proper error handling when refreshing budget data after a timer stops.

Voice Task Priority: Set task priority via voice during audio recordings. Say things like "priority P1", "this is urgent", or "low priority task" and the AI updates your task priority automatically. Maps spoken terms to priority levels (urgent/critical→P0, high/important→P1, medium/normal→P2, low/minor→P3). Only sets priority when not already explicitly set, preserving your manual edits.

Daily OS Timeline: Double-tap planned blocks to edit start/end times. This provides a more intuitive alternative to the existing long-press gesture, opening the same edit modal for adjusting time range, category, and notes.

Daily OS Smart Timeline Folding: The timeline now intelligently compresses inactive periods to reduce vertical scrolling. Gaps larger than 4 hours between entry clusters are automatically folded, displaying at 8px per hour instead of 40px with a distinctive zigzag edge pattern. Tap any compressed region to expand it. Hours before 6 AM and after 10 PM are folded by default when empty, and a 1-hour buffer around each entry keeps context visible. Days with sparse activity see up to 60% less scrolling.

Daily OS Overlap Fix: Time entries within the same category no longer double-count when they overlap. For example, a 1.5-hour "Gym Trip" containing a 45-minute "Fitness Entry" now correctly reports 1.5 hours total instead of 2.25 hours. Uses a time range union algorithm to calculate actual time coverage.

Visual Nesting: Same-category entries that fully contain another now nest visually in the timeline. Child entries render inset inside their parent block, reducing visual clutter. Different-category overlapping entries still display in separate lanes.

Daily OS Priority System: Tasks now display Linear-style priority badges (P0 red, P1 orange, P3 gray) in both list and grid views. P2 (Medium) is hidden to reduce visual noise. Tasks without tracked time are sorted by priority first (P0→P1→P2→P3), then by urgency, then alphabetically.

Future Date Filtering: When viewing a future date, only tasks specifically due on that day are shown. Overdue tasks no longer clutter future planning views - they remain visible on today's view for review and rescheduling.

Timeline Improvements: Entry heights now accurately reflect their actual duration based on calendar scaling (removed artificial 20dp minimum).

Daily OS Due Task Visibility: Time budget cards now show tasks that are due today or overdue, even if you haven't tracked any time on them yet. This ensures important deadlines don't fall through the cracks. Due tasks display visual badges indicating urgency - red for overdue items and orange for tasks due today. Categories with due tasks but no planned time budget show a warning banner prompting you to allocate time. Tasks are intelligently sorted with tracked-time tasks first, then due tasks by urgency.

View Preference Persistence: Your preferred task view mode (list or grid) is now saved per category and persists across app restarts. The default view has changed from grid to list for better readability of task details and due date badges.

Daily OS Task Visualization: Time budget cards now show which tasks contributed time to each category. Each task displays its time spent and completion status (checkmark for tasks completed today). Switch between grid view with task thumbnails and compact list view using the toggle button. The collapsible task section header shows the total task count and combined time. Tasks are sorted by time spent with zero-time completed tasks at the end.

Daily OS Timeline Overlap Handling: Overlapping time entries now display in separate visual lanes instead of stacking on top of each other. Uses a greedy lane assignment algorithm that places non-overlapping entries in the same lane for full-width display, while overlapping entries get their own adjacent lanes with equal widths and a small gap for visual separation. Useful when tracking multiple concurrent activities like a meeting while taking notes.

Daily OS Architecture Refactor: Unified data controller for consistent real-time updates. Consolidated day plan, timeline data, and budget progress into a single atomic state that updates together when any underlying data changes. Uses ref.keepAlive() with a manual StreamSubscription to prevent Riverpod 3's automatic pausing behavior. Fixes the auto-update failure where the timeline and budget progress bars wouldn't refresh when time entries were created or synced.

Day Plan Timeline Fix: Fixed a crash that occurred when calendar entries crossed midnight (e.g., a work session starting at 23:00 and ending at 01:00 the next day). The timeline view now correctly handles overnight entries by treating them as ending at midnight for display purposes. Added defensive bounds checking to prevent the RangeError that caused blank/grey screens on days with late-night entries.

Daily Operating System: New time management feature for planning and tracking your day. (WIP)

Task Time Tracking Fix: Audio recording duration no longer counts toward time spent on tasks. This prevents double-counting when recording meetings (e.g., a 1-hour meeting recording would previously add 1 hour to task progress, even if you also logged a 1-hour time entry for the same meeting). Only actual logged work entries now contribute to task progress calculations.

Localization: Added missing translations to German, Spanish, French, and Romanian localization files.

OpenAI Onboarding FTUE: Added first-time user experience for OpenAI providers with one-click setup. Automatically creates 4 models (GPT-5.2 for reasoning, GPT-5 Nano for fast tasks, GPT-4o Transcribe for audio, and GPT Image 1.5 for image generation), configures 9 optimized prompts with appropriate model assignments, and creates a test category with all prompts enabled. Follows the same streamlined pattern as Gemini FTUE.

Audio Format Simplification: M4A audio files are now sent directly to most providers labeled as mp3, reducing processing overhead. Only Mistral requires actual WAV conversion.

Code Modularity Refactor: Extracted focused services from large modules for better testability and maintainability. MetadataService handles metadata creation with vector clock integration. GeolocationService manages geolocation addition with race condition prevention. ExifDataExtractor provides pure functions for EXIF timestamp and GPS coordinate extraction. AudioMetadataExtractor handles audio file metadata parsing and duration extraction. Media import is now separated into audio_import, media_import, and image_import with single responsibilities each.

Voxtral Token Streaming: Upgraded local Voxtral transcription from chunk-level to true token-by-token streaming. Text now appears progressively as it's generated instead of waiting for full 60-second chunks to complete. Tokens are batched in groups of 6 for smooth display without excessive network overhead. The streaming behavior is configurable via Settings → Flags. Non-streaming mode is available for approximately 20% faster processing when real-time progress display isn't needed.

Mistral Cloud Provider: Added a new cloud transcription option using Mistral's Voxtral API. Supports the voxtral-small-2507 model for high-accuracy cloud transcription with automatic audio format conversion from M4A to WAV for API compatibility. Uses FFmpegKit on iOS/Android/macOS and system FFmpeg on Linux/Windows. The Voxtral model is auto-created when adding a Mistral provider.

Audio Transcription Improvements: Improved context handling to prevent previous transcripts from bleeding into new ones. Now uses task summary instead of full task JSON for cleaner context. Added explicit instructions that context is for terminology only. Transcriptions now include paragraph breaks on small pauses or topic changes for better readability.

Voxtral Streaming Transcription: Audio transcription now streams progressively as each 60-second chunk completes. Each chunk's transcription is sent as a Server-Sent Event (SSE), providing real-time visual feedback instead of waiting for the entire audio to process. Particularly useful for longer recordings where you can see progress as it happens. AI streaming responses are now enabled by default for new installations - existing users can enable this in Settings → Flags.

Voxtral Local Transcription: Added a new local AI transcription service using Mistral's Voxtral model. Supports up to 30 minutes of audio transcription (compared to 5 minutes for Gemma 3N) with 9 languages and automatic language detection. Features context-aware transcription with speech dictionary support for improved accuracy on technical terms and proper nouns. Two model options available: Voxtral Mini 3B (~9.5GB VRAM) for local/edge deployment and Voxtral Small 24B (~55GB VRAM) for higher accuracy. Runs locally on Apple Silicon (MPS) or NVIDIA GPUs (CUDA) with full privacy - no data leaves your device.

Gemini Setup Dialog Reset Fix: Fixed the reset functionality not working properly. Migrated storage from SharedPreferences to SettingsDb (SQLite) for improved reliability. The reset now takes effect immediately without requiring an app restart. Also localized the reset dialog strings for internationalization support.

What's New Modal Improvements: Added a "Done" button on the last page for clearer completion flow. The "Skip" button is now hidden on the last page, replaced with "Done" on the right. Button labels now use proper localization (l10n) for internationalization support.

Cover Art Display: Reverted to BoxFit.cover for better display on mobile devices.

Dialog Stability Fix: Fixed Gemini setup dialogs disappearing when resizing the app window. Both the Gemini setup prompt modal and FTUE setup dialog now survive widget tree rebuilds during window resize.

Task Estimate Fix: Fixed the task estimate field not appearing on Linux and fresh installs. The estimate chip was incorrectly hidden when no labels were defined in the app. Now the estimate and "Add Label" controls always appear, regardless of whether any labels exist.

Gemini FTUE Streamlined: Simplified the first-time user experience by reducing default prompts from 18 to 9 with optimized model assignments. Gemini Pro handles complex reasoning tasks (Checklists, Coding Prompts, Image Prompts), Gemini Flash handles fast processing (Audio Transcription, Task Summary, Image Analysis), and Nano Banana Pro handles Cover Art generation with reasoning mode enabled for reliable image output. The Gemini Setup Modal is now dismissible by tapping outside for a temporary skip - it will reappear on next app start, while "Don't Show Again" still permanently dismisses it.

Flatpak Fixes: Resolved several console warnings in the Flatpak version. Fixed keyring access error by adding D-Bus permission for org.freedesktop.secrets, enabling secure storage to work properly. Fixed cursor theme warning by exposing host cursor theme paths. Removed invalid fontconfig overrides that caused "Cannot load default config file" errors. Added Flatpak-specific icon path to eliminate application icon warnings.

Cover Art Fixes: Fixed image cropping on mobile where sides were cut off - now displays full 16:9 cover art without side cropping. Also fixed cover art set/unset not persisting after database sync. The vector clock counter could fall behind synced data, causing updates to be silently rejected. Added auto-catch-up logic that detects stale counters and recovers automatically.

Voice-Controlled Task Properties: Set time estimates and due dates via voice during audio recordings. Say things like "this will take about 2 hours" or "due by Friday" and the AI will update your task properties automatically. Converts natural language durations to task estimates and resolves relative dates to absolute due dates. Only sets values when not already set, preserving your manual edits.

Gemini Quick Start: Automatic setup prompt for new users without AI providers configured. Modal appears after What's New is dismissed (no overlapping dialogs). One-click Gemini setup with pre-configured models and prompts. Explains available AI features including audio transcription, image analysis, smart checklists, and task summaries. "Don't Show Again" option persists dismissal permanently. Also notes that other providers like Ollama for local inference are available in Settings.

Upgraded to Flutter 3.38.6.

What's New Modal: Editorial magazine-style release notes viewer. Features 21:9 hero banner images with glassmorphism version badges, multi-release navigation with animated indicator dots, and smart "seen" tracking that only marks releases you actually viewed. Includes version filtering to only show releases matching or older than your installed app version, image precaching for smooth transitions, "Skip" button to dismiss all releases, and "View past releases" option to review previous updates. Responsive design adapts to bottom sheet on mobile or centered dialog on desktop.

Linked Tasks Section: New dedicated UI for viewing and managing task-to-task relationships. Features bidirectional link display with directional indicators (↳ LINKED FROM, ↗ LINKED TO), minimal Linear-style text links with status circles, searchable "Link existing task" modal powered by FTS5, "Create new linked task" for quick subtask creation, and "Manage links" mode for unlinking. Tasks are filtered out from the generic Linked Entries section to avoid duplication.

Calendar Auto-Refresh Fix: Fixed calendar not updating when returning from creating a time recording. Improved visibility change handling to track transitions from invisible to visible, triggering full provider rebuild only when needed. More efficient than the previous onResume approach with zero CPU overhead when staying on the calendar page.

Scroll Performance Optimizations: Significant improvements to reduce jank during scrolling. Added cacheExtent to key scrollable views (Entry Details, Tasks List), converted Labels Modal to sliver-based lazy loading architecture, and added RepaintBoundary isolation for task cards, linked entries, and checklist items. Fixed memory leaks in editor widgets where ScrollControllers were being recreated on every build. These optimizations target smooth 60/120fps scrolling, especially beneficial for tasks with many checklist items.

High CPU Usage Fix (#2578): Resolved infinite rebuild loop in calendar controllers causing 160%+ CPU usage when idle. Removed ref.onResume with invalidateSelf pattern which created a rebuild cycle. Calendar updates are handled correctly by existing visibility and stream listeners.

Entry Actions Menu Redesign: Restyled to match the FAB addition menu with Nano Banana Pro styling. Features unified list design with subtle horizontal dividers (removed card-based layout), clean icons without gradient containers, and consistent visual language across all modal menus.

Calendar View Stale Data Fix: Fixed calendar not updating after adding or modifying entries. Root cause was Riverpod 3's auto-pause feature pausing providers when widgets are not visible. Added ref.onResume() callbacks to calendar providers that invalidate themselves when resuming, ensuring fresh data is always fetched when returning to the calendar view.

FAB Addition Menu Redesign: Modernized the add entry bottom sheet with Nano Banana Pro styling. Features unified dark background (no separate cards), clean white icons without gradient containers, subtle horizontal dividers between items, and edge-to-edge tap effects. Also fixed missing API Key field for OpenAI Compatible provider type (#2570) - authentication section now displays correctly for remote OpenAI-compatible endpoints.

AI Cover Art Generation: Generate task cover art directly from audio descriptions using Gemini's Nano Banana Pro model. Trigger from audio entry action menu when linked to a task. Full task context (title, checklists, labels, summaries) included in prompt. Review modal with accept, edit, and regenerate options. Cover art display updated to 16:9 aspect ratio at full resolution for consistency with generated images.

Cross-Checklist Drag-and-Drop Fix: Restored ability to move items between checklists. Fixed regression from checklist redesign where drag gestures were being intercepted. Now uses unified drag system with item-level drop regions for position-aware drops, enabling both within-list reordering and cross-checklist moves via long-press.

Nano Banana Checklist Redesign: Major UI rewrite with card-based architecture. Features modular widget structure, animated chevron rotation, filter tabs with underline indicator, and three display modes (expanded, collapsed, sorting). Progress ring now hidden when empty in expanded mode. Add input moved to bottom of checklist body with click-to-edit title functionality.

Image Card Thumbnails: Now display as uniform squares with center crop for consistent visual presentation. Portrait images are cropped from vertical center, landscape images from horizontal center. Also updated Gemini AI models to latest versions.

Due Date Visibility Refinements: Improved UX for completed and rejected tasks. Due dates are now hidden on task cards for completed/rejected tasks since they're no longer relevant. In the entry details view, due dates show grayed-out styling instead of red/orange urgency colors for completed/rejected tasks.

Visual Mnemonics: Tasks can now have cover art images for memorable visual representation. Set any linked image as a task's cover art via the action menu. Features include cover art thumbnails on task cards (with filter toggle), a cinematic 2:1 collapsible SliverAppBar in task details, glass effect overlay buttons, and horizontal crop adjustment for positioning.

Riverpod 3 Migration: Upgraded to Riverpod 3.x with comprehensive codebase migration. Updated all providers to new syntax, added ref.mounted checks after async gaps, converted family providers to constructor-based parameters, and added ref.onDispose cleanup handlers. Fixed disposed ref access errors in autoDispose providers and checklist item resolution.

Task Due Dates: Tasks now support due date assignment with a date picker in the details header. Features include color-coded status indicators (red for overdue, orange for due today), due date display on task cards with filter toggle, and tappable text that toggles between absolute and relative date formats. Card layout updated with creation date on left, due date on right.

Habit Settings Fix: Fixed habit settings page opening empty for existing habits. Changed ref.watch() to ref.read() for habitByIdProvider in controller build to prevent rebuilds when stream data changes, preserving form state. Edit flow now loads cached habit data synchronously.

Habits Page State Refactor: Migrated habits page state management from Bloc to Riverpod. HabitsCubit replaced with HabitsController notifier using keepAlive for app-wide state persistence. Created Freezed-based HabitsState with chart calculation helpers. Updated HabitsTabPage, app bar, streaks, filter, search, and chart widgets to use Riverpod. Fixed search TextEditingController lifecycle and chart touch state handling.

Audio Player State Refactor: Migrated audio player state management from Bloc to Riverpod. AudioPlayerCubit replaced with AudioPlayerController notifier using keepAlive for app-wide state persistence. Updated AudioPlayerWidget to Consumer pattern and RecorderController to use ProviderContainer injection.

Habit Settings State Refactor: Migrated habit settings state management from Bloc to Riverpod. HabitSettingsCubit replaced with HabitSettingsController notifier using family provider pattern with habitId as key. Added habitByIdProvider and habitDashboardsProvider. Updated HabitDetailsPage, CreateHabitPage, and related widgets to use Riverpod providers.

Theming State Refactor: Migrated theming state management from Bloc to Riverpod. ThemingCubit replaced with ThemingController notifier and enableTooltipsProvider. Theme state now uses keepAlive for app-wide persistence. MyBeamerApp updated to ConsumerStatefulWidget pattern.

Sync Outbox State Refactor: Migrated sync outbox state management from Bloc to Riverpod. OutboxCubit replaced with outboxConnectionStateProvider and outboxPendingCountProvider. OutboxBadgeIcon now uses Riverpod providers for consistency with the codebase.

Task Sorting and Date Display: Tasks can now be sorted by date (newest first) or by priority using a new segmented button in the filter modal. Optionally display creation dates on task cards with a subtle bottom-right placement. Both preferences persist across sessions.

Dashboard State Refactor: Migrated dashboard list state from Bloc to Riverpod for consistency with the codebase. Dashboard filtering and sorting now uses dedicated Riverpod providers with case-insensitive sorting for better UX.

Labels for All Entry Types: Labels can now be assigned to any journal entry, not just tasks. Features include labels display on journal cards, edit capability in detail views, a new "Labels" action in the triple-dot menu, and a unified label selection modal with search and create functionality.

Twi Language Support: Added Twi (Akan) as a supported language for task summarization. Twi is spoken by approximately 9 million people in Ghana. Enables AI-generated task summaries in Twi with Ghana flag in the language selection UI.

Image Prompt Generation: New AI response type that transforms audio recordings and task context into detailed prompts for AI image generators like Midjourney, DALL-E 3, and Stable Diffusion. Features visual metaphor guidelines, multiple style options, and a convenient copy-to-clipboard button.

Task Summary Goal Section: AI task summaries now include a succinct Goal section after the TLDR. This 1-3 sentence description captures the desired outcome or essential purpose of the task, helping maintain focus on the "why" behind the work.

Single-User Multi-Device Sync: New room discovery feature allows Device B to find and join existing sync rooms without invitation. Includes confidence indicators, smart navigation, and bounded concurrency for faster discovery. Also fixes QR scanner restart after invite failures.

Calendar Privacy Filtering: Calendar view now respects category visibility settings from the Tasks page. Selected categories show colored boxes with text; unselected categories show colored boxes only (text hidden for privacy).

Checklist Correction UX: Corrections now use a delayed-save pattern with a cancel option. A 5-second countdown snackbar lets you discard accidental corrections before they're saved as AI learning examples.

Task Summary Link Extraction: AI summaries now include a Links section that automatically extracts and displays all URLs from task entries with succinct titles (e.g., "Linear: APP-123", "Lotti PR #456"). Links are deduplicated and formatted as clickable Markdown.

Upgraded to Flutter 3.38.5 with dependency updates. Sync refactoring: OutboxService.enqueueMessage() improved with Dart 3 pattern matching, extracted helper methods, and expanded test coverage (60 → 77 tests).

Gemini Thinking Support: All Gemini 2.5+ models (including Flash) now display AI reasoning in the Thoughts tab. Plus new usage statistics tracking shows token counts and processing duration for each AI response.

Sync: Live scans now process strictly after the last marker. The Matrix look-behind tail and its flag have been removed to eliminate redundant work.

Checklist Deletion Fix: Empty card containers no longer appear after deleting a checklist. The checklist ID is now properly removed from the parent task, and defensive UI filtering handles any existing stale references.

Sync Catch-Up Concurrency Fix: Prevents concurrent catch-up execution from multiple sources. External forceRescan calls now skip catch-up when an internal retry-driven catch-up is already in flight. Fixes timeout failures that occurred when connectivity triggers ran concurrently with scheduled catch-up retries.

Sync Catch-Up Fix: All catch-up paths now wait for the Matrix SDK to complete server sync before processing. Fixes issue where catch-up after extended offline periods would miss entries. Includes automatic follow-up for slow networks.

Sync Gap Detection Fix: Prevents false positive gap detection during reconnection. Covered vector clocks are now processed before gap detection, and live scan signals are deferred during catch-up to ensure in-order event processing.

Nested AI Responses: Generated prompts from audio entries now display directly beneath them in an expandable section. Includes smooth collapse/expand animation and swipe-to-delete with confirmation.

Sync Backfill Improvements: EntryLink support ensures all sync message types are tracked and can be recovered. Ghost missing entry resolution handles cases where different message types share the same sequence counter.

Add prompt type for creating prompts, for example for feeding into Claude Code, Codex and similar tools, or ChatGPT, Gemini, Claude in research mode.

Sync Backfill: Request missing journal entries from connected devices during sync to ensure complete synchronization across all your devices.

Automatically create Gemini prompts.

Multiple improvements and simplifications in Sync code.

Automatic Image Analysis: Drop, paste, or import images to a task and they're analyzed automatically. Smart Task Summaries: Your first task summary is created immediately when you add meaningful content (image analysis, audio transcription, or text). No more manual checkbox clicks—just work naturally and let the AI keep up.

Checklist Correction Examples: The AI now learns from your manual corrections. When you fix a checklist item title (like "test flight" to "TestFlight"), Lotti remembers and uses these examples to improve future AI suggestions for both checklist updates and audio transcription.

Speech Dictionary per Category: Teach the AI your domain-specific terms. Add names, places, and technical words to a category's dictionary, and transcriptions automatically use the correct spellings. Select misrecognized text and add corrections via the editor context menu.

Smarter AI checklist updates: Say "I did the shopping" and the AI marks the right item complete. Mention "fix the typo in iPhone" and it corrects transcription errors. The AI now understands what you mean, not just what you type.

Improved task search field width and layout for better use of available space.

Office ProjectManagement Calendar A task with its cover art, status, labels, and the assistant's summary https://raw.githubusercontent.com/matthiasn/lotti-docs/89d8e81b93711e3c41685e903349cc93d6ab5239/images/0.9.998/task_details_screenshot_linux.png