Changelog
v1.3.076
Added
- New boards start in a template gallery and setup wizard - and every board can be reshaped the same way later. "New board" now opens one unified dialog instead of a bare name input: pick from ten curated Truetask templates (Software project, Bug tracking, AI-assisted build, Project plan, Cross-functional launch, Goals & OKRs, New hire onboarding, Client CRM, Content calendar, Personal tasks), from templates shared with the workspace, or from your own - filtered by category chips and search - or start blank. Every tile draws a live structural miniature straight from the template's real lists and colors (kanban columns, timeline bars, calendar dots), so previews can never drift from what gets created and adapt to light and dark on their own. A short wizard follows: choose exactly which views the board is born with - all nine are on the menu now, Code and Automations included (Automations stays admin-gated at render, and Code opens into its guided setup until a repo is linked) - pick the view it opens in, then name it, give it an icon, and file it into a folder. The same Shape step is re-runnable on any existing board via Board setup in the board menu and from the view-preferences pane (admin scope), so a board can be trimmed or expanded exactly the way it was born. The chosen tab set is respected to the letter: nothing rides along anymore, so a template that says one view really produces a board with one tab - Software project is the only built-in that ships the Code tab by default - and the "Opens in" pick offers every enabled view except Code and Automations, which can't be a landing tab (one is admin-only, the other starts as a setup screen). Templates got real substance too: saving one can now include up to 50 open cards with their checklists as skeleton work (trashed, archived, completed, cancelled, and draft cards never travel), carries the board icon, and takes a category - and instantiating a template restores all of it transactionally, including a localized Default list-view preset when the template brings no views of its own. Curated templates ship with sample cards, sensible tags and custom fields (severity, deal value, progress), and a prewritten board AI context. Experts lose nothing: "Don't show this again" in the dialog (or the new-board-wizard toggle in Tweaks > Behaviour) restores today's instant name-input everywhere, with the gallery still one click away under "From template". Import moved into the gallery's footer as well as keeping its menu entry. The getting-started checklist's "Create a board" item now opens the flow directly. Intake forms travel too: Save as Template grew a "Save forms" toggle and Clone an "Include forms" toggle (both on by default), carrying a board's forms with fresh public links and zeroed counters - password protection and cover images never travel, clone keeps its notification emails since the recipients still apply, and form fields wired to custom attributes re-wire themselves to the recreated fields on the new board instead of arriving broken. The Bug tracking and Client CRM built-in templates now ship with a ready-made intake form (bug report and contact form respectively), landing submissions in their first list. Custom attribute definitions were already carried by both clone and template; that stands verified. Agent workflows travel with templates too: a template structure can now carry full agent workflow definitions, with their card effects stored portably - lists referenced by position, tags by name - and re-wired to the real records when the board is born, so a workflow that moves cards can finally ship inside a template instead of arriving amnesiac. The AI-assisted build template puts this to work: it is born with the Coding agent workflow already installed as the board default, kickoff parking the card in "Agent working", the Review step moving it to "Review" for a human pass, and blocked or failed runs sending it back to "Up next" wearing a blocked tag that the next pickup clears. And your own boards can do the same: Save as Template and Clone Board both grew an "Include agent workflows" toggle (on by default) - templates store the workflows portably and strip per-step agent assignments (bot identities are workspace-local), while clones keep the assignments and remap every list and tag effect onto the cloned records. To end the naming collision that hid this gap, the old "Include workflows" toggle - which copies the automation builder's workflows - now reads "Include automation workflows" in both dialogs. The gallery also grew two deliberately minimal templates: Simple kanban (three lists, one view, zero content - the lightest possible board, and now the first tile in the gallery) and Knowledge base (only the Notes view: a Markdown vault seeded with Docs and Meeting notes folders plus a localized "Start here" page that teaches wiki links and points at Board setup for the day tasks become needed). New strings in all five locales.
- Truetask Desktop: a native macOS app that wraps your workspace and owns
truetask://. New top-leveldesktop/app (Tauri 2 on the system WKWebView, ~15 MB, no bundled Chromium): download it, enter your workspace URL - cloud or self-hosted - sign in once, and the whole web app runs inside a native window whose session survives restarts. The app registers thetruetask://protocol and routes every launch through the DEVE-387 Rust security core as-is: strict URL parsing, repository resolution against your configured clone roots with origin verification, branch and SHA checks that fail loudly instead of opening the wrong checkout, first-use per-tool approval (revocable in the new shell Settings), explicit confirmation before any clone-on-demand, and argv-only process execution - never a shell string. Terminal agents are never spawned headless into the void: the app verifies the checkout, copies the exact quoted command to the clipboard, and opens Terminal right at the repository. IDE tools (VS Code, Cursor, Zed) open directly. Option+Space summons a Spotlight-style palette (configurable via a press-to-record shortcut control in the shell Settings, shown next to Quick Capture in the tray menu): type to search cards, boards, and notes across your workspace and hit Enter to jump to the result in the main window - or press Tab to capture a task on the spot, with title, description, and a proper board combobox - searchable, showing each board's icon and its folder, with starrable favorites pinned on top - that remembers the last board and list you captured into so repeat captures are just type-and-Enter. The palette is movable and resizable and remembers its position, it only appears once you are signed in (otherwise the app brings up the main window and says so), and the shell mirrors your web session into the Keychain on its own - no web deploy required. The account menu also grew a browser-only Download app row between Settings and Help. The palette is scriptable from anywhere via the newtruetask://capture?title&description&board&urlcommand (Raycast, Alfred, browser bookmarklets), parsed by the same allowlist-strict Rust parser astruetask://open, and your session token lives only in the macOS Keychain - palette API calls run in the native layer, never in a webview. The wrapped web app detects the shell and upgrades itself: coding-tool actions route through the native bridge with verified checkouts (plain browsers keep every existing copy and URL-scheme fallback, and terminal-agent clicks now try atruetask://hand-off first with a clean timeout fallback), the PB session mirrors into the keychain on every auth change, and the Code tools settings pane grew a quiet Truetask Desktop card that shows the connected version or points at the download. Navigation is confined to your workspace origin - external links open in your default browser - and the wrapped page can reach exactly four narrow shell commands, each additionally validating its calling window in Rust. Signed with the same Developer ID as the classic installer, hardened runtime, notarization-ready (desktop/docs/RELEASING.mddocuments the full credential and release flow, updater and CI requirements included). ADR 0002 gained an addendum recording every decision. New strings in all five locales.
- The toolbar is yours to trim now - and sidebar customization finally follows you across devices. Right-click the icon cluster at the top right to hide any of its optional buttons - Search, Timelogs, Timer, and the agent command center - with live checkmark toggles, a direct "Hide X" entry when the right-click landed on a specific button, and a shortcut into the new Customize interface dialog. That dialog is the old Customize sidebar grown up: one dialog, two tabs (Sidebar and Toolbar), and every entry point - sidebar gear, sidebar menus, toolbar context menu - lands on the tab it configures. Notifications and the profile menu are deliberately not on offer: they always stay. The agent command center gets the same "Show when badged" tri-state the sidebar items have, so it can stay out of sight until an agent actually needs you; the Timer button resurfaces on its own while a timer is running, whatever the preference says - a hidden ticking timer is a footgun; and hiding Search never touches the command palette or its keyboard shortcut. Underneath, per-user chrome visibility - toolbar buttons and sidebar nav items alike - moved out of device-local storage into the user's preferences record, so hiding a nav endpoint on one computer finally sticks on the next, with a device-local mirror keeping the first paint instant even before (or without) the server answering, and each device's pre-upgrade sidebar setup adopted into the account on its first boot after the update. New strings in all five locales.
Added
- Truetask Desktop now builds for Windows and Linux, not just macOS. The wrapper's macOS-only seams were made per-platform: the session token lands in the OS keystore of wherever you are (macOS Keychain, Windows Credential Manager, GNOME Keyring/KWallet via the Secret Service - libdbus linked statically so nothing extra needs installing),
truetask://links register at runtime on Windows (registry) and Linux (.desktop entry) and a second app launch - which is how those platforms deliver protocol links - hands its URL to the running instance instead of opening a duplicate window. Terminal agents get a real console everywhere: Terminal.app on macOS as before, the first available terminal emulator on Linux (x-terminal-emulator, GNOME Terminal, Konsole, kitty, alacritty, xterm...), and a PowerShell window on Windows - all through the same generated-launcher containment where the prompt text travels in a file and can never escape into a command line. Tool discovery learned each platform's install map (VS Code/Cursor/Zed user installs and npm's global bin on Windows, snap and flatpak export dirs on Linux),wherereplaces the login-shell PATH probe on Windows, and console children never flash a window. The quick-capture palette keeps Spotlight's non-activating panel on macOS and becomes a focused always-on-top window over all workspaces elsewhere - the launcher idiom of PowerToys Run and Ulauncher - with the palette's ⌘ shortcuts reading and acting as Ctrl there. Bundling is wired per platform (dmg / NSIS per-user installer with WebView2 bootstrapper / deb + rpm + AppImage) with a Windows .ico generated from the app icon, the tray shows the colored icon where template glyphs would vanish into a dark taskbar, and the wrapped web app is told the real platform instead of assuming macOS. The Windows code paths type-check from macOS via cargo-xwin and the Linux ones in a container - both documented indesktop/docs/RELEASING.mdalongside full per-platform build instructions. Each platform also gets a one-command build script (desktop/scripts/build-macos.sh,build-windows.ps1,build-linux.sh) that verifies the four version carriers agree, checks the platform's prerequisites, builds the bundles, and prints artifact paths with SHA-256 checksums - the macOS one runs the whole sign-notarize-staple pipeline by default (UNSIGNED=1opts out), and every script announces loudly when it is producing an unsigned build.
Changed
- Every Settings view speaks the same design language now. The settings dialog's thirty-odd views had each grown their own habits: Save lived inside the enable switch on one page, at the bottom of the form on another, and said "Save changes" on a third; headers scrolled away on some pages and stayed put on others; padding shifted between views; section labels came in seven different styles; buttons widened mid-click as "Save" turned into "Saving..."; and the left nav's selected state was genuinely invisible in light mode. All of it is unified. Every view now shares one skeleton - a pinned header (title, description, and the book doc link, rendered by one shared component, with the eight views that lacked a doc link gaining one) that never scrolls away, content scrolling beneath it - and every view that persists something ends in the same pinned footer row with one identical Save at the bottom right: floppy-disk icon, a label that never changes, the icon swapping to a spinner and the button disabling while a save is in flight, so nothing ever jumps or resizes. The same no-jump treatment now covers every busy button in Settings (Test Connection, Create Backup, Export Workspace, Send Test Email, dialog Create/Save, destructive confirms - which also gained idle icons so the spinner has a place to land). Section labels wear one eyebrow style, scroll areas share the overlay scrollbar without stray right-hand gutters, status greens are emerald and warnings amber everywhere, the config under every enable switch slides open and closed instead of popping, and the selected nav item is finally unmistakable in both themes, its icon switching to the filled weight. The audit log's export menu also stopped being the panel's one unlocalized "Download". Seventeen locale strings the old per-view buttons carried ("Save changes", "Saving...", "Testing...", "Creating...", "Exporting..." and friends) retired from all five languages. A second sweep then unified the recipes inside the views: every data table shares one chrome (pinned header, identical column-header type, one row-hover treatment that actually reads in dark mode - two tables and four header rows were still on an invisible default), every sortable column header, pagination footer, search field, status pill, removable token chip, date-range filter, and row-actions menu is now one shared component instead of up to twenty-five hand-rolled copies, filter rows share one labeled layout with one control height, both bulk-action bars match, the three competing destructive-confirm button treatments became one, empty states share the same illustration pattern, and icon buttons use the size that matches their box instead of overriding a wrong one. Duplicated demo-mode guards and invisible alignment placeholders went out with the sweep. And focusing a control that sits flush with the pane edge - the User Directory search, the Workspace name field - no longer slices its focus ring off at the edge: the views' clipping boxes now leave the ring its four pixels of air.
- The Code tab is on every board now - with a guided setup instead of a vanishing act. The git tab used to be the one tab that played by its own rules: it existed only after an admin had already connected a provider in Settings → Git and linked a repository, and it wore the provider's name (Gitea, GitHub, GitLab) while every view menu called the same thing "Code" - so new users had no way to even discover the integration, and the menus seemed to talk about a different tab. The Code tab is a first-class view now: present on every board by default, hideable per-user or board-wide exactly like Files or Forms. Opening it on a board with no repository shows a two-step guided setup - 1. Connect a provider, 2. Link a repository - resolved live (step one shows a check and the connected provider's name once the workspace is signed in), with a single button that always does the current step and hands off to the existing connect wizard, which already walks provider → authorize → pick-a-repo locked to this board. Workspace owners and admins get the button enabled; everyone else sees the same steps with the button deliberately disabled and a line asking a workspace owner or admin to set it up - the backend gates both actions to OWNER/ADMIN, and an unexplained empty pane would teach nobody anything. Once a repository is linked the tab renames itself to the provider as before (the board can hold several repos, even mixed providers - the label follows the first). Personal tab-visibility overrides saved before this change never offered the Code tab, so they upgrade in place and can't hide it by accident; hide it on purpose and that sticks - and a one-shot migration appends Code to every board's stored board-wide visibility list the same way, so no admin-curated tab set swallows the new default either. New strings in all five locales.
- The view tabs' right-click menu is personal now - and View preferences grew into a real dialog. Right-clicking a view tab used to mix two audiences in one menu: your own quick actions on top, a "For everyone" admin section below - close enough in wording ("Set as my default" / "Set as board default", "Hide X" / "Hide for everyone") that even we kept reaching for the wrong one. The menu now touches only your own setup: Set as default (no more "my" - there's nothing else it could mean), Hide X, and a new Views submenu that flips any view on or off without leaving the menu, with the same guard rails as everywhere else - the view you land on and the last visible tab can't be hidden, and the menu stays open so several can be toggled in one visit. Board-wide settings live in exactly one place instead: the new View preferences dialog. The old anchored popover was too cramped for two scopes hidden behind a pill toggle; members now get a focused single column of their own setup, and admins get a matrix - every view listed once with two slim toggle columns, You and Everyone, plus a compact default-view row per scope - so nothing is duplicated, a per-view mismatch (hidden for everyone, shown for you) is visible on its own row, and changing your own board never means accidentally changing everyone's. Each scope's default view wears a quiet star in its column (you must land somewhere, so it can't be hidden), and the Tab labels and Board setup rows close the dialog out. The square preferences button that sat beside the tabs folded into the tab strip itself: a quiet ⋮ handle pinned at the strip's right end, opening the same personal views menu with View preferences… at the bottom. Wording updated in all five locales.
- Desktop app download links now point at the public site. The account menu's Download app row and the Code tools settings promo both send you to
https://truetask.io/downloadinstead of the oldtruetask.devaddress. - The account menu's Download app row is hidden for now. The desktop downloads are not public yet, so the row is switched off behind a single flag rather than removed; the row, its icon, its link and its translations all stay in place and come back by flipping
SHOW_DOWNLOAD_APPback to true. - The Reviews inbox stopped being blank while it loads - and tells you how to fix "no reviews". Loading now paints skeleton rows in the exact shape of the list (section headers, two-line rows, the author dot bottom-right) instead of a centered spinner, so arriving rows don't shift the page. An unmapped git identity reads as a proper state now: a titled explanation plus a button that goes where the fix lives - workspace admins land in Settings → Git, everyone else gets their personal Git accounts dialog. And inbox-zero got its due, with a quiet "All caught up" headline over the explanatory line. New strings in all five locales.
- The card aging clock moved into the metadata row, and hover tooltips stopped mounting for cards nobody is pointing at. The staleness clock (and its 30d+ "Stale" label) used to sit on its own line under the card title, splitting the card into two places where status lives; it now rides in the bottom metadata row immediately right of the due-date chip, as a bare glyph with no fill of its own - a second pill next to the date reads as a competing value rather than the quiet marker this is - so age sits with the date and the avatars instead of claiming a row. The row appears for an aged card even when the done marker, due date, members and votes are all switched off. Underneath, both that tooltip and every user avatar's stopped being components: a bits-ui tooltip builds its popup lazily but still instantiates a Root, a Trigger and a Content at render time - and the avatar carried a whole tooltip Provider of its own, per avatar - so a task list with two hundred member avatars paid two hundred provider-plus-tooltip instances for a bubble almost none of them would ever show. They now share one small hover helper (extracted from the tag-dot tooltip, which was already doing it right, and which now uses the shared version too): two listeners per element, and a single plain div built on hover and removed on leave. Nothing is created until you actually point at something. The helper also closes on scroll, so a tooltip can no longer be left stranded over the page when the row slides away under a stationary cursor, and it cleans itself up if the card or row unmounts mid-hover. Avatar name tooltips are unchanged to look at, on task-list rows, the comment feed, the archived-cards dialog, the notes view, agent-run views and viewer-mode boards alike.
Fixed
- The webhook dialog's agent events have real names now. The backend fires six agent-run webhook events, but the event picker only knew "Agent handoff" - the other five (completed, failed, blocked, needs input, cancelled) fell into the "Other" bucket showing their raw translation keys. All six now sit together in the Agents group with proper labels in all five locales.
- Disabling Active Directory can actually be saved now. The LDAP view's Save button lived inside the section that only renders while the enable switch is on, so flipping LDAP off made Save vanish along with everything else and the disabled state could never be persisted - it was back on at the next load. With the settings-wide Save relocation into the always-visible footer, switching it off and saving now sticks. S3 went through the same consolidation: its two embedded section saves merged into the one footer Save that writes both, which is safe for an untouched section because the server ignores the masked secret placeholder.
- The collapsed sidebar's boards-menu icon can no longer be impersonated by a pinned board. The rail's boards menu wore the same four-squares glyph the board icon picker offers, so pinning a board with that icon put two identical buttons in the rail - one opening the menu, one opening a board - with nothing to tell them apart. The menu button now wears a four-circles glyph that is deliberately absent from the icon picker, plus a small corner caret marking it as a menu rather than a board.
- An aged card snaps back to full opacity the moment you touch it, instead of staying dim until a reload. Cards that have not been updated in a while dim progressively, and the dim is computed from the card's last-activity stamp - which the server writes, and which your own optimistic edits never had. Every write site marks the card as "mine" so the board can ignore its own realtime echo and avoid flickering mid-drag; but that echo is exactly the message carrying the fresh timestamp, so moving, assigning, tagging, completing or dating a stale card left it visibly stale until the next page load. Ironically it worked when somebody else made the same change, because their echo was not yours to ignore. The board now takes that one value out of its own echo before dropping it - just the timestamp, so a card mid-drag keeps its optimistic position and nothing jumps - which fixes all forty-odd card write paths at once rather than one at a time. Commenting resets aging too now, and durably: a comment only ever wrote to the comments table, so the card record never moved and no client could learn about it; a new hook touches the parent card on comment create, which fans out over realtime to everyone and survives a reload. Cards sitting in a cancelled list are now exempt from aging the same way done-list cards already were - both are terminal, and nothing terminal is stale. And the age itself is finally computed correctly in Safari, whose date parser rejects the space-separated timestamp format the database stores and silently switched the whole feature off there.
- A moved git host no longer bricks its connection with "ip_pin_mismatch". Self-hosted connections pin the provider host's IP addresses at connect time - a DNS-rebinding defense - but the pin never refreshed, so a legitimate IP change (a new server, a rotated tunnel, a changed site address) blocked every git call forever and the repository picker just said "No repositories found". The pin now heals itself through full revalidation: the host is re-resolved, re-checked by the same SSRF classification, and the stored credential must verify at the new address before the new pin is saved, so the rebind protection stays intact. The heal runs inline on every provider call - listing repos, syncing issues and PRs, registering webhooks, the health cron, the connection's "Test" button, and the OAuth code exchange and token refresh (which re-pin the OAuth app record too) - retrying the blocked request once against the re-verified address, so surfaces like the board Code view recover without anyone noticing. When a call does surface the block client-side, the app re-validates and retries on its own, announcing a successful heal with a "View connection" button that opens Settings → Git; only when the heal fails (the token no longer verifies at the new address) does the toast explain that the host's IP changed, with a "Renew token" button that jumps straight to Settings → Git with that connection's re-token panel already open. Toast strings shipped in all five locales.
- Installing an automation template can create the tag it asks for - and its pickers are clickable again. The install dialog asks you to match a template's references to your board ("Which tag marks weekly-recurring cards?"), but the control that answers it was opening underneath the dialog itself: the dialog had been raised to the nested-modal layer so it could be summoned from inside other dialogs, and its pickers stayed on the layer below, so the list showed through the dimmed backdrop while every click landed on the dialog in front of it. Picking anything was a fight and creating something new was impossible. The pickers now sit on the dialog's own layer. On top of that, a tag reference is no longer just a list of what already exists: it hosts the product's shared tag picker - the same search, create, color and inline-rename panel the card window uses - in single-pick mode, so the tag a template needs can be created with a real name and a real color without leaving the install. It stays a reference surface rather than a tag manager, though: tags that already live on the board are pick-only, their color dot a label instead of a control, with no rename and no delete. Tags you create right there keep the full row - recolor, rename, delete behind the usual confirmation - so a typo is fixable on the spot. Rename one and the install follows it to the new name; delete the one you had picked and the field empties and Install goes back to waiting for an answer. Lists and custom fields keep their type-to-create combobox, now equally reachable. New string in all five locales.
- Closing a dialog no longer pops the tooltip of the button that opened it. Dismissing the board's Share dialog handed focus back to the Share button - correct for keyboard users - and the tooltip took that focus as an invitation, so "Share Board" bloomed under the cursor over a button the user had just finished with. Tooltips now ignore focus that did not come from the keyboard, everywhere in the app rather than on the handful of buttons where somebody had noticed the problem before; hovering still shows them, and tabbing to a control still does too. The Share button goes one step further, since a dialog dismissed with Escape leaves the restored focus looking keyboard-driven to the browser: it keeps its tooltip closed for as long as the dialog owns the interaction and re-arms the moment the pointer or a fresh tab reaches the button again.
v1.3.075
Fixed
- A brand-new account no longer opens with its board Style reading "Custom". Comfy is the stock look every board starts with, yet the preferences seeded for a new user carried card padding, corner roundness, list width, and list gap values left over from before the Comfy preset existed, and never set the milestone toggle (so it stored off) - five differences the Style picker dutifully read as "Custom" from the very first load, before anyone had changed a thing. The new-user seed now mirrors the Comfy preset field for field, so a fresh account reads "Comfy" as intended, with a comment tying the seed to the preset so the two can't drift apart again.
- Sign-in and verification emails stopped signing themselves "- Acme". The OTP and other auth emails close with the workspace's app name, which lives in the instance settings - and PocketBase's factory default for that field is literally "Acme". Nothing ever replaced it on instances where no one had saved a branding record, so every code email went out signed by a company that doesn't exist. The bootstrap now catches that untouched factory value (or an empty one) and replaces it with the branding record's name if one exists, "Truetask" otherwise - on every boot, so existing instances heal on their next restart. A name an admin actually chose is never overwritten.
- The welcome wizard stopped greeting you by your placeholder username. A fresh cloud sign-up lands in the wizard before choosing a name, so the greeting read "Hi users147754, let's get you set up!" - addressing you by the random account handle the system minted seconds earlier. The greeting is just "Hi, let's get you set up!" now; the profile step right behind it is where the real name gets set. All five locales updated.
- Adding a workflow step no longer strands tooltips over the step list. Clicking Add step smooth-scrolls the editor to the fresh step, and as the rows slid under the stationary cursor each one's hover tooltip could fire and stick - leaving two or three "Step agent" bubbles floating over steps nobody was pointing at. The cause: every tooltip in the step editor carried its own private tooltip provider, and the provider is precisely the thing that closes an open tooltip when another one opens. The whole steps-and-outcomes region now shares a single provider, so at most one tooltip can be up at a time - the moment another trigger opens, the previous bubble closes, mid-scroll or not. Hover feel is unchanged (same 150ms delay).
- Turning the workspace AI switch off now hides every agent entry point, not just the Agent tab. A workspace with AI disabled still offered doors into agent features that led nowhere: Coding agents sat in the account menu, Agent workflows and Agent behavior in the board menu, Copy agent kickoff in the task window's dropdown and both card context menus, the Agent tab toggle in board Preferences > Behaviour, and the MCP connector dialog still pitched "Create a coding agent". All of them now follow the switch: with AI off they disappear entirely (the kickoff item also stops fetching the board's workflows it would never show), and flipping AI back on brings every one of them back exactly where it was. The MCP connector itself stays available either way - connecting your own client to your own data was never an AI feature.
- The Agent tab really stops flashing now. The previous release moved the tab off refetch-the-world onto realtime patches, but one dependency slipped through: the tab's loaders were keyed on the card record itself, and the board replaces that record on every realtime touch. A live run touches its card constantly - the presence heartbeat and the run-status mirror both write to it - so each step tick still tore the whole dashboard down to loading skeletons, refetched the run, the questions, and the working-context note, and rebuilt everything, top tiles included. The loaders now key on the ids they actually need (the card's id, the context note's id, the run's id), which do not change when the record object does, so a step update repaints exactly the pixels it owns: one step row, the progress counter and its segments, the log list - labels and everything else stay put. The steps and log subscriptions also stop being torn down and reopened on every run event (a gap that could drop an update), and a slow run fetch that resolves after you have switched cards can no longer paint the previous card's run over the current one.
- The workflow editor now always states where kickoff moves the card - without wrecking the header. On boards with several In Progress lists, the list selector used to squeeze into the title row beside the workflow name, crushing the name field into a stub and spilling past the pane's padding; on boards with a single In Progress list it didn't render at all, so nothing told you that starting a run moves the card. The selector now sits on its own line right under the description and reads as a sentence - "When a run starts, the card moves to ..." - with each list wearing its flow-state icon in its own color (the "First In Progress list" fallback stays muted), in the trigger and in the dropdown alike. And it renders whether the board has one In Progress list or five, so the side-effect of kicking off a run is always visible and pinning a specific list stays one click away. New string in all five locales.
- Saving an agent workflow no longer collapses the step you were editing. Save refreshes the editor from the server's copy of the workflow, and that refresh rebuilt every step in its collapsed state - so hitting Save mid-edit folded the very step you were working in and made you re-open it after every save. Each step's open/closed state now survives the round trip (matched by the step's stable id), so the editor looks exactly the same after a save as before it: open steps stay open, and the step rows keep their identity instead of being torn down and rebuilt.
- Renaming in the Notes browser no longer jolts the row. The inline rename field used to draw its box from the panel's left edge - ignoring the tree indentation entirely, worse the deeper the note sat - with the icon and text shifted left of where the title normally rests and the text a size smaller. The field now mirrors the row it replaces exactly: same indent, icon and title in the same pixel positions, same type size, for notes and folders at any depth, so entering and leaving rename doesn't move anything but the outline. The inline "new note / new folder" input got the same treatment. And the tree learned the sidebar's shortcut: double-click a note's title to rename it, with the full title pre-selected and ready to type over.
Changed
- The welcome wizard shows what TrueTask does instead of describing it - and it finally can't be dismissed half-done. The first screen used to be an empty hello: an icon in a gray box, a greeting, and a sentence. Now the rocket stands on its own (bigger, regular weight, no tile) above a living miniature board that plays the product's story on a calm loop: a card appears in To Do, an agent chip lands on it with a pulsing working dot, it slides to In Progress, a PR badge appears, and it lands in Done wearing an emerald check - built from the product's real visual vocabulary (accent-fill lists, floating cards), translated column labels matching each language's kanban terms, honoring reduced-motion with a static scene, with one short caption beneath instead of paragraphs. Every step now fits the dialog exactly (nothing scrolls or gets cut off), steps glide in instead of popping, and the close button that let people abandon setup mid-way is gone for real: the wizard passed a prop the dialog never had, so an X rendered anyway - it now must be finished, as intended. The profile step grew up: the whole avatar is the upload target now (hover shows a camera scrim; the tiny badge is just a hint), every chosen photo passes through the product's shared crop dialog before it becomes your avatar - pan, zoom, circular preview, same as agent identities, and now also wired into the profile settings dialog - and nothing shifts when it lands: the preview swaps in at the same size and the Remove button fades into a slot that was always reserved for it. The step also stopped pre-filling your name with the auto-generated username (an empty field with a placeholder invites a real name) and finally lets you pick your username right there, prefilled with the generated one and wearing an inline @ prefix. Neither field lets you sail past it empty anymore: leaving the step checks that a name is entered and that the username is present, well-formed, and not already someone else's (a live availability check), with the problem named inline under the exact field - and the server-side unique check on finish still backstops it all, keeping the wizard open with the error named instead of silently keeping the random handle. The final screen's tip rows traded their outlined boxes for the soft filled cards the rest of the product uses - with the quick-search tip rewritten so the keyboard keys sit where the sentence points. And the first screen's caption stopped implying every board comes loaded: "AI agents, automations, and git: ready when you need them." The deeper tour lives where there's room: every new user's Welcome board grows a Discover list after Done, visibly outside the flow, with six cards - one per power feature nothing ever mentioned: flow states and WIP limits (Board flow), the automations builder (pointing at the seeded sample), agent workflows and behavior, intake forms, repository linking, and webhooks - each naming the exact menu entry that opens it. And those curated cards now arrive flagged
skip_hydrate, so the "Hydrate new cards" AI starter no longer re-tags the tutorial with its own guesses seconds after sign-up. New strings in all five locales. - Agent workflow templates are plain blueprints now - no strings attached, and deleting one is real. A workflow promoted to a template and a workflow created from one used to stay tied together: the board workflow carried a hidden pointer back to its template, listings dragged the whole template record along with every workflow, and "deleting" a template only hid it - the record lived on invisibly, with no way to see it or bring it back. All of that is gone. Promoting and instantiating are now one-way copies in either direction: once a workflow exists it is fully its own, nothing tracks which template it came from, and neither side can be "ahead of" or "behind" the other. Deleting a template deletes it - permanently, stated plainly by a confirmation dialog in its place (workflows created from it are untouched, the dialog says that too), and templates that earlier removals had left soft-hidden are purged for good by the migration. The built-in default coding workflow is unaffected: it lives in code, not in the library, so a fresh board still gets its starter workflow even with the library emptied. New strings in all five locales.
- Workflow files now carry their list and tag mappings on your terms - and the import review resolves them instead of dropping them. Exporting a workflow whose steps or run outcomes move cards or set tags now asks whether those mappings should travel: a new "Include list and tag mappings" toggle in the export dialog (on by default) lists every list and tag name that would ride along, and switching it off ships a clean file that behaves like a plain workflow on any board. On the way in, the import review stopped treating unmatched names as silent casualties: every list and tag the file references gets its own row - names that match this board arrive pre-mapped (and can be re-pointed at any other list or tag), and names that don't offer three real choices: map it to something that already exists, create it right there, or skip that name's effects. Creating a tag is one click; creating a list asks the question a list can't exist without - which flow state it belongs to - with an inline picker of the five states (Idle, In Progress, Review, Done, Cancelled) wearing their standard icons, so an imported "QA" list lands as a real In Progress column instead of a nameless idle one. The import stays blocked until every name has a decision, created entities are wired into the workflow's steps and run outcomes in the same pass, and a fully-matched file still imports in one step with no dialog at all. The export dialog itself behaves like the rest of them, too: flipping the mappings toggle slides the name badges in and out so the dialog grows and shrinks smoothly instead of popping, and every toggle row's title and description are part of the switch - click the text anywhere and it flips, exactly like a native labelled control, because that is what it now is. New strings in all five locales.
- Copy agent kickoff wears a rocket now. The paper-plane icon it shared with "send email" surfaces (comments, SMTP, notifications) is gone - the kickoff item now carries a launch rocket in the task window's dropdown and both card context menus, all through the one shared component. The task window's menu also reordered: the copy actions lead, and Move to sits in its own separator-fenced group between them and Archive, so the destructive tail keeps its distance from the everyday items.
- The Board workflows header is down to one button. The separate import icon moved into the + menu as its third entry - Add built-in workflow, Create empty workflow, then Import workflow behind a separator - so every way a workflow can arrive on the board now lives behind the same +. In the built-in gallery, the category chip (Coding, Debugging, Review, ...) is pushed to the card's right edge, off the title, so names and chips each get their own column.
- Workflow descriptions read in full now, everywhere. In the workflow editor the description used to be a single truncated line that only became editable on click - fine for a one-liner, useless for the built-ins' paragraph-length descriptions. It is now a permanent input right under the name, exactly like the title: always editable, auto-growing to fit its content. The Built-in workflows gallery got the same treatment - cards no longer clamp their descriptions to two lines, and the dialog grew wider and taller so the six entries read comfortably.
- Workflows in the Agent workflows editor answer to a right-click now. The Board workflows list on the left grew a context menu carrying the same workflow-scoped actions that sit under the steps - Duplicate, Save as template, Copy to board (fanning out into the same board submenu), Behavior, Export, and Archive (absent on the default workflow, which can't be archived) - but aimed at the row you clicked, not the one open in the editor. The selection never moves: right-clicking another workflow doesn't switch to it (switching discards unsaved edits, a right-click never should), Behavior opens the clicked workflow's policies, and Export downloads the clicked workflow as saved - unless you right-clicked the workflow you're editing, which exports with unsaved edits included, exactly like the action-bar button.
- Documentation links look the same everywhere now. A handful of dialogs and pages still announced their docs with an underlined "Documentation" text link on its own line - the Clone board, Save as template, and Choose a template dialogs, the milestone editor, the push-notifications section of the profile, and the license activation page. All of them now use the quiet convention the settings views established: a small book icon at the end of the title or description, opening the docs in a new tab, with the label carried by a tooltip instead of taking up a line (the push-notifications link keeps its specific "Browser setup & troubleshooting" wording in that tooltip). And the icon now truly flows with the sentence - it sits right after the last word, a space away, instead of being pushed to the container's far edge whenever the description wrapped to a second line - across every one of those surfaces, the board share and import dialogs, and all the settings views. The activation page's link was also hardcoded English; it's translated now like the rest.
New
- Four more built-in agent workflows - and the first ones that aren't about writing code. The built-in gallery grows from two entries to six, each with its own icon and category chip. Code review (Review) completes the delegation loop: an agent reads the whole diff, restates what the change claims to do, judges it against that intent - correctness, security, whether the tests can actually fail - then verifies instead of trusting (checks the change out, runs tests and lint itself, exercises the behavior) before posting inline comments and a verdict on the PR; the review is the deliverable, so the run proposes done whatever the verdict. Triage (Triage) turns raw reports into actionable cards without working them: duplicate hunt first, severity and completeness assessment, targeted questions back to the reporter, then tags, priority, and a route to the right list - it is the one workflow that never auto-moves the card, never proposes done, and never completes anything, because triage prepares work rather than doing it. Research report (Research) answers questions with evidence: pin the question down, map sources, gather findings with citations, cross-check every load-bearing claim against a second source or direct verification, write the report in a linked note - answer first, confidence levels, open questions - and re-read it as a skeptic before proposing done. Checklist executor (Operations) runs any process the team already wrote down: the card's checklist is the procedure and the agent supplies the discipline - read the whole list first, batch the questions up front, check a box only with evidence recorded, no silent skips, and a final verification pass where every item is done with proof or reported with a reason; built for SOPs, recurring ops, onboarding, and release checklists. All four ride the same rails as the first two: symbolic effects resolved per board, failure outcomes that tag
blocked, retries and fallbacks where they earn their keep, and full descriptions in all five locales. - A second built-in agent workflow: Bug squashing - reproduce first, fix the cause, prove it both ways. Where the Coding agent plans a change, this one hunts a defect: the agent may not touch code until it has reproduced the bug - following the report against the current branch, capturing the failure as evidence, and codifying it as a failing test when practical (can't reproduce it? It asks instead of guessing at a fix). Then it diagnoses the root cause - tracing the failure to the code responsible, using git history to learn whether it's a regression - and writes cause and intended fix into the working-context note before the Fix step makes the smallest change that removes it, sibling code paths included. The review gate is bug-shaped too: the reproduction must fail without the fix and pass with it (a fix whose reproduction never failed proves nothing), and the reviewer judges whether the change removes the cause or masks the symptom. Tests, lint, docs, PR, and CI follow as in the Coding agent, retries and send-backs land on Fix, and the proposed done names the root cause and regression coverage. Cards picked up by this workflow get the board's
bugtag on kickoff (matched by name or created), so the board shows what kind of work is in flight. It sits beside the Coding agent in the built-in gallery with its own rose bug icon and Debugging chip. New strings in all five locales. - Agent workflows now ship built-in - and archived workflows finally have a way back. The + button in the Agent workflows editor grew into a menu with two ways to start: Add built-in workflow opens a gallery of ready-made processes maintained in the product itself (styled like the automation templates: duotone icon tile, category chip, description, step count), and Create empty workflow starts from scratch as before. The first built-in is the Coding agent - the full 14-step process proven on our own board: load context, clarify, plan before touching code, implement, then gate the work with tests, lint, docs, an adversarial self-review, and a CI watch after the PR opens, with automatic retries and send-backs on failure and a proposed done at the end. Built-ins are un-deletable and un-modifiable by construction - they live in code, not in the database - so adding one puts a fully editable copy on the board that can never be lost for good: remove it, and it is always there to add again. The copy arrives speaking the board's language: flow-state moves resolve to the board's own lists (kickoff to its first In Progress list, the wrap-up to its Review list), and the
blockedtag it uses is matched by name or created on the spot. A board's very first run seeds this same built-in, so the starter workflow every board gets is now the good one, effects and all. And archived workflows stopped being a black hole: an Archived (n) row at the bottom of the Board workflows list opens a dialog scoped to this board where each workflow can be restored (it comes back selected, as a regular non-default workflow) or deleted permanently - a real delete behind a confirmation that states exactly that, allowed only from the archive so a live workflow can never be nuked in one click, and harmless to history since past runs carry their own frozen copy of the steps. Saving a workflow as a template also stopped failing on the second try: template keys get a unique suffix now instead of colliding with the first promotion. New strings in all five locales. - The sidebar reorders by drag now - pinned boards on the rail, nav rows inside their section, and the Customize sidebar dialog too. Grab a pinned board icon on the collapsed rail and slide it up or down: the other icons step aside as you go, the dragged icon rides a vertical track (no sideways wandering), and it stops dead at the boards-menu icon - it can push its neighbours around but never leave the stack. The expanded sidebar's nav rows (Personal, Workspace) drag the same way, each row staying inside its own section, so My Tasks can trade places with Reviews but never wander into Workspace. The Customize sidebar dialog joined in: its rows now list in your live sidebar order, and each carries a six-dot drag handle to reorder from there - what you drop in the dialog reorders the sidebar behind it on the spot, and vice versa. While dragging you see exactly one row: the row itself rides the pointer while an empty slot walks through the list - no more semi-transparent twin trailing a duplicate. Your order is saved to your user preferences - it follows you to every computer you sign in on - and mirrored on the device so the sidebar paints in your order instantly on the next load, before the server is even asked.
- Agent workflow steps move cards and set tags on their own now - and the run's outcome can too. Until now the run engine touched the board exactly once: kickoff moved the card to an In Progress list, and every move after that was a polite instruction the agent could forget (and silently skipped when the "agent moves cards" policy was off). Card movement is now a property of the workflow itself. Every step carries optional card effects - a target list (any list, any flow state, not just In Progress) plus tags to add and tags to remove - applied by the engine the moment the step becomes active, on every path there is: forward advance, handoff adoption, manual and automatic retries, and send-backs, where they shine - a run kicked back to Implement walks the card back across the board by itself, and a fallback step that adds a
blockedtag gets it cleared by the step that re-enters later. Leaving every list empty is now a real choice: a research or context-reading workflow can declare that the card never moves at all, which was previously impossible. Legacy workflows keep the old kickoff move untouched until they are saved through the editor, which surfaces that move as step 1's list effect so it is finally visible and editable; the old header selector is gone. Runs freeze effects in their snapshot like everything else (editing a workflow never redirects an in-flight run), moves ride the bot WIP bypass so a full column cannot wedge a run, and every applied effect writes a run-log line. For run states that are not step transitions, each workflow also gets a Run outcomes section - completed, failed, blocked, needs input, cancelled - with the same list-and-tags controls, so "blocked goes back to To Do and gets tagged" is now two clicks. And for everything beyond that, run outcomes became a first-class automation citizen: a new Agent Run Status trigger node (filterable per outcome, with{run.*}placeholders) plus per-outcome webhook events (agent_run.completed/.failed/.blocked/.needs_input/.cancelled). Steps rail chips show each step's destination list (in its flow-state color) and tag delta, so reading the rail top to bottom is reading the card's journey across the board. Effects travel by NAME in workflow export/import with the import review listing anything that has no match on the target board, they are stripped when promoting to a template, and the server drops ids that don't belong to the board on every write path. The agent contract states when a workflow applies its own moves, so agents stop duplicating them. New strings in all five locales. - Cards can be upvoted now - built-in voting for lightweight, collaborative prioritization. Retros, idea boards, "what should we build next": turn on Card voting in the board menu (admins only, off by default, per board - the way Trello gates its Voting Power-Up, except ours is built in and free) and every card grows a vote. In the task window a Votes row sits right under Members: one click casts your vote, the count and the voters' avatars sit beside it, and clicking again takes the vote back - one vote per person, enforced by the data model itself, so there is no double-voting to police. On the kanban board a card with votes wears a small count badge (subtle filled pill, matching the due-date badge; cards without votes stay clean), and the badge itself toggles your vote without opening the card - as does a new Vote entry in the card's right-click menu, which is also where the first vote on a fresh card is cast from the board. Votes would be invisible without a way to rank by them, so they plug into every ranking surface at once: a Votes column in the List view (hidden by default, sortable, exports to CSV with the rest), a Votes per-list sort on the kanban (most-voted first), and a Votes filter in the board filter popover (number-typed, so "more than 5" and "has any" both work, and it persists in saved filters like any other). Everyone with board access can vote - including read-only viewers, whose one permitted write is exactly this opinion - and votes update live across everyone's boards through the same realtime channel cards already use. Agents get the same rights over MCP with new
cards_vote/cards_unvotetools,votes+vote_countride along in every card payload (REST:POST/DELETE /v1/cards/{id}/vote), and the vote store is a users relation on the card, so "who voted" is first-class data, not a counter. The opt-in also travels: cloning a board keeps its voting setting, saving a board as a template records it and boards created from that template inherit it, and a board export/import round trip preserves it - across both the FastAPI and PocketBase code paths (older templates and exports simply lack the key and fall back to off). New strings in all five locales.
v1.3.074
New
- One task, several agents: workflow steps can now be assigned to different coding agents, and runs hand off between them automatically. In the Agent workflows editor every step grew a small agent chip: leave it alone and the step runs as whichever agent picks up the task (the quiet caption under STEPS says exactly that), or pick one of the board's agents and that step - and every step below it, until the next assignment - becomes theirs. Only the assignments you set are stored; everything else inherits, so setting an agent on step 3 of 10 hands steps 3-10 over in one click, and the editor repaints its new ownership rail in the same frame: tinted segments with the agent's avatar heading each stretch, a down-arrow "Hands off to ..." marker at every boundary, and a dashed neutral "Kickoff agent" segment on top while no one is pinned. At run time the pipeline is real: when an agent completes its last owned step the run flips to a new
handoffstate - the next agent is assigned to the card, the Agent tab shows an amber "Waiting for ..." banner with a copy-kickoff button that routes the pasted session straight to adoption, the kanban card keeps saying who it's waiting for even after the previous agent's presence decays, and the hover peek's status pill pulses amber. The waiting agent'sagent_runs_startadopts the run at the waiting step; any other bot gets it read-only (which also closes the old hole where any bot could silently resume any run, and bot step updates are now gated to the run's current agent). The working contract scopes each agent to its own steps ("You own steps 9-11 ... do NOT redo steps owned by other agents"), single-agent runs behave exactly as before, and a handoff to a missing or off-board agent blocks the run visibly instead of stranding it. Three wake-up rails fire on every handoff: a notification to the target agent's human owner, anagent_run.handoffwebhook through the durable delivery queue, and a new Agent Handoff automation trigger (with an optional target-agent filter) so a runner can auto-launch the next session. Templates stay agent-free (promoting a workflow strips assignments, copying across boards drops bots that aren't members), and the agent-setup document teaches visiting agents the whole protocol. The loop closes in both directions: when review finds a problem, the reviewing agent (or any board editor) calls the newagent_runs_send_back- one atomic call that resets the target step and everything after it, returns the run to that step's agent with a required, visible reason (logged and mirrored as a comment), and fires the same wake signals as a forward handoff; the receiving agent reads the reason first and redoes the work, and the pipeline flows forward again. And the wake-up is configured on the step that hands off, because that step is the handoff: assign an agent and the step asks "How does this agent get started?" with three exclusive answers - Notify the team (the owner is pinged and the task shows a copy-kickoff button for a manual start), Call a launch URL (Truetask POSTs the run, step, and agent to your runner, which starts the session by itself), or Run an automation (a board automation on the Agent Handoff trigger reacts; a button installs a ready-made "on Agent Handoff -> HTTP request" workflow, prefilled with new{handoff.run_id},{handoff.step},{handoff.to_agent}placeholders). Only the chosen answer opens its settings, the owner is notified either way so a manual pickup always works, and a dead runner just logs a visible warning instead of stranding the run. Both the Launch URL and the automations HTTP Request node can now sign what they send, so the receiving runner can prove the call really came from your workspace: pick a Signing secret (or add one right there) and Truetask sends the standard timestamped HMAC-SHA256 headers a gateway expects. Signing secrets are write-only - you name one and paste its value once, and from then on nobody can read it back, not even the person who set it: the value is encrypted at rest in a store no browser can reach, and the workflow or automation only ever holds the secret's id. That is deliberate, because a workflow step and an automation graph are readable by everyone on the board, which is also why the hint tells you never to put a secret in a URL or a header. Every boundary then states itself on one line - "Hands off to qa-bot" with a chip pinned right saying how it wakes them (Notify, Launch URL, Automation), turning amber with Needs a URL when the setup is unfinished. New strings in all five locales. Agents also carry their own wake endpoint now (My agents > Wake endpoint, owner-set like the guardrails): Truetask POSTs the signed handoff there whenever a run becomes that agent's turn - forward handoffs, send-backs, retries, and reassigns, which previously woke nobody because only boundary steps carried a URL. A step's Launch URL still overrides it, an agent can never edit its own (frozen server-side, like guardrails), and the secret is a write-only signing secret referenced by id. On the watching side: the run's status is mirrored onto the card itself, so the kanban progress strip now stays up for as long as the run is genuinely live - it used to vanish whenever a remote agent thought quietly for five minutes, with no way back - while a completed or cancelled card never shows it (the human decided the outcome), and a "live" status with a full day of agent silence is treated as wrong and hidden rather than trusted forever; the Agent tab patches step, run, and log changes in place instead of refetching and re-rendering everything (the "whole tab flashes on every tick" is gone); the steps rail's state glyphs shrank to match the agent avatars and every column - name, status, avatar, caret - sits in a fixed position so nothing slides as statuses change; a run that claims to be active but has had no agent activity for 15 minutes stops pulsing green and says "No activity for Nm - the agent may have stopped" in amber; and the working contract now forbids an agent from ending its turn with a step left active, so a finished agent can never leave the UI looking busy.
- A failing workflow step can now retry itself or send the run back to an earlier step - configured per step. In the Agent workflows editor every expanded step gained an "If this step fails" row: pick how many times the step re-arms itself, then what happens once the retries run out - fail the run (as before) or send the run back to any earlier step. The send-back target is referenced by a stable per-step id, so renaming the target updates the picker label in place, and a target that gets deleted or dragged past its dependent flags the step with an amber "Fix fallback" chip, an inline explanation, and a blocked Save; a collapsed step summarizes its policy in a small chip. At run time the policy is enforced server-side from the run's frozen snapshot: when an agent reports a step
failed, the step re-arms with the attempt visible in the run log ("attempt 2 of 3"), and once retries are exhausted the run is sent back exactly like a manual send-back - the failure reason the agent gave is posted to the task as a comment, the rewound steps reset with a fresh retry budget, and if the target step belongs to another agent the run flips tohandoffand fires every wake rail. The reporting agent learns what happened in the same response (failure_policy: keep working, redo the earlier step, or stop), and every send-back - automatic or manual - now states whose turn it is explicitly: a send-back to your own step says "it is YOUR step: redo it now", while one that lands on another agent's step names that agent, flagshandoff: true+owned_by, and instructs the sender not to carry the step itself, each step gets at most 3 automatic round trips per run before the run fails loudly instead of looping, and steps without a policy fail the run immediately, exactly as before. Policies survive duplicate, copy-to-board, template, and export/import round trips, and the board's agent-setup document annotates each step with its policy ("on failure: auto-retry up to 2x, then the run goes back to step 3 'Implement'"). - Agent workflows now travel as files: export any workflow as JSON and import it on any board, with the same care automations get. The workflow editor grew an Export action next to Duplicate and an import button at the top of the Board workflows list. Exporting a plain workflow just downloads it, no questions asked; one that hands off between agents first asks what should travel: a toggle for the hand-off launch settings (launch webhooks and Agent Handoff automations), and nested inside it a second, off-by-default toggle for the launch URLs themselves, with every address listed so you can see exactly what would leave. Signing secrets never travel, whatever you choose, and the dialog says so on its face. Agent assignments export by name, never as account ids, and on import a review dialog maps every name onto the target board's agents: names that match arrive pre-resolved, avatar and all, while unknown names block the import until you pick an agent or explicitly leave those steps unassigned (and an unassigned step sheds its handoff wiring with the assignment, since there is no boundary left to fire). External URLs are gated again on the way in, behind an amber safety warning and an off-by-default switch; declining them keeps the steps' launch mode so the editor's "Needs a URL" chip asks for a replacement instead of silently downgrading the handoff to a notification, and automation handoffs get a reminder that the board needs an automation on the Agent Handoff trigger. Hand-crafted files can't smuggle anything past the gate either: unknown keys, raw ids, secret references, and non-http URLs are stripped on parse, and the server re-validates every agent against the board's bots anyway. Files that need no decisions import in one step, invalid files fail with a clear toast, and the whole flow mirrors the automations import review users already know. New strings in all five locales.
- What a coding agent does on a card is now an owner-set policy, not baked-in code. Every board gained an Agent behavior dialog - in the board menu right beside Agent workflows, and one click from the workflow editor, which stays lean and steps-first - controlling, per workflow, how a delegated coding agent works a card: whether it creates a git branch (only when a PR or issue is linked, always, never, or its own call), whether it opens a pull request, whether it must run inside a structured run, whether it asks and stops when blocked or presses on, how it treats a Definition of Done, how chatty its progress updates are, whether it moves cards across lists, which checklist items it owns (by assignment, only its own, only unassigned, or all - so several agents, or a human and an agent, can split one task), and whether a working-context note is required. Every setting defaults to exactly today's behavior, so nothing changes until you move a toggle - and each one wears a small info tooltip explaining the control and every option. The per-agent autonomy guardrails (completing, archiving, and deleting cards, merging PRs) sit read-only beside them with a shortcut to My agents, since those live on the agent account. The policies feed the working contract the agent reads through
cards_contextand the board's agent-setup document, so the instructions never disagree. And a card can now kick off any of a board's workflows rather than only the default - the card menu and the Agent tab let you pick which one to hand off. New strings in all five locales. - Board Preferences is style-first now: pick a Style, save your own, and the details tuck away under Advanced. The Kanban tab of the Preferences popover used to open on 22 raw controls; now it leads with a single Style dropdown - Dense, Comfy, Airy, and Vast presets, with Comfy as the stock look every board starts with - and applying one restyles the whole board in a click. A style captures everything under Card Elements and Card Style (all eleven element toggles, the description preview length, and the four sliders); tweak anything afterwards and the dropdown reads Custom, with a one-click Save current as style that stores your look by name - in your account, not the browser, so it follows you to any device (up to 10 saved styles, renameable and deletable in place; the cap is enforced server-side too). All the individual toggles and sliders still exist, grouped under a collapsed Fine-tune disclosure that remembers whether you left it open (per device). A real Save current as style button sits pinned at the bottom whenever Fine-tune is open - enabled the moment your look differs from the selected style - and names already used by the built-in presets or your own styles are rejected with an inline hint. The Card Tabs toggles (which card-detail tabs show) moved to the Behaviour tab, with the other non-look settings. And the popover behaves like a proper panel: the title, tab bar, Style dropdown, and save button all stay pinned while only the controls scroll between them, and nothing ever jumps - expanding Fine-tune, switching tabs, or swapping the save button for its name field animates smoothly at constant height, with the field appearing focused, tinted, and exactly as tall as its Save button. The List Width slider also grew four steps at the top (up to ~448px) and List Gap three (up to ~48px), the stock "Theme" spacing is now a real slider step instead of masquerading as the tightest one, and the effective style is cached on-device and applied at first paint, with your account's copy taking over as it loads - so a saved tags-hidden or labels-only look now applies on reload instead of waiting for a toggle nudge. New strings in all five locales.
- The workspace now teaches AI agents how to use it - one URL, always current. Every workspace serves a living agent-setup document at
/v1/agent-setup.md(also reachable at/agent-setup.md): how to connect over MCP, the full delegation protocol (thecards_contextcontract, structured runs, needs-input, definition of done), git conventions, and API conventions. Fetch it with?board=and a bearer token and it appends that board's team-maintained context, agent workflows, and lists - the base document stays public and secret-free, so a plainfetchfrom any agent always works. Agents reach the same document over MCP as thetruetask://agent-setupresource (board-scoped:truetask://board/), the MCP server instructions point delegated agents at it, and both the copyable kickoff payload and the coding-tool launch prompts now carry the link so it propagates on its own. On the human side, the MCP connect surfaces (the account MCP wizard and the coding-agent token screen) grew a Teach your agent block that copies a one-liner for your repository's CLAUDE.md/AGENTS.md - the repo carries a pointer, not a snapshot that rots - and the agent how-to card links the protocol. New strings in all five locales./agent-setup - Board Flow has a dedicated "Review" state, linked to In Progress. Teams kept hand-rolling a Review column and parking it in the In Progress lane, where it was indistinguishable from active work. Review is now a first-class flow state that sits right beside In Progress in the Board Flow dialog - linked to it the same way Cancelled is linked to Done (no flow arrow between them). A card in a Review list still counts as active work - nothing gets completed or cancelled - but the lane carries no WIP limit, no auto-assign, and no other In Progress side-effects, and Review lists wear their own icon (a double caret in a circle) everywhere lists appear: the Kanban column header, pickers, the automations state selectors (
state:review), and the flow dialog itself. Agents and the API understand it too -cards_move_to_stateacceptsreview(within_review/reviewingaliases). The Board Flow dialog also got its padding tightened so the five lanes have more room. New strings in all five locales. - Git workflows now reach agents, editors, CI gates, and team chat. The Git integration work now includes generated repo automation onboarding and management, MCP parity for Issue and link/reference workflows, per-check CI details with polling fallback and merge gates, safer self-hosted provider access, coding-tool launch actions across reviews and Code views, VS Code/Zed/CLI integration packages, and opt-in Slack or Teams notifications for repo activity.
- The desktop-app launch direction is documented. The helper-only install path is superseded by a full Truetask desktop wrapper tracked in DEVE-389, while
truetask://openremains the native protocol contract for local repo resolution and terminal-agent launches. - Git automation templates now guide you to set Git up first. In the Automations templates gallery, the Git templates stay visible but sit disabled until the board can actually run them, so you never install a Git flow that has nowhere to act. Beside the Git section heading a small shortcut appears - but only for workspace owners/admins who also administer the current board: Connect Git provider when no provider is connected yet (it opens Settings -> Git), or Link repository once a provider exists but this board has no repo linked (it opens the existing link-a-repository dialog). Link a repository and the Git templates enable and the shortcut disappears. New strings in all five locales.
- The MCP git surface is now at full parity with the REST API. Delegated agents working over MCP gained the last dozen Git tools: read a pull request's diff and its conversation, pull your cross-board review queue, promote an orphan issue or PR into a task, close an issue as a duplicate, sync a repository's pull requests and issues on demand, and manage a repository's label-to-tag mappings. They round out the existing connection, repository, pull-request, issue, commit, branch, and user-mapping tools, so anything the Code / Issues / Reviews surfaces can do, a delegated agent can now do too. Reads need board membership, writes need board editor, and connection administration stays owner/admin - all enforced by the API. (Developer-facing; no new user strings.)
Changed
- The Agent tab opens instantly on cards without a run. The tab used to greet every card with a wall of loading skeletons - even when there was nothing to load - and only then swap in the kickoff block; the workflow picker inside that block then waited on its own fetch, queued behind the run lookup, so the dropdown filled in noticeably late. The card itself already knows whether it has a run (the run's status is mirrored onto the card record), so the tab now uses that: no run means the kickoff block renders immediately, and the skeletons only appear while a run that actually exists is being fetched. The workflow picker is served from a shared per-board cache - the board's active workflows are fetched once per session and kept current by a realtime subscription, so the picker (and the right-click Copy agent kickoff submenu, which shares the cache) is populated the moment it appears instead of re-fetching on every open. A migration stamps the mirrored status onto cards whose runs predate the field, so older cards get the fast path too. The task window's copy action produces a clean Markdown dossier of the card - title, status, tags, dates, description, custom fields, checklists, comments - which is just as useful for a wiki page, a chat message, or an email as it is for an AI, so the label now says what you get instead of who it's for. And you no longer have to open the task to grab it: right-click any card on the Kanban board or the Timeline and Copy as Markdown and Copy agent kickoff sit in their own group right under Assign to me - kickoff still fans out into a workflow picker when the board has more than one active workflow, and stays hidden from viewers just like in the task window. One shared component now backs the task-window menu and both context menus, so the three surfaces can't drift apart. Renamed and translated in all five locales.
- The Agent workflows editor is a proper workbench now. The always-open "When to use" box - two labels and a permanent textarea for prose nobody edits twice - collapsed into a single muted line under the workflow name that becomes a textarea only while you are actually editing it, and the name itself is now the pane's title instead of another labelled field. With the space back, the editor got its bands: the Add step bar stays pinned at the top, the workflow actions (Save as template, Duplicate, Copy to board, Behavior, Archive) stay pinned at the bottom, and only the steps scroll between them - ten steps are visible where six used to be. Collapsed steps are taller and easier to hit, and dragging one to reorder is now locked to the vertical axis, so a step can no longer be flung sideways across the dialog while you are only trying to move it up or down. And the name and description at the top now read as what they are - editable fields, not labels: both sit in soft filled inputs aligned with the pane, and the description shows a small pencil on hover.
- Recommended Git automations now use switches and name your board's real lists. The automation cards you review while linking a repository - in the connect-a-repository wizard and mirrored in the board's Git settings dialog - swapped their checkboxes for small switches, dropped the decorative icons, and center the control in the card. And because the repository is bound to a board, the descriptions stop talking in abstractions: once a board is picked, "Move linked tasks back to Open" becomes "Move linked tasks back to 'Backlog'" - the actual first list of that flow state on your board, exactly the one the automation will target at run time. Pick a different board in the wizard and the copy re-resolves; with no board picked yet, the generic flow-state wording stays. New strings in all five locales.
- The weekly timelogs window remembers whether you want suggestions, and maximizes on a double-click. The Sparkle button that shows draft time suggestions now remembers your choice: hide the panel and it stays hidden across sessions instead of reappearing on every open. The little count badge on the button is gone - it was noise - so the button just reflects on/off. And the window's titlebar now maximizes on a double-click (double-click again to restore), matching the floating task windows; dragging it to the top edge to maximize still works as before.
- The board menu is tidier and quicker to reach. It now opens with a quick-action row - four large icon tiles with labels underneath (Pin/Unpin, Clone, Template, Export) that light up on hover - so the most-used board actions are one click away instead of buried in a submenu (the old Duplicate & export submenu is retired now that its actions live in the row). Below the row: Board context and Pin swapped so pinning leads, Agent Workflows moved up under Board flow, and a divider sets the quick row apart from the rest. The Integrations submenu was also flattened - Create intake form, Manage webhooks, and Link repository now sit directly in their own section rather than one level down. Automations is gone - it already has its own board view. Activity dropped into the secondary utilities group just above Subscribe to digests, Create form became Create intake form, and Archive & Trash became Restore tasks. All new and renamed labels are translated across the five locales.
- Personas are now just identity and voice - and there is one Agent node. A persona is who the agent is: a name, an avatar, a one-liner, and a personality that shapes how it writes and signs its comments. What an automation may read or change now lives in exactly one place - the Agent node's capability panel - so the old two-place permission model (persona defaults pre-filling the node, snap-on-select, amber "deviates from persona" warnings) is gone entirely, along with the persona editor's Capabilities tab. The palette's Agents group now offers a single Agent node (the former "Workflow" node, which already had the prompt, per-node capabilities, model, and limits); the old simple Agent node is no longer offered, but existing automations that use it keep rendering (labeled "Agent (legacy)", with a pointer to the new node) and keep running exactly as before - their permissions still resolve from the defaults stored on the persona record. The three shipped AI templates (triage note, milestone retrospective, milestone prep brief) were migrated to the merged node with self-contained prompts and an explicit safe read-only tool set, so they no longer depend on a persona to run - pick one only if you want the voice. Strings updated in all five locales.
- Agent personas are now created, edited, and deleted right inside the agent nodes. The standalone "Agents" dialog is gone from the account menu - a persona is configured where it is used. Open a simple Agent node or a Workflow Agent node in the Automations builder and the management controls sit beside the persona picker: New, Edit, Delete, and Install starter. The editor opens in place (details + capabilities tabs, the avatar picker, and the usage-aware delete that lists exactly which workflows will be disabled), and the picker reflects every change immediately - a persona you just created or installed is selected for you, and deleting the selected one clears the node. Creating, editing, and deleting stays owner/admin-only; everyone else can still pick a persona, the management buttons simply don't render. Prompts and Coding agents are unaffected. Under the hood the read/write capability catalog that was copy-pasted across three files is now one shared module, and the editor's formerly hardcoded English (tabs, capability labels and descriptions, the avatar picker, the whole delete-usage panel) is translated in all five locales.
- Native Git launch packaging now belongs to the Truetask desktop wrapper. The ADRs now record that the existing native-helper code is a reusable protocol and launch-planning core, not a standalone product, and they list the macOS, Windows, Linux, updater, signing, notarization, and release-endpoint requirements needed before broad desktop distribution.
- The board menu's Git actions are now grouped on their own. Once a Git provider is connected, the board menu sets its repository actions apart with a divider. When no repo is linked yet, Link a repository sits alone in that group; once you've linked one, Open repository (now with a link icon) and a new Repository settings shortcut join it - Repository settings switches the board to its Code view and opens the repository-settings dialog directly. New string in all five locales.
- Reviewing a pull request is one code-first surface now - the tabs are gone. The review panel (opened from a board's Git tab or the Reviews inbox) keeps the diff front and center. The old Conversation and Reviews tabs became a compact Activity popover - PR comments and submitted verdicts interleaved on one timeline, with the comment composer right there - and a Review changes button that gathers your pending inline comments (jump straight to any of them, or drop one), a verdict picker, and the summary note in a single popover. The per-file header is now pinned and fully opaque under both scroll axes, so long lines never drag it away and code never bleeds through it; the file list is resizable and tracks per-file viewed state with a progress readout; and j / k walk the files while v marks one viewed, so a whole review can run keyboard-only. Inline comment threads and the composer sit flush with the code gutter (soft fills, no more dashed boxes), stay put while the code scrolls sideways, and pending notes render their markdown. Every icon-only button wears a real tooltip, and the Reviews inbox can now comment and submit reviews exactly like the board's Git tab - the capability is derived from your role on the PR's board. New strings in all five locales.
- The "open in your coding tool" control reads as one split button. The quick-launch half shows the icon of your tool (VS Code, Cursor, Zed, terminal agents, or copy-prompt) and launches it; beside it a small caret opens the tool menu - no more two identical
>buttons whenever the preferred tool happened to be VS Code. The menu marks the current default (launching from the menu makes that tool the new quick action), each tool has its own icon, and both halves carry tooltips. The review panel's header cluster is uniform now - every button the same size and color - and Open on provider wears a link icon across the review panel, the issue panel, and the Git tab rows. - The issue panel got the same polish. Its header matches the review panel (uniform icon buttons with tooltips, the link icon for the provider), and the body dropped its boxed outlines: the description and comment thread read as flat text separated by whitespace - no cards, no backdrops - while the label/assignee/milestone pickers, the state button, and the comment composer are borderless filled controls.
- Cover images in the task window keep their full color. The task window's header used to lay a translucent white or black wash over the cover image to keep the title readable, and the picture paid for it - colors went pale and flat. The wash is gone: the cover now shows at full saturation, and readability comes from the text itself, which picks black or white from the image's own brightness (white text carries a soft shadow on dark covers, and the AI title button adapts along with it). The key, branch, and review pills already sit on their own chips and are unchanged.
- PR and issue rows are borderless everywhere, and the Reviews inbox rows behave. The board Git tab's PR/issue cards dropped their outline ring - the hover fill is the delineation, matching the Reviews inbox look. And in the inbox itself the right side of a row is fixed: the author chip pins all the way to the row's edge, the hover chevron that collided with the coding-tool buttons is gone, and those buttons now surface as a small floating toolbar on its own surface at the row's top-right - clickable, and legible over whatever it overlaps.
Fixed
- Deleting the built-in agent workflow template no longer breaks agent runs. On a board with no workflows of its own, kicking off or starting a run copies the workspace's default "Coding agent workflow" template onto the board - and if that seeded template had been deleted or archived from the template library, the whole agent-run surface failed with a server error, permanently. The API now carries its own copy of the default workflow definition and falls back to it when the template record is gone: the board still receives the standard workflow, and nothing is recreated in the template library, which stays exactly as you curated it.
- The first step in the Agent workflows editor no longer has its outline shaved off. The steps list's scroll region started flush at the top, so the first step card's hairline ring was clipped by the scroll container; a small top inset lets it render fully.
- Copied task Markdown no longer leaks timestamps into its dates. On a scheduled task, Copy as Markdown (previously "Copy as AI context") printed the start and due dates as raw datetimes -
Start: 2026-06-23 12:00:00.000Z- and comment dates and date-type custom fields did the same. All four now copy as clean2026-06-23dates. - The top toolbar's right-side controls no longer drift during page load. While a heavy page was still rendering (My Tasks with a large task list, for example), the search box, timer, agent, notification, and profile controls sat bunched toward the left and only jumped to the right edge once the page finished mounting. The icon cluster is now pinned to the toolbar's right edge on its own, so it holds its place from the first frame regardless of how long the page content takes to load.
- Personas that grant "Add checklist items" or "Set custom attributes" now actually confer them. The backend resolver never recognised the
checklistsandxattrwrite categories the persona editor saves, so a simple Agent node running such a persona silently lacked the matching tools. Both categories now expand correctly (tocreate_checklist_itemandupdate_card) for the tool list and the write-permission gate alike. - @mentions with hyphens no longer split in half. A mention like
@dev-claudeused to render as a chip for@devwith a dangling-claudebeside it - in the comment composers and in rendered comments alike. The full handle is one chip now, and mentions inserted through the picker no longer leak an escaped underscore (Yas\_Opisso) into pending review comments or the text posted to your git provider. - Modal dialogs always open above the side panels now. Commenting or closing an issue from the review/issue side panel while not signed in to the provider popped the "Act as yourself?" prompt underneath the panel, clipping its Connect button. The whole modal layer (dialogs, confirmations, sheets) now sits above the side panels and floating task windows by default, every popover/menu/select moved up with it so nothing sinks under its own dialog, tooltips ride on top, and the act-as guard specifically claims the topmost modal tier so it can interrupt a git write from any surface - including nested dialogs. The automations workflow editor moved up with the layer too, so opening a workflow shows the canvas and nodes crisp on top instead of dimmed beneath their own blurred backdrop.
- A long task description no longer breaks the task window's scroll. On a task whose description was long enough to collapse, the Details tab could scroll far past the comments into empty space - and if you kept going, the whole panel emptied out. The collapsed (and expanded) description box now clips its hidden overflow properly, so the tab scrolls exactly as far as its real content - description, checklists, and comments - and no further. (The culprit was the editor's screen-reader-only tooltip anchor escaping the description's scroll box and inflating the tab's scroll height to the description's full, uncollapsed length.) While in there, the comment composer stopped floating over the thread entirely: it now sits in its own strip below the scroll area, so messages stop just above it instead of sliding underneath and fading out. The comments region also dropped its gray backdrop - the whole Details tab is one continuous surface now, so no color seam ever appears above the composer regardless of where you've scrolled.
v1.3.073
New
- Maximize and snap floating task windows like a desktop app. A task opened in a floating window now resizes the way windows do on your desktop. Double-click its titlebar to maximize: the window grows to fill the screen with a small margin on every side, with a quick animation and a touch of overshoot, and double-clicking again drops it back to exactly the size and place it was before. Drag a maximized window and it snaps back to its previous size and rides along under your cursor, so you can move it without hunting for a restore button first. And drag a window to a screen edge to tile it: a soft highlight previews where it will land, then you let go - the top edge maximizes, the left edge fills the left half of the screen, and the right edge fills the right half. Every adjustment eases smoothly from wherever the window currently sits. Floating windows only; docked and centered task views are unchanged.
- Watch a coding agent work, right on the board - a live workflow progress bar on the card. When an agent is actively running a workflow on a kanban card, the card now shows a compact segmented bar - one segment per workflow step, tinted by state (completed steps green, the active step pulsing, skipped/blocked/failed each their own colour) - with a
done/totalcount and the current step named just beneath it, all advancing in real time as the agent moves through the run. Hover any segment to read that step's name and status. It's a glance, not a wall of steps: the full step-by-step list still lives in the Shift-hover peek and the card's Agent tab. The bar shows only while an agent is live-working and tucks away the moment the run finishes or the agent goes idle, so a settled card returns to its normal look - and the round done-marker stays a plain, interactive checkbox throughout, so you can still complete the card yourself. It stays cheap: only cards with a live agent load their run, and the per-segment tooltip is the same lightweight hover chip the tags use (not a heavyweight component), so the board stays fast with many agents running at once. Reuses the existing run labels, so no new strings. - Manage webhooks from the board, in the Automations view. Webhooks used to live behind a board-menu dialog; now they are a first-class Webhooks tab in the board's Automations view, right beside your Flows. Add, edit, test, toggle, and inspect a webhook's recent delivery logs without leaving the board, with the subscribed events tucked behind a smooth expand. The board menu's Manage webhooks jumps straight to the tab, and it appears for workspace admins on plans that include saved webhooks. The Webhooks panel was restyled to match the Flows list - the same soft cards, green toggles, and hover states - so the two tabs read as one surface.
- Send webhooks with a chosen method and authentication. An outbound webhook can now be delivered with POST, PUT, or PATCH, and can authenticate to your receiver with a Bearer token, Basic auth, or a custom header (an API key, for instance) - picked from a dropdown in the webhook editor, right beside the URL. This is separate from the signing secret: authentication proves Truetask is allowed to call your endpoint, while the signature proves the payload is genuinely from us - many setups want both. Credentials are stored write-only and never shown again (leave them blank when editing to keep the saved value), and the pre-save Test button exercises the exact method and auth you have configured. Available over the API and MCP too.
Changed
- "Automations" are now "Flows". An individual automation is a Flow everywhere in the app - the builder, list, toasts, empty states, Settings, plan copy, and the command palette - because a webhook is not an automation, yet both belong under one roof. The board's Automations view keeps its name and now holds two tabs, Flows and Webhooks; the top + New button follows the tab you are on (+ New flow or + New webhook), and Templates now live inside the Flows tab rather than a separate tab. Renamed across all five locales.
- Webhook deliveries now carry a standard HMAC-SHA256 signature. Every webhook POST now includes an
X-Truetask-Signature: sha256=header - an HMAC-SHA256 of the raw request body keyed by your webhook secret - so receivers can verify authenticity the way GitHub and Stripe do. The olderX-Webhook-Signatureheader is still sent during a transition window so existing integrations keep working; move your verification to the new header when you can. To verify a delivery, computeHMAC-SHA256(your secret, raw request body)and constant-time compare its hex digest against the value aftersha256=. - Webhook deliveries are now durable and sent off the request path. When something happens on a board, the delivery is written to a persistent queue and handed to the server to send in the background, so a slow or unreachable endpoint never delays the action that triggered it (creating a card, moving it, and so on). A delivery survives a server restart mid-flight - it is picked back up rather than lost - and one that fails on a temporary error (a timeout or a
5xxfrom your endpoint) is retried automatically with increasing back-off, while a permanent rejection (a4xx) is recorded once and not retried. Every attempt still shows up in the webhook's delivery logs. - The "blocked by" count pill on cards lines up with the tags beside it. The small amber blocked-by chip was a hair shorter than the tag pills sharing its row; it now uses the exact same box (padding, text size, and height) as the tags and the draft badge, so a card's tag row reads as one clean line across every view - kanban, list, calendar, and the task list.
v1.3.072
New
- Create a coding agent and drop it on the board you're viewing in one step. The Coding agents dialog's create form gains an Add to
checkbox - shown only when you're on a board you can manage, named after that board, and on by default. Tick it and the new agent joins the board as a member (editor) the instant it's created, so you can assign it to a card straight away instead of detouring through Share -> Add member after the fact; leave it off and the agent is created exactly as before. The add is best-effort and never loses the agent - if joining the board fails, the agent still exists and a toast points you back to Share. New strings in all five locales. - Share Board, redesigned - wider, far fewer lines, and agents in their own list. The board's share dialog dropped its stack of bordered boxes (the teams container, the members container, the full-width "Add" buttons, the always-on search field) for one clean pane: each section is a compact header - icon, label, count - with an inline + Add on the right, and people render as borderless hover rows with plain-text roles (the role Select shows only where you can actually change it, and the remove X reveals on hover). The dialog is wider and sizes to its content instead of a fixed tall box - it opens instantly on the members it already knows (no loading screen), then eases its height as the background refresh and any add or remove settle in, so nothing pops - and the filter field only appears once a board has enough people to warrant scanning. Most of all, agents are split out: bot accounts no longer hide among the members - they get their own Agents section (robot glyph, its own count, and an add-picker that offers only agents), while the members add-picker offers only people, so at a glance it's obvious who's a teammate and who's an automated agent. All the sharing behaviour - roles, teams, subscribed/via-team markers, last-admin guards, leave-board - is unchanged. New strings in all five locales.
- A finished agent run no longer vanishes - its steps and log stay on the card for review. The Agent tab used to fetch only the active run, so the moment a run proposed done or ended, the whole step-by-step record disappeared. It now loads the card's most recent run (a new latest-run endpoint), so a completed run stays visible - every step with its result/evidence, plus the run log - with a "Copy kickoff" to start a fresh one. The "current step" highlight only shows while a run is actually in progress.
- The card's Agent tab is a true dashboard now. A run leads with four stat tiles - Status (colour-coded dot that pulses while the run is live), Progress (done count over a per-step segment bar tinted by each step's state), Duration (elapsed time with the start → finish range), and Workflow (click-through to the workflow editor, with the agent as a small caption chip - it is already the assignee and signs the proposal, so it no longer gets its own headline block). Steps and the run log sit in floating cards: steps on a timeline rail with tinted state glyphs and slide-open detail, the log as a divided table with mono kind tags. Live-run controls (retry / skip / reassign / cancel) moved to the dashboard's top-right toolbar. Ready for review, Definition of done and Working context are cards too - DoD and Working context are full-width cards stacked one per row, each showing an always-visible clamped preview that expands and collapses in place with a smooth height animation (their Show more and Edit controls are compact icons - swapped so the expand caret sits at the far edge - so the header never collides with them), and the proposal header carries just the proposer's avatar + time instead of a sentence. The no-run state is a proper empty card with a kickoff button, loading shows a skeleton of the exact layout, and task-list previews render correctly (hanging checkboxes, inline code no longer shredded letter-by-letter). New strings in all 5 locales.
- Hold Shift and hover a card to peek at what its agent is doing. On the kanban board, Shift-hovering a card an agent is working (or has worked) pops a compact floating card with that run's steps - the same timeline rail as the Agent tab, the active step spinning and a live status pill - so you can scan an agent's progress across the whole board without opening each card. It is entirely lazy: nothing is fetched or attached until you actually Shift-hover (a normal card does nothing), the peek is a single shared card that positions itself beside whichever card you point at and follows the cursor from card to card while Shift is held, and it updates in real time while it is open. Reuses the existing run labels, so no new strings.
- The agent workflows dialog got a full pass. The step-key field is gone - keys derive from the step name automatically (deduped on save). Steps are compact collapsible rows that expand with a slide and reorder with the board's displacement drag. The per-step MCP tools picker now offers the complete tool catalog (217 tools, generated straight from the MCP server) as a searchable reference with removable chips - an authoring hint, not a guardrail. Workflows can be created empty from the list header, duplicated, copied to another board (the picker shows each board's icon and folder path), or saved as templates; templates can be renamed and removed; the default is set from the list star and a default workflow can no longer be archived. The In Progress list picker only appears when the board has more than one In Progress list - and selecting a list actually sticks now (the trigger renders its own label and the fallback option uses a real sentinel).
- A kickoff now requires the structured workflow. The delegated-agent contract stopped treating the structured run as optional: on a kickoff, if the agent has the structured agent-run tools it MUST start a run and drive every step (a heartbeat-only fallback is only for tools that lack them), so a kicked-off agent sticks to the plan.
- A working agent now always shows as assigned, and its status reads at a glance. Two fixes to a card's agent presence: an agent that heartbeats now joins the card's members, so "an agent is working" can no longer show with an empty assignee list (a lean heartbeat with no structured run used to stamp presence without assigning). And the no-run presence block dropped its "Heartbeat active / No structured run / Latest heartbeat" stack for one compact line - the agent, and "working" or "active Xm ago" - with the detailed status tucked into a hover tooltip.
- The card's Agent tab reads like a dashboard now, not a wall of markdown. Ready-for-review, Definition of done, and the working-context note each read as a flat section - a small icon-and-label header, no gray card or medallion - with their long content collapsed by default behind a "Show more" - the proposal summary truncates with a fade, the definition of done and the working note expand on demand - so a completed card's Agent tab is scannable at a glance instead of a long scroll. Follows the house design language (flat sections that match the other tabs, an emerald accent for the positive "ready for review" state, and motion on reveal). New strings in all 5 locales.
- Completing a task no longer closes an unmerged pull request - only its linked issues. Marking a card done used to close every linked open or draft PR on the provider (a plain close, not a merge), which could silently drop unmerged work - approving an agent's "done" proposal while its draft PR was still open, or the first of several
ClosesPRs merging and force-closing the rest. Completion now closes only the card's linked open issues; linked pull requests are left alone (a merged PR is already closed, an unmerged one is pending work you merge or close yourself). The per-repo "Close linked issues when a task is completed" toggle and its copy were updated across all five locales to match. - The Agent tab reads cleaner while a run works - the "working now" pulse stays lit, and completed steps collapse. The presence pulse used to decay 5 minutes after an agent's last heartbeat, so a working agent looked idle (and, misleadingly, like it had left the task) between step checkpoints; it now stays live for the whole time a run is active - the backend refreshes presence on every run step-update and log, and the Agent tab treats an active run as live, so the kanban dot and the tab line both keep pulsing. And the run's step list no longer renders each completed step's full result inline: every step is a uniform compact row with its result/evidence collapsed behind a caret, expandable on click.
- The Agent Workflow editor got roomier and clearer - wider step rows, a Step key explainer, and a per-step MCP tool picker. Each step used to spend a fixed column on the drag handle and another on delete, squeezing the fields between them; the grip and delete now sit in a compact per-step header row, so a step's name, key, instructions, and tools span the full width. The Step key field gained a shadcn tooltip explaining what the key is and how to name it (a stable, lowercase, snake_case id used in run logs and progress tracking). Each step now carries an MCP tools picker modelled on the Automations capabilities picker - a searchable popover of Truetask MCP tools grouped by purpose (context & memory, presence, communicate, update, git), each with a plain-language description, stored per step as documentation of which tools that step uses (it does not gate the agent at runtime). And the dialog dropped its third column: Templates fold into the left rail beside the workflow list, handing the reclaimed width to the steps editor. All five locales updated.
- Pinned boards - your daily boards stay one click away, even with the sidebar collapsed. Pin a board from the ⋯ menu next to its title, or from the sidebar tree (right-click or the row's ⋯ menu - the item flips to Unpin once pinned); a pinned row wears a quiet pin marker at its right edge, clear of the space the hover ⋯ button uses. The payoff is the collapsed icon rail: every pinned board renders as its own icon directly under the Boards menu icon - in pin order, each wearing the board's own icon with a right-side tooltip naming it - so switching between working boards no longer means opening the boards menu at all. Selection follows the pin: when the open board is pinned, its rail icon carries the active state and the Boards menu icon stays quiet; otherwise the menu icon shows it, exactly as before. Right-click a pinned rail icon to Unpin or Change icon (the shared board icon grid, live everywhere the icon shows). Pins are personal and sync with your account (a
pinned_boardslist on the preferences record), and stale pins - boards archived, deleted, or left - simply don't render. All five locales updated. - Delegated agents became teammates you can see and steer - they ask blocking questions in the card, pulse while they work, and agree on what "done" means before finishing. Three new channels, all living in the card's Agent tab (now one cohesive surface: Needs input, Definition of done, and the Working context note share the same quiet headers, type, and slide-open reveals). Needs input: when an agent hits a decision it can't make confidently, it calls
cards_ask_question(optionally with choices) and stops instead of guessing; the card flags "awaiting input" and notifies the members, watchers, and the agent's owner. Humans answer right in the Agent tab - options stack as a vertical single-select with an "Enter your own..." row that slides open a free-text field, every option is copyable (handy for pasting into the agent's chat), Dismiss is confirm-guarded, and resolved questions collapse into a history. The signal travels: a violet dot on the Agent tab, a needs-input pill on the kanban card (right of the tags, tag-style hover tooltip, click lands directly on the Agent tab) plus matching chips on the Tasks and List rows, and a new command-center drawer beside the notifications bell that lists every open question across your boards with one-click answer chips (with Undo) and an Open button. Answers wait in the agent's context for its next run - and if you answered it in chat instead, the contract tells it to reflect your decision withcards_resolve_questionso the card clears for everyone. Presence: agents heartbeat (cards_heartbeat, plus an automatic stamp whenever they update their working notes), and the agent's own avatar pulses with an emerald halo on the kanban card while it's live (bleeding over the card edge, not clipped by it), with an "is working - status" line in the Agent tab; the pulse decays to "active Xm ago" and then quietly disappears - no stale green dots. Definition of done: an optional acceptance-criteria field (Markdown) in the Agent tab; when set, the agent's working contract gains a DONE-means-DONE gate - verify every criterion before completing, or say exactly what's missing instead - and when it's not set, the agent is nudged to propose one for you to confirm or edit, so the bar for "done" gets agreed before the finish line, not argued after it. All new strings in five locales. - Agents propose "done", you approve it - draft-PR semantics for finishing a task. When a delegated agent believes the work is finished, it can now propose completion (
cards_propose_done, with a Markdown summary of what it did and how it measures up to the definition of done) instead of completing outright. The card's Agent tab grows a Ready for review section - the proposing agent, its summary, and two actions: Approve & complete (the card completes, attributed to you, and moves to Done) or Decline, which slides open a reason field; the reason lands as a comment on the card and reaches the agent on its next run (its working contract quotes the feedback and tells it to address it, then re-propose). The signal travels like needs-input does: a sky review chip on kanban/tasks/list cards (click lands on the Agent tab), a sky dot on the Agent tab label, and anagent_proposalnotification to the card's members, watchers, and the agent's owner. The loop completes the guardrails story - a complete-restricted agent's 403 and its contract now both point at proposing, so "may not complete" degrades into "hands off a reviewed completion" rather than a dead end - and the DONE-means-DONE gate uses it too: criteria the agent can't verify itself mean propose, not complete. Proposals are agent-only (humans just complete), one pending per card (re-proposing replaces), and any terminal outcome settles them server-side. While in there, agent questions and proposals got proper notification rendering (icon, color, message) in the bell - question notifications previously fell through to a raw default. All new strings in five locales. - Per-agent guardrails - decide what an agent may do on its own, and dial autonomy up as trust grows. Each coding agent's page in the Coding agents dialog gains a Guardrails section: four owner-set switches for whether that agent may complete cards, archive cards, delete cards, and merge pull requests (everything defaults to allowed; switching one off hands that action to a human). Enforcement is server-side for agent tokens on every path - single and bulk updates, the complete action, and moving a card into a Done list (which auto-completes it, so a restricted agent can't sidestep the rule by dragging); a blocked attempt gets a 403 that tells the agent what to do instead - finish the work, leave a comment or a question, and hand off. The agent's working contract states its limits up front, so a well-behaved agent never even attempts them, and merge - which has no API to block - is enforced there as a standing instruction. Self-escalation-proof by construction: the flags live on the agent's account, only its owner (or an admin) can change them, and the agent's own token can't touch them - not through the profile endpoint (field-allowlisted) and not through the record API (frozen at the schema boundary). Humans are never gated. All new strings in five locales.
- Linked vs Referenced git issues & PRs - "this PR finishes the task" and "see also" are different things now, and only the first one drives automation. Every issue/PR on a card is now one of two kinds. Linked means the work IS the card, and it powers a true bidirectional status sync: a linked issue closing or a linked PR merging completes the card (manually-linked artifacts included - previously only closing-keyword matches did anything), and completing the card closes its open linked issues and PRs on GitHub/GitLab/Gitea, echo-safe in both directions so nothing loops. That reverse half is governed by a new per-repository toggle in Repository settings ("Close linked issues & PRs when a task is completed"), on by default, and when it fires you get a toast + notification naming exactly what was closed (or what the provider refused), with a View action that lands on the card's Code tab. Referenced means related context - prior art, a blocker, a follow-up - it surfaces everywhere but drives nothing, guaranteed. Magic-linking now classifies instead of lumping: closing keywords (
Fixes DEVE-12) and branch-name matches create links, while bare key mentions in titles/bodies become references (the automation may promote a reference when a strong signal appears, but never demotes a link - only you do that). The kind is visible and editable on every surface: the card Code tab gets a References section, per-row convert/unlink menus, and a Reference option in both the issue and PR split-buttons; the board Code view grows a Referenced group, dashed reference chips, and a Link/Reference choice in its card picker; the unlinked rail keeps referenced-only items (a reference isn't ownership) with a marker and a "Reference to card" action; and both the issue and PR drawers show linked and referenced tasks separately. Label-to-tag inheritance stays a linked-only behavior. New REST endpoints (/reference,/unreference, plus akindon link) andref_cardsin the MCP payloads. All new strings in five locales. - Checklist items and task cards convert into each other by drag-and-drop. Grab a checklist row by its handle and drop it on a kanban column: while you hover, the row morphs into a dashed preview of the card it is about to become, and dropping creates the card at exactly that spot, carrying the item's title, assignee and due date (the row leaves the source card and progress counts recount on both ends). Drop the row on another open card frame instead and it changes owner - into the precise slot when dropped inside that card's checklist section, appended when dropped anywhere else on the frame ("Move to this card"). It also works in reverse: drag a kanban card onto an open card frame ("Convert to a checklist item") and it becomes a checklist item there - morphing into a row preview while hovering the checklist section - carrying title, assignees, due date and done state; the original card is moved to the trash, so the conversion stays recoverable. Works across floating, panel and centered frames, respects hard WIP caps when a converted item would enter In Progress (full columns refuse the drop with the same ring card drags get), and both sides update optimistically with realtime reconciliation. All new strings in five locales.
- Notes fire automations for their whole lifecycle - updated, commented, published, and trashed, not just created. The Automations palette's Notes group grows four triggers: Note Updated (debounced - autosave writes coalesce into a single event that fires once, about 90-150 seconds after the last edit of a typing session, with
{note.changed}listing what changed), Note Commented (with{comment.message}/{comment.author}placeholders), Note Published (filterable by publication scope, with{publication.slug}/{publication.url}), and Note Deleted. Every note trigger (including the existing Note Created) gains an optional folder filter that matches the folder and its whole subtree, and notes gain{note.url}/{note.status}placeholders. Writes performed by an automation never re-fire note triggers, so graphs cannot feed themselves. - Automations can now update and delete notes - including "append to a journal, creating it if missing". Two new action nodes join Read/Write Note: Update Note appends, prepends, or replaces content on the triggering note, the focus card's linked note, or a note found by name (with an opt-in create if missing for running-log workflows), and Delete Note moves the same target selection to the Notes trash (restorable). Self-feeding graphs (Note Updated editing its own trigger note) are blocked at validation, import, and runtime, same as Note Created + Write Note.
- Note events and cards cross-link automatically. A card created by a note-triggered automation gets a
[[wikilink]]to that note appended to its description (opt-out switch on the node), and Write/Update Note gain a "Link the card" switch that stamps a#cardmention into the note - both flow through the existing note<->card link index, so the pair shows up in Linked notes / Linked tasks like a hand-made link. - @mentions in note comments now notify - in-app, push, and (opt-in) email. Typing
@Namein a note comment or reply resolves against board members exactly like card comments and lands a notification with the note's title that deep-links straight to the note. It honours the same "Mentions" notification preferences as card mentions, never notifies the sender, and never notifies someone the note is hidden from. - Per-note and per-folder permissions - share a note with exactly the people it concerns. Every note and folder gets a Manage access entry (its creator and board admins only): flip Restrict access and pick who can view or edit from the board's members. Restricting a folder covers everything inside it (deepest restriction wins), restricted items show a lock in the tree, and enforcement is server-side everywhere - lists, search, wikilink resolution, backlinks, versions, comments, exports, realtime, collaborative editing sessions, and the REST/MCP surface. Restricted notes stay out of public publications unless the person who published could see them, are invisible to automations unless the automation's author can view them, and admins keep an escape hatch (site owners/admins and the board owner always retain access, so nothing can be held hostage).
- Delegate a task to a coding agent (Phase 1) - personal agent accounts, self-serve tokens, and a "Delegated to" chip. You can now hand a card to a coding agent (Claude Code, a CI runner, or any MCP/REST client) and let it work in git the way a teammate would. Every user creates their own coding agents from the account menu's new Coding agents dialog - no admin access needed - because an agent is owner-bounded: it can only ever reach the boards its owner belongs to (it's pruned from any board its owner isn't on, and from boards the owner leaves), so its token can never touch anything you couldn't. Give an agent a name, @username, colour and avatar, then generate an API token for your coding tool (write-scope by default, revocable, shown once). Agents show up everywhere a person does with a small AGENT badge, and never sign in interactively - the token is their only door; they also can't hold OWNER/ADMIN, and their owner is fixed at creation. Delegation reuses assignment: assign the agent to a card and it auto-joins that board (when its owner is a member), the card frame shows a "Delegated to
" chip, and the agent polls for what it's assigned. Two new MCP tools -git_branches_createandgit_pull_requests_create(draft by default) - let it open a branch and a draft PR named with the card key (e.g.DEVE-123), so the existing magic-linking wires the branch, commits, PR, reviews and CI back onto the card automatically, and it streams progress as comments. Admins get a workspace Settings -> Coding agents oversight panel - every agent across all users, with owner, token count, last-used, search / filters, and a bulk enable / disable (kill switch) / delete - the same manage-without-entering-each-board pattern as Settings -> Automations. Provider-agnostic across GitHub, GitLab and Gitea; the workspace's git credentials never leave the server (the agent pushes with its own). All new strings across five locales. - View preferences, redesigned - one flat panel, a You / Everyone switch, and view tabs you can actually control. The board's View Preferences popover had grown convoluted: your settings and the board's defaults lived in two near-identical tabs, each section carried its own "Use board default" switch you had to flip before touching anything, the default view was a nine-row radio wall, and the whole thing wore boxes and borders the design language retired. It's now a single flat panel: everything is personal by default, and admins get a small You / Everyone pill in the header that re-scopes the same controls to the board-wide defaults - no duplicated sections, no arming switches (touching a control diverges on its own; a quiet reset arrow appears while an override exists and puts you back on the board default). Default view collapsed to one select whose first option is "Board default (X)", and picking a hidden view as your default simply unhides it instead of erroring. Visible views are borderless rows with an eye toggle - the effective default row wears a quiet DEFAULT tag instead of an eye (it's the one tab you can't hide; you have to land somewhere). Code and Automations stopped being unhideable: they were force-pinned "system tabs"; now they're ordinary rows (still availability-gated by a linked repo / board admin), backed by a storage migration - a versioned per-device override shape plus a PocketBase sweep over saved
visible_views- so nothing vanishes from boards configured under the old force-include rule. The board-wide default view still excludes them (members can't land on an admin-only or repo-dependent tab), but hiding them is now your call. A new Tab labels preference (Auto / Show / Hide, device-wide) pins the view-switcher's labels on or collapses it to icons, instead of only reacting to available space. Task open mode moved out entirely, into the board Preferences (paintbrush) popover's Behaviour section - it's an interaction preference (where a click lands a task), so it now sits beside "Assign yourself to new tasks" and "Right panel order" rather than in a panel about the tab strip; its per-view selects show the effective mode (muted when it's just the inherited default), the "Override per click" modifier-key cheat sheet moved into a keyboard-icon tooltip (reference material, not furniture), and that popover traded its cramped edges for the standard panel padding. The view-switcher order now leads with what's used most - the four task views, then Notes ahead of Files (a daily work surface before occasional reference), then Forms and the gated Code / Automations tail - and the popover's You / Everyone pill is sized exactly like the view tabs, so the two switchers read as the same control family; switching scopes eases the panel's height (the connect-a-repository idiom - measured content, no popping), with the two scope descriptions written to the same length so nothing reflows. Picks still apply instantly, but the success-toast-per-click spam is gone (the tab strip updating live is the feedback; only failures toast). And the tab right-click menu was rebuilt from an embedded settings checklist into quick actions about the tab you clicked: Set as my default, Hide, a Hidden views submenu to bring tabs back without opening anything, an admin For everyone group (set as board default, hide / show for everyone), and View preferences… as the bridge into the full panel. All five locales updated. - Collapsing the sidebar now leaves an icon rail - navigation stays one click away, and fully-hidden becomes an opt-in. Toggling the sidebar (the
Bshortcut, the toolbar caret, or the command palette) used to slide it completely out of view, taking all wayfinding with it: switching boards meant reopening the sidebar or knowing the command palette. The collapsed state is now a compact 56px icon rail, the pattern Linear and Slack landed on. The transition is an in-place morph, not a swap: each nav icon is the same element in both states, anchored to the same left gutter, so the panel width animates while labels fade and the icons grow into larger, full-width hit targets - nothing pops, nothing drifts. Rail items keep their active pill, their role/entitlement/visibility gating, and their right-click Visibility menu; notification badges condense into a corner count bubble; a quiet tooltip on the right names each icon. The boards tree condenses into a single Boards item that opens the full hierarchy as a nested menu - the exact pattern of the card's Move menu: folders as submenus, each board wearing its own icon, a check on the one you're in - with New board / New folder / From template / Import in its footer. Creating from the rail (or via the global new-board/new-folder shortcuts while collapsed) opens a small create dialog (name + location folder) that reuses the same creation path as the inline inputs - default lists seeded, straight navigation into the new board - while the expanded sidebar keeps its inline add flow untouched. Prefer the old zero-chrome look? Customize sidebar gains a When collapsed choice - Icon rail (default) or Hidden - device-local like the rest of that dialog, applied instantly even while collapsed. The expanded sidebar is pixel-identical to before, the mobile overlay is untouched, and the getting-started checklist, plan banner, and resize handle simply sit out rail mode. All five locales updated. - One reusable cover picker - colour, upload, or Unsplash - shared by notes and cards, plus favourite notes in search. The note and card cover controls are now a single component: a compact popover to pick a colour (the shared spectrum), upload an image, or search Unsplash, with a customizable trigger (icon + optional label) so it reads consistently in the notes properties strip AND the card frame toolbar. The Unsplash tab is gated: on Cloud it uses a managed key; on self-hosted it appears only when Settings -> Network "allow features that fetch from the internet" is on AND a key is configured. Self-hosted admins get a new Settings -> Unsplash panel (hidden on Cloud, the managed side) that reflects an env-provided key (
UNSPLASH_ACESS_KEY) or lets them enter their own, stored encrypted server-side in a superuser-only collection and never returned to a browser. Choosing a photo downloads it into the cover image (mirroring the existing link-preview cover) and pings Unsplash's download endpoint per their API terms; the whole outbound path honors the offline-first promise - and search results are cached in the browser (self-clearing weekly), so reopening the tab shows photos instantly without re-hitting the API. The popover reads Color / Unsplash / Upload, each tab wearing an icon, eases its height to fit the active tab (the connect-a-repository idiom - measured content, no popping), and opens on the tab matching what's already set (a colour lands you on Color, an image on an image tab). Picking never snaps it shut: colour, upload, and Unsplash all keep the popover open, with the download spinner shown on the photo you clicked - so switching images just moves the spinner - until the cover has actually changed. The two fields follow each surface's nature: on a card the colour and image are independent (both can be set; setting or removing one never touches the other), while a note's cover is one slot (a colour replaces an image and vice versa). The Color tab renders the exact same spectrum grid as the standalone colour picker (a shared component, named-colour header and all), the Upload tab is a proper dropzone-style target (a filled, hover-responsive area that reads clearly in both light and dark, replacing a button that vanished on dark popovers), the photo grid got taller, and the bottom remove action is tab-aware (Remove colour on the Color tab, Remove image on the image tabs). A note's cover is now a rounded banner inset to the note's content column - it shares the title header's exact alignment, so the icon, title, and property buttons sit in the same spot whether a cover is applied or not, and the cover's left edge always lands on theirs. Separately, favourite notes now appear in the command palette under a "Favorite Notes" section, next to favourite cards. All new strings across five locales. - Notes grow up: per-note properties, an outline, templates + a daily note, folder breadcrumbs, and a link graph. Building on the note icons shipped earlier this release, every note now carries first-class metadata and the navigation conveniences people expect from Notion/Obsidian. A compact properties strip under the title exposes a status (draft / in progress / in review / done / archived, as a coloured chip), tags (the very same shared board tag picker cards use, writing to a new
notes.tagsrelation on the shared tag collection - and deleting a tag now prunes it from notes as well as cards), pin and favourite toggles (a real pressed-state toggle group now, and - like the cover control - wearing proper hover tooltips instead of native title hints), and a cover (a curated colour or an uploaded image that renders as a banner above the editor). Pinned / favourited notes float to the top of the browser tree, badged with a pin or star on the row. The editor header shows a clickable folder breadcrumb for nested notes - each crumb expands and scrolls the tree down to that folder. A new Outline panel (beside Comments / History) lists the note's headings indented by level and kept live as you type; click one to scroll the document to it. The browser header gains a templates menu: a one-click Today's note (quick-capture / daily note, titled by date and idempotent - clicking again reopens the same note) plus New from template (Meeting notes, To-do list, Spec, Weekly review, each seeding a starter body). And a graph view visualises the note link network as an Obsidian-style force-directed graph - nodes sized by link count, isolated notes as lone dots, click a node to open it, drag to pan and wheel to zoom - built from thenote_linksindex (note-to-card edges follow once the cross-boundary index lands). The new fields ridenotes.*migrations mirroring the icon field, and every new string is translated across all five locales. - Work-in-progress limits and a Board Flow control center - Kanban's defining practice, finally first-class. Every board is now an explicit flow: a list carries a type - Idle (backlog / not-started), In Progress, Done, or Cancelled - where before only "Done" existed (the double-check column). In Progress is a first-class type now, and every board must keep at least one - open a board that doesn't (older boards, the odd import) and an admin gets a one-time, can't-dismiss prompt to pick an existing column or create one before continuing (editors/viewers are never blocked - they can't change list types anyway). The new Board Flow dialog - from the board's ⋯ menu or any list's menu - is the control center: a four-lane rail - Idle → In Progress → Done, plus Cancelled as a second terminal off-ramp - where each column is a tile you drag (or nudge with the ‹ › chevrons) between lanes, and each lane header carries an ⓘ whose tooltip explains what that state means and how to work with it - and nothing commits until you press Save. You rearrange freely; Save runs sanity checks (a board needs ≥1 In Progress and ≥1 Done list) plus a one-shot summary of how many cards will be completed / cancelled / reopened before applying, while Reset (live only when your draft differs from the board) discards it - and the draft is remembered per board, so closing mid-edit never loses your work. The headline is WIP limits - and they live on the In Progress state, not on individual columns (a WIP limit is a property of the phase, so that's where it belongs). One config on the board caps it two ways at once: the whole state (total cards across every In Progress column) and per person (max in-progress cards per assignee), with one shared mode - Warn (an amber/red
count / limitbadge; never blocks - Trello parity) or Block (enforced client and server: you can't drop, create, bulk-move, or have an automation push a card into In Progress past the cap). Because it's a phase cap, moving a card between In Progress columns is free - only entering the phase is checked. A move is blocked if either hard cap would breach; the column shows the phase total and your owncount/limit; unassigned cards aren't capped per-person (auto-assign automations cover that). New boards default to a gentle per-person 3 / Warn. Every list's column header now wears its flow state as an icon painted in the list's own colour - idle's dashed ring, In Progress's half-circle, Done's check-circle, Cancelled's prohibition - and that icon is the colour picker, so a column's state and its colour read from (and are set on) a single element, replacing the old plain colour dot and the separate fixed-colour state glyphs (and matching the Board Flow dialog's lane icons) - and a collapsed column now carries that same flow icon at the top of its strip (in place of the old plain colour bar), sitting on the exact same line as the expanded headers' icons, so trace across the board and every flow icon lines up whether its column is open or folded. A blocked drag shows a red not-allowed ring mid-drag and the card bounces back with a toast; the authoritative backstop lives in a PocketBase hook, so even a direct write or a cross-tab race can't overflow a hard cap, and a bulk move that would breach one is rejected as a whole batch rather than partially filling. What counts toward a limit is the honest thing - cards that are genuinely in progress (not completed, archived, or draft) - so a Done card parked in a column never inflates it, and setting a limit below the current count just shows the "over" state without ever ejecting cards. Moving a card out of a full column and reordering within one are always allowed. Cancelled is the second terminal, parallel to Done - work that was declined / won't-be-done rather than finished - so it's kept out of WIP and out of throughput, and (like Done) it releases anything it was blocking; it's optional, so no board is forced to have one. On the board a cancelled card reads like a settled one - dimmed (and struck through on the Calendar / Timeline), with a rose "prohibition" mark where Done wears its green check - consistently across the Kanban, List, Calendar, and Timeline views. And every board statistic treats it as terminal, not pending: the Task Summary counts Cancelled as its own number (never folded into Done, never miscounted as Open) and leaves it out of the completion-rate denominator - so deciding not to do work nudges the percentage up, not down; Overdue and No-due-date ignore it (a cancelled card can't be late or missing a date); List distribution's "skip finished" hides it alongside Done; and the Burndown drops it from the open/remaining line (both the live view and the daily snapshot). Blocked is deliberately not a flow type - it's an orthogonal status any card can carry at any stage, and Truetask already models it through task dependencies (a blocked card is "not actionable"). Under the hood all four types run off a single shared "kind" map (active / done / cancelled) across the PocketBase hook, the API, and the UI, and a card's outcome is the pair(completed, cancelled)- so the flow can gain a state without another sweep through the codebase. It's all exposed over MCP too:boards_updategains the phase WIP config (wip_limit+wip_user_limit+wip_mode),lists_create/lists_update'scategoryacceptsin_progress/cancelled, andcards_updategainscancelled. All five locales updated. (Per-swimlane limits, WIP in the List / Calendar / Timeline views, flow analytics - cumulative-flow, cycle time, throughput, card aging - are tracked as their own follow-up cards.) - Picking up a card assigns it to you - and a soft WIP overflow finally tells the person it lands on. Moving a card into In Progress is the moment work is picked up, so ownership now follows the move instead of waiting on an automation a board could switch off. A card that enters an In Progress list with no assignees adopts whoever moved it - enforced in the same PocketBase hook that owns the Done flip and the WIP cap, so it's part of the board's flow, not an opt-in rule. It's additive (a card that already has assignees is left untouched) and sticky (sliding it back out never un-assigns), and it's keyed to a real person dragging: a move made by an automation, the REST API, MCP, or a cron authenticates as the service account and is skipped, so nothing ever self-assigns a robot. Because the mover becomes an assignee the instant the card enters, that card now counts against their own per-person WIP cap - so dragging an unassigned card while you're already at a hard cap is refused up front (client and server) instead of slipping through because the card looked unowned. And the per-person limit in Warn mode stopped being silent: when entering In Progress pushes an assignee past their personal cap, the person who dragged it gets a toast - and if that assignee is someone else (a lead pushing a teammate's card onto an already-full plate), that teammate gets a real in-app notification too, so an overflow you caused for somebody is something they hear about, not a badge they have to spot. Hard mode still blocks the move outright (there's no overflow to report); this only fires on Warn boards. A board can also turn on Require an assignee (a Board Flow toggle, independent of Warn/Block): then dropping an unassigned card into In Progress opens a quick owner prompt - mover pre-selected, pick a teammate if the work is theirs - that shows each person's In Progress load and, on a Block board, won't let you pick someone already at their cap (so a lead sets the right owner instead of hitting a generic error). And the owner now appears on the card immediately, no refresh. All five locales updated.
- The list menu drops its flow-state switches - Board Flow is the one place to set a list's role. A list's ⋯ menu used to carry Set as In Progress and Set as done toggles: a partial (2-of-4-states - there was never an Idle or Cancelled switch), context-free shortcut that duplicated the Board Flow control center and, for done, silently completed every card in the list from a bare toggle. They're gone - the menu is now just Sort by / Board flow / Delete, and Board flow opens the same self-explanatory dialog with the full lane context, the WIP config, and the pre-commit summary of how many cards a change will complete or reopen (the safety the bare toggle skipped). Under the hood this also deleted a chunk of now-dead plumbing - the toggle handlers, two confirm dialogs, and their convert/revert chain - that only existed to serve the switches.
- Automations can target and match lists by their flow state, not just by a specific list - "when a card moves to any In Progress list, do X." This delivers the follow-up promised with Board Flow: every list picker in the automation builder now carries a States group (Idle / In Progress / Done / Cancelled, wearing the same lane icons as the Board Flow dialog) above the board's named lists, so a rule can key off a column's role instead of one specific column - and it keeps working when lists are renamed, reordered, or the board is cloned. Triggers match "any list of that state": Card Moved (From and/or To - fire when work enters In Progress from anywhere, or leaves it for Done) and Card Created. Condition / Filter gain a List state field (e.g. only continue when the card's list is Done). For Each can loop every card across all lists of a state, and the Schedule trigger can scope its run to one. Actions that place a card resolve a state to "the first list of that state, by board order": Move Card, Create Card, Duplicate Card, and Move to Board (resolved on the destination board). Existing automations are untouched - a state is stored as a
state:token alongside plain list names, so name-based rules keep working and Duplicate Card's old "First open list" option is now simply Idle in the unified group (saved configs still resolve via an alias). Available over MCP too: any list field in anautomations_create/automations_updategraph (to_list,list_name,target_list, the schedule filter) accepts astate:open/state:in_progress/state:done/state:cancelledtoken. The four lane descriptors (key + label + icon) now live in one shared module reused by both the Board Flow dialog and every automation picker. All five locales updated. (⚠️ "Idle" is stored as theopentype.) - Admins can hand off password setup the secure way - email a reset link instead of typing someone's password - with a manual fallback for instances without email. Settings → User Directory's edit dialog used to only let an admin set a password directly (so the admin then knew it). Now, when SMTP is configured, it leads with Send password reset email: the user sets their own password on a branded
/auth/confirm-password-resetpage (the email link no longer drops people on PocketBase's unbranded/_/screen), and the admin never sees or handles it. Setting one manually is still one disclosure away - and the only option when email isn't set up, where the dialog says so and links to Configure email. The manual path gains a Generate button (a strong, ambiguity-free random password you reveal and copy once) in both the Edit and Create dialogs, plus a Require a password change on next sign-in toggle (on by default): a user provisioned with a temporary password is gated on a new/auth/force-password-changescreen until they choose their own (pre-filled with the password they just signed in with, so it's a single field). The dialog animates its height when you switch between the reset-link and manual modes, and the confirm-password field stretches open/closed - no popping. Under the hood: aforce_password_resetuser flag drives the gate (set on login and enforced by the root route guard), and SMTP availability is mirrored into the client-readable settings record so the UI picks the right path. All five locales updated. - Notes and tasks now link both ways - and you make the links from the slash menu, no syntax required.
[[note]]in a card and#taskin a note already rendered as clickable links, but they were invisible to each other: a card couldn't tell you which notes referenced it, and a note never listed the tasks it touched. Now every note↔card link is indexed (a new bipartiteentity_linkscollection, kept fresh by hooks on every save, with a one-time backfill of existing content) and surfaced on both sides - a card's Details tab gains a Linked notes section, and a note's sidebar gains a Linked tasks panel. Both are realtime and open the other side in one click, and each shows the union of the relationship (a note that mentions the card and a card whose description links the note both appear). And you no longer need to know the markdown: the editor's slash (/) menu - in notes, card descriptions, and comments - gains Link note and Link task items that open the very same picker the[[and#shortcuts do (they clear the slash query, drop the trigger, and hand off to the existing autocomplete). The cross-link graph is now readable over the API + MCP too -GET /v1/entity-links/card/{id}/notesand/note/{id}/cards, plus thecards_linked_notes_list/notes_linked_cards_listMCP tools, return a card's linked notes and a note's linked cards (the union of both directions, deduped, with soft-deleted/archived entities dropped). Indexing is resolved-only for now (the picker always inserts a real target). Remaining follow-ups, now their own cards on the board: comment-sourced[[note]]links, and the live/card·/boardembeds. (A gnarly PocketBase-goja gotcha surfaced en route -record.get("is a truthy empty object, so naive") if (record.get("deleted_at"))guards silently treated live records as deleted; all date guards now string-coerce.) - Embed a live task in a note -
/Embed taskdrops a chip that stays current. A note could only hold a static text link to a task (#task- the title captured at insert, nothing about the task's real state). The slash (/) menu now has an Embed group with Embed task: pick a task from the very same picker the#shortcut uses, and a compact live chip lands in the note showing its title, status (list), assignees, due date, and priority - kept in sync over realtime, so move the task, reassign it, or shift its due date and the chip updates in place. Click it to open the task frame. It works in every Milkdown surface (notes, card descriptions, comments), shows an unavailable state for a task you can't access or that was deleted, and - because the embed token (!#id) carries the same id a mention does - it's indexed as a note→task link for free, so the embedded task lists the note in its Linked notes panel. Read-only for now (the chip mirrors the task; you edit from the frame). The chip's DOM is cached per task so editing around it never re-flashes the avatars. While here, every inline widget in the editor (the new chip,#taskpills, and[[note]]wikilinks) swapped the browser's nativetitlehover box for a proper shadcn tooltip - one shared tooltip anchored to whichever widget you're hovering, so it matches the rest of the app. The sibling live/boardview block is its own follow-up card. All five locales updated. - Embed a live board view in a note -
/Embed board viewdrops a filtered, self-updating slice of a board. The sibling to the/cardchip: where that embeds one task, this embeds many. The slash menu's Embed group gains Embed board view → a configurator (board · view type · filter, with a live "N matching tasks" count) → and a read-only block lands in the note rendering the matching tasks as a list, kanban, or calendar - switchable inline by the reader - kept current over realtime (cards moving / completing / being reassigned on the real board reflect in the block). Filters are either a built-in scope (open · all · assigned to me · due in 7 days · overdue · completed) or one of the board's saved views (reusing their exact filter, so the embed matches what you'd see on the board). It respects access (a board you can't see shows a no-access state), bounds large boards (caps the fetch and says so), and handles empty / error / loading. Click any task to open its frame. It's the Notion "synced database" move, powered by your real Truetask boards - and it works in notes, card descriptions, and comments. Serialized as a stable token (!=board-id) that round-trips, rendered (like the chip) as a decoration so it never perturbs the collaborative document. Read-only for now (you edit from the task frame). All five locales updated. - A note's comments and linked tasks are one panel now - and it slides. Opening comments on a note popped a side panel in, while the linked-tasks / backlinks lived in a separate always-on strip below it. They're now a single panel, opened and closed together - close the comments and the linked tasks tuck away with them - that slides in and out on the same docked-panel animation the board's Statistics panel uses, instead of appearing instantly. The header gained a close button in its top corner and an icon on the COMMENTS label so it lines up with LINKED TASKS, the Publish button is now a quieter ghost, and the stray divider under the note header is gone. And clicking a comment now reliably scrolls the document to its highlighted anchor every time - it used to silently do nothing when you re-clicked the already-selected comment (only marking it done would jump there), because the editor only reacted when the selected id changed; a per-click scroll token fixes it. Finally the header chrome was tidied: the version-history button moved into the note's ⋯ menu (every menu item now carries an icon - readable line length, version history, move to trash), and the header + sidebar icon buttons swapped their native
titlehints for proper hover tooltips. - A published note's row menu now offers to open or edit the publication instead of "Publish" again. In the Notes browser, a note that's already live - the one wearing the globe badge in the tree - kept showing a plain Publish item in its ⋯ (and right-click) menu, which reopened the dialog as if starting from scratch. That menu now reads the published state and swaps the single item for two: Open published note (opens the public URL in a new tab) and Edit published note (opens the publish dialog already editing the exact publication that covers the note - whether it was shared on its own or as part of a folder / all-notes / selection link, so you tweak the real link instead of accidentally spawning a second one). Each carries its own icon, and notes that aren't published yet (and folders) keep the plain Publish item - mirroring the open/edit affordances the note header's ⋯ menu already had.
- The notes editor tells you how to start again - and the slash menu is one clean list, not five tabs. Two changes to the Milkdown editor behind notes, card descriptions, and comments. First, the placeholder is back: the line your cursor sits on now shows "Write something, or press '/' for commands" - the way Notion does - so the slash command is discoverable instead of a secret. It had been suppressed the moment a note held any content (so a half-written note offered no hint on its blank lines); now it surfaces on whichever empty block you're focused on, and only there - never on every blank line, never inside a list or code block, and never in a read-only view. Second, the slash (
/) menu drops its tab bar (Text / List / Advanced / Link / Embed) for a single, taller scrolling list with quiet section headers, so every block type is visible at once instead of buried a tab deep: Basic blocks (text, headings, quote, divider), Lists (bulleted, numbered, to-do), Advanced (code, table), and the Truetask-native Link to note / task and Embed task / board view. Labels now match what people actually type - To-do list, Bulleted list - and the lines between sections gave way to plain spacing. All five locales updated (and a few stray French accents in the menu - Avancé, Séparateur, Liste à puces - fixed along the way). - Images and video in notes - drop in a picture or embed a YouTube/Vimeo clip from the slash menu. The notes editor's
/menu gains a Media group. Image opens the same board file picker you already use on cards - now with an Upload button built in, so you can add a new picture or pick one already on the board (filtered to images) - and drops it inline as a real image that renders immediately and shows up in published notes too (board files are served by URL, so there's no auth wall for a public reader). Video takes a YouTube or Vimeo link (watch / share / embed / Shorts /youtu.be/ unlisted-Vimeo URLs all parse) and embeds a responsive, click-to-play player - the clip stays hosted on the provider, Truetask never copies it. Both work in notes, card descriptions, and comments; the video rides as a compact!video[…]token rendered through the same collaboration-safe decoration path as the live/cardand/boardembeds (so it never perturbs the Yjs document), with a matching renderer on the public reader. The shared file picker grew opt-inallow_upload/only_imagesso the comment composer is untouched. All five locales updated. - Toggle lists in notes - fold a section behind a caret, like Notion. The notes editor's
/menu gains a Blocks → Toggle item: a foldable block with a ▸/▾ caret, a summary line, and a body that tucks away when collapsed. A fresh toggle shows an Enter a toggle title placeholder and a blinking cursor at the start of the line so it's clear where to type, and the caret stays centered on the summary at any text size. Pressing Enter on a collapsed toggle continues below it rather than tucking new text into the hidden body. Click the caret to open or close it; the open/closed state is saved with the note (and syncs live to anyone editing alongside you, since flipping it is just a one-character text edit). Under the hood a toggle is an ordinary blockquote carrying a hidden Obsidian-style[!toggle]±marker, drawn entirely with view-local decorations - so, exactly like the/card,/board, and/videoembeds, it never introduces a custom collaborative node that could desync the real-time document. Published notes render toggles as native, no-JS(foldable for the reader, with no marker text leaking through). Works in notes, card descriptions, and comments. All five locales updated. - New boards open the List view on a sensible default instead of every column at once. A fresh board used to show the List view with all eleven columns visible and no grouping - title, list, members, priority, tags, due date, start, progress, modified, blocked-by, blocks - which is a wall of columns to land on. Every newly-created board now gets a built-in "Default" view: title, list, members, priority, tags and due date shown (the rest hidden), grouped by list and sorted by title, marked as the board default so it applies for everyone until they pick or pin their own. It's a normal saved view - rename it, edit it, or clear it like any other. The view's name follows the creator's language (English, Spanish, French, German, Portuguese), falling back to "Default" in English for any unset or not-yet-translated locale. This is seeded only for genuinely new boards; boards made by cloning or from a template are left alone, since they already carry whatever views they were built with. (Existing boards aren't backfilled - the default lands on boards created from here on.)
- Copy last week into this one. The Timelogs popup gained a Copy last week button - and a right-click Repeat last {weekday} on any day header - that re-logs a prior period's entries shifted forward seven days, the affordance people coming from Harvest or Clockify reach for on day one. A confirm dialog sums up what's coming (entries, hours, tasks) and lets you untick any you don't want; days a manager has locked and slots that already hold time are skipped and listed (never silently doubled); and the whole batch reverses from a single Undo toast.
- Sub-minute mis-clicks no longer clutter your time. A timer tapped on and off in the same second (or a zero-length manual entry) used to linger as an invisible sliver in the Timelogs calendar - adding nothing you could see, yet blocking Copy last week as a phantom "already logged" clash. Entries shorter than a minute are now treated as if they don't exist across the whole Timelogs popup - grid, day and week totals, CSV export, and copy - matching the rule the Timesheets view already applied (now a single shared threshold). They're ignored, never deleted, so the data stays intact while the surfaces stay clean.
- The stats panel remembers whether it was open. Its placement (floating / docked left / docked right) and floating size + position already survived a reload; now its open/closed state does too - refresh a board and the Statistics panel comes back exactly as you left it, shown or hidden, instead of always reopening closed. Stored per browser like the rest of the panel's layout.
- Folding a stats widget now animates. The board's Statistics panel lets you collapse each widget down to its title with the caret - that toggle was an instant jump. It now slides open and shut on the same quick curve the sidebar folders use, so the widgets below are pushed and pulled through the layout instead of popping, the content settles in with a subtle parallax as the body unfurls (no extra fade - the height reveal owns it), and the caret rotates between states rather than swapping two icons. Snappy by design and reduced-motion aware.
- Connect your code: GitHub, GitLab, and Gitea now link to boards. Truetask talks to your git provider so the work and the code that implements it stop living in two disconnected tools. An OWNER/ADMIN connects a provider once in Settings → Git with a personal access token (self-hosted Gitea/GitLab supported via a base URL - the token is stored in a superuser-only collection and never returned to a client, and outbound calls are SSRF-checked against that one host), then links a repository to a board. From there, branches, commits, and pull requests magic-link to cards by their key: name a branch
DEVE-123-fix-login, mentionDEVE-123in a PR title or a commit message, and that card grows a Code tab showing its linked PRs (with state, CI status, and review state), commits, and a one-click branch-name to copy (you/DEVE-123-card-title). Linking is webhook-driven - Truetask registers the hook on link and dedupes everything server-side - so the card stays in sync with no polling, and every inbound delivery is signature-verified and scoped to the one board the repo is connected to (a PR can only ever touch cards on its own board). Card keys come from a per-board prefix, made race-safe so two cards never collide on a number. - Connect a git provider in one click - sign in with OAuth (GitHub, GitLab, Gitea). Pasting a personal access token works, but it's a chore and the token is you-the-admin's, not the workspace's. Now an OWNER/ADMIN can connect by signing in: pick a provider in Settings → Git, click Connect, approve on the provider, and you're linked. The access token - and its refresh token, where the provider issues one - is encrypted at rest in a superuser-only collection, never returned to a browser, and auto-refreshed before it expires. Self-hosted instances stay fully in control by registering their own OAuth app once, and the setup is guided per provider: the exact callback/redirect URL to copy, the precise scopes, and the provider-specific toggles that trip people up (GitHub's Device Flow off, GitLab's Confidential on, Gitea's Confidential Client) - so you're not guessing across three different consoles. One authorization-code flow drives all three providers behind a single code path, and the public callback is CSRF-protected with a signed, expiring state.
- Act as yourself on GitHub, GitLab, and Gitea - your reviews and comments go out under your name. Until now every write Truetask sent back to a provider - a review verdict, a PR or issue comment, a merge, a new issue, a label or state change - went out as the workspace connection an admin set up, so the provider recorded the service account, not the person who did the work. Now anyone can connect their own account from the user menu's Git provider dialog (sign in with the provider's OAuth, or paste a personal access token - the token path works even when the workspace has no OAuth app), and from then on their write-backs run on their token, so GitHub/GitLab/Gitea attribute the real human. It's the standard two-layer model: the workspace connection still owns webhooks, sync, and reads (the stable service identity that survives people coming and going), while per-user tokens drive the writes that need a face. Connecting also auto-confirms your team mapping - the provider login you just authorized as is bound to your Truetask user - so attribution flows both ways: inbound PRs and reviews already showed you as the teammate, and now your outbound actions go out as you too. Tokens are encrypted at rest in a superuser-only store and never returned to a browser, OAuth tokens auto-refresh before they expire, and because you're acting as yourself you're bounded by your real permissions on the provider - if you can't merge on GitHub, the merge is refused with a clear message (and the offer to fall back to the workspace account) instead of failing silently. Members who haven't connected keep working exactly as before, on the workspace token - nothing breaks, attribution just upgrades the moment you sign in. And you're nudged at the right moment: the first time you take a git action - a review, a comment, a state/label/assignee change, creating an issue, a branch, or a PR - without your own account linked, Truetask asks once whether to act as yourself (connect now) or as the workspace, then remembers that choice for the session so it never nags again. Already-linked members are never asked; the prompt only ever appears for the provider the action actually targets. And an admin who wants hard accountability can flip Settings → Git → Require personal accounts: with it on, the workspace fallback is removed - every interactive git write-back is blocked until the member connects their own account (the prompt drops its "use the workspace" option and only offers Connect), enforced server-side, never silently downgraded. Automations are exempt - they keep running on the workspace identity - and the default stays prompt-then-fallback, so nothing changes until an admin opts in.
- A first-class code-review experience - a resizable drawer, not a cramped panel. Reviewing a PR from a card used to mean squinting at a diff, the conversation, and the reviews all stacked inside a small modal. Now Open review launches a dedicated code-review drawer that slides in from the right and works from any view - the board, Lists, Calendar, or a card frame - so the code sits beside your work instead of burying it. Drag its edge to set the width (remembered per browser), or toggle full screen for a serious reading session. A file tree down the left lets you jump between changed files in a multi-file PR; each file renders as a real unified diff with hunks and line numbers (a zero-dependency parser - nothing leaves your instance), and you can comment inline on any line or hold a whole conversation on the PR. The Review tab authors a verdict - approve, request changes, or comment - with inline notes, posted back to the provider and synced both ways, so a review left in Truetask shows up on GitHub/GitLab/Gitea and vice-versa (with comments marked outdated when the branch moves under them). The card's Code tab is now a clean summary that opens the drawer.
- A board-level Code view - every PR and issue, no manual linking. Boards connected to a repo gain a Code view alongside Kanban/Lists/Calendar. One Sync pulls all open pull requests and issues straight from the provider - no need to reference a card key first - and lists them in one place: PRs open the review drawer; issues open a full detail drawer you can comment / label / assign / close from (below). The headline move is "Make a card": developers see every issue and promote the ones worth doing into a real card on the board's first open list (carrying the issue body and a back-link), so triage flows from "what's filed" to "what we're building" without copy-paste. Promotion is idempotent - a second click returns the existing card instead of a duplicate.
- Create an issue from a card - a real composer, and your tags become labels. The card's Code tab can now file work, not just track it. Create issue opens a composer that looks like the rest of Truetask: a title, a description in the same Milkdown editor you use for card descriptions and comments (no second-class textarea), and a sidebar of Labels, Assignees, and Milestone pulled live from the provider. It opens pre-filled from the card - title, the card's description, and a
Tracked in Truetask: DEVE-123back-link that doubles as the magic-link, so the new issue is bound to the task both ways and never spawns a duplicate card. The standout: the card's tags are offered as labels and, if a tag has no matching label on the provider yet, choosing it creates the label there (with the tag's own color) and records the mapping - so your board's vocabulary and the tracker's finally converge, from either direction. The composer fills instantly from what we already know (title/description) and lets the provider pickers load in the background - no blocking spinner, no layout pop. Every git-connected board now shows the Code tab on every card (not only ones that already have links), with Create issue and Link issue or PR in a toolbar at the top, so filing or linking is always one predictable click away. And the tab is self-healing: opening it reconciles each linked issue/PR against the provider - deletions disappear, states and labels refresh - backed by a real-time issue-deleted webhook, so a card never shows work that no longer exists. - A cohesive Git settings panel. The board's Code → Settings used to stack a couple of mismatched widgets; it's now one Repository settings panel with consistent section headers - Labels & tags and Issue automation - that share the Code tab's visual language. And because creating an issue from a card now materializes its tags as labels, the label-mapping list reads as a clean review/edit surface instead of a from-scratch chore.
- Manage issues from the board - every issue and PR, grouped, with a full detail drawer. The board's Code view no longer hides anything or treats issues as read-only mirrors. Both the Pull requests and Issues tabs now list everything for the repo - linked and unlinked alike - split into Linked and Unlinked groups with counts, so "what's already tied to a task" versus "what still needs triage" is explicit at a glance (and a webhook/
repositorymismatch that could make the Issues tab read "0" while the rail showed the same issue is fixed - the lists agree now). A linked card chip opens that task's frame; clicking an issue opens a new issue detail drawer - the issue counterpart to the code-review drawer, resizable and full-screenable, reachable from any view. Inside: the issue's description and full comment thread rendered as real Markdown, a comment composer in the same Milkdown editor you use for card descriptions (not a second-class textarea), and a properties rail to close or reopen the issue, edit its labels and assignees against options pulled live from the provider, and see its milestone and linked tasks. Every edit - comment, label, assignee, state - writes straight back to GitHub/GitLab/Gitea and updates the board in place (closing an issue drops it off the Unlinked rail; a label change re-tags the linked cards). Issue rows also carry a one-click close/reopen right in the list. Promote-to-card stays one click away; now the issues you don't promote are first-class too. - Live git updates - no more "I created an issue and had to hit Sync". The board's Code view, the Unlinked rail, and the card Code tab now subscribe to the issue/PR mirror over realtime, so the moment a webhook lands (issue opened, PR merged, label changed, comment posted) the open view reflects it - no manual Sync. FastAPI still owns the webhook (verify, normalize, write); PocketBase does the fan-out it's built for, with the same board-membership access rule that gates every other live collection. The webhook callback now also reads the instance's real
PUBLIC_URL. - Provider comments come to you - notifications + a bubbled thread. A new comment on a git issue or PR that's linked to a card now does two things. It notifies the card's members in-app (skipping the comment's own author, mapped via your team mapping), deep-linking to the card - so a Gitea/GitHub/GitLab comment reaches the people doing the work like any other card activity. And it bubbles into the card's own comment thread: the card's Comments section interleaves the provider comments inline, time-sorted with native comments and styled the same, each tagged with its source (
Issue #12/PR #34) and a one-click link to open it on the provider. Read-only on the Truetask side (reply from the issue/PR drawer, which writes back), always fresh (fetched on open), and resilient - a provider that's unreachable just contributes nothing. - Search + filter + collapse in the Code view. A search box filters the active tab live - issues by title and description, PRs by title and branch - and a filter popover (beside Settings) narrows by state, link status (linked / unlinked), label, and assignee (names resolved through your team mapping), with an active-count badge and clear-all. The Linked and Unlinked group headers are now collapsible, remembered per board and tab.
- The Code view, restyled to match the rest of Truetask. The board's Git/Code view carried heavier chrome than the views around it - two bordered header bars, a hand-rolled segmented switcher, and pull requests/issues boxed inside one bordered, divider-striped list. It now speaks the same floating-panel language as Files and Notes: a single quiet header with the repository as a medallion + name (the provider beneath it, and a switcher when a board links several repos) and Sync / Settings as ghost buttons; Pull requests and Issues are now real tabs; the in-view search is the same borderless filled field the other views use; and the filter popover dropped its dividers and bordered chips for soft fills. Every pull request and issue is now its own soft card - a faint floating-card outline that lifts on hover - instead of rows fenced inside a big bordered box, so the list reads as distinct entries with almost no lines on screen. Per-row actions (open review, close / reopen, open on provider) stay tucked away until you hover the card. And the tab counts no longer pop as data streams in: they appear once, after the first load settles, rather than flickering up from zero.
- Webhook delivery is no longer a black box. Code → Settings gains a Webhook card: whether the hook is registered, when a live event was last received ("3m ago" vs "never" - the honest signal that delivery is or isn't reaching this instance), a Test delivery button (asks the provider to fire one), and Re-register (re-points the hook at the current public URL - the fix after moving instances or setting a tunnel). Registration is idempotent across all three providers, and GitLab now subscribes to issue + note events it was silently skipping.
- Triage git issues & PRs from the board - the Unlinked rail. Toggle it from the Kanban toolbar (or a board's Code → Settings) and the view grows a rail listing every git issue and pull request that isn't linked to a card yet - it syncs from the provider on open (and a refresh button), so freshly-filed issues show up. Drag one onto a list to promote it into a task there (the target list shows a dashed drop zone and expands a landing area if empty), or right-click for the full menu - promote to task, link to an existing card, or (issues) mark as duplicate (which closes it on the provider with a note). It's a separate native-drag rail that never touches the kanban's own pointer-based card drag, so dragging can't disturb your card ordering; showing/hiding it slides smoothly - and the rail now carries its own close button in the header (beside refresh) that tucks it away with that same slide, so you can dismiss it without hunting back to the toolbar toggle.
- More reliable webhooks. Re-linking a repo no longer piles up duplicate hooks - registration now finds the existing hook for that callback URL and updates it in place, which also repairs hooks registered by an older Truetask that subscribed to fewer events (so issue events that were being silently dropped now arrive).
- Keep statuses in sync, both directions - git automation triggers, actions, and templates. The automation engine speaks git now. Triggers: PR opened / merged / closed / review-requested / approved / changes-requested, a commit pushed, and CI failed - each with an optional target-branch filter (
release/) so "merged to main → deploy" and "merged to staging → QA" coexist. Actions: comment on the card's PR, merge it, or set its state - mark it ready for review, convert it to draft, close, or reopen (draft maps to each provider's real mechanism: GraphQL on GitHub.com, a WIP/Draft title prefix on Gitea and GitLab). Placeholders like{git.pr_title}fill in PR context. And a kit of one-click templates wires the common bi-directional mappings so cards and code move together: PR opened → card to In Review, card to In Review → PR ready for review, card to In Progress → PR back to draft, card to Done → merge the PR, PR merged → complete the card, PR closed → card back to To Do* - each fuzzy-matching your real list names on install, in all five languages. - Tie git identities to your team - attribution, auto-match, and auto-assign. A new Team mapping panel (Settings → Git, per connection) maps a provider login to a Truetask user. Auto-match scans every login that has shown up on the connection's PRs, commits, reviews, and issues, and proposes the matching teammate by username or email - confirm the list instead of typing it - and you can map anyone by hand too. Once mapped, the board's Code view shows the real person (avatar + name) instead of a raw git handle. Flip on Auto-assign and linking a PR to a card adds its author's mapped user to the card's members, so "opened the PR" and "assigned the work" stop drifting apart. Managing mappings is OWNER/ADMIN; attribution is visible to any board member.
- Agents can drive git over MCP. Twelve
git_*tools expose the integration to agents: list connections and a board's linked repos, read a card's PRs / commits and a PR's full state, post a comment or submit a review (approve / request changes / comment) on a PR, read review threads, sync a repo and promote an issue to a card, and manage user mappings (list, auto-match suggestions, map, unmap). So an agent can pull a card's PRs, summarize a diff, leave a review, or wire up attribution - the same surface the UI uses, board-membership and OWNER/ADMIN gated exactly the same way. - Set an issue's milestone from Truetask - and git authors read as your teammates everywhere. The issue detail drawer's milestone is no longer read-only: pick one (or clear it) from a live list of the repo's milestones and it writes straight back to GitHub/GitLab/Gitea, each provider's own clear semantics handled (null on GitHub,
0on Gitea/GitLab). The issue's description author and every comment author now render through the shared GitUser component - the matched teammate's avatar and name instead of a raw login - so attribution reads the same in the drawer as it does in the Code view. And editing an issue's assignees now refreshes the board's lists immediately, the way label and state edits already did. - Promote a pull request to a card - and choose the list it lands in. The board Code view could turn an issue into a card but not a pull request (the endpoint existed; the button didn't). Now every unlinked PR has a Make a card action too, and both issue and PR promotion are split buttons - one click drops the card in the first open list, or pick any list from the caret - so triaged work lands where it belongs. The Link to a card picker also stopped capping at 60: it now searches the whole board server-side as you type, so every card is reachable on a large board, not just the first page.
- Recover a git connection without losing your links. Settings → Git gains two per-connection actions. Test connection re-checks the stored token against the provider on demand - the manual companion to the health-check cron - and updates the status badge in place. Re-enter token swaps in a fresh PAT without disconnecting: previously the only fix for an expired or rotated token was Disconnect, which cascade-deletes every repo↔board link (so you'd have to re-link everything); now the credential is replaced, the connection repaired, and the links survive.
- Start the work from the task: create a branch or open a PR from a card. The card's Code tab can now begin the code, not just track it. Create branch makes a branch on the provider off the default, named from a configurable template (Settings → Git - placeholders
{user} {key} {number} {prefix} {title}, with a live preview) and copies it ready forgit checkout. Open PR opens a draft pull request from that branch into the default, stamped with the card's key so it magic-links home. And the loop closes the other way too: a PR that saysFixes/Closes/Resolves DEVE-123now completes that card (and moves it to a Done column) when it merges - distinct from a bareDEVE-123mention, which only links. Branch + PR creation works across GitHub, Gitea, and GitLab. - A Reviews inbox - every pull request waiting on you, across every board. A new Reviews view (in the sidebar's personal section) lists the PRs awaiting your review and the ones you authored, across all the boards you belong to - resolved through your team mapping, no manual filtering. Each row carries the PR's state, review verdict, and CI status, and opens the full review drawer in place.
- Timers and Timelogs are now two separate topbar buttons - and the timer popover is rebuilt. Reaching the Timelogs week view used to mean opening the timer popover and clicking through; now a dedicated calendar-check button opens it in one click (great for people who live in their timesheet, or never touch timers), sitting next to an hourglass button for the timer itself - which switches to a filled "running" hourglass and shows the live elapsed time inline whenever a timer is going. The timer popover that bugged you is redesigned to close real gaps: it now lists the tasks assigned to you (not just whatever you happened to track before), with a search box to find one fast and an always-visible Start button on every row (the old one only appeared on hover, so it looked like you couldn't start from the list at all). Each row spells out your tracked time vs. the estimate ("8h 42m tracked / 4h", or "No time yet") so the number isn't a mystery, and the running-timer banner separates this session (big, live) from your total on the task - and always names the task, even one started from a card's Time tab or a task you're no longer assigned to. A footer link still jumps to the full Timelogs view, and the now-redundant in-page Timelogs button on My Tasks has been removed since it's one click away in the toolbar.
- The Timelogs window remembers where you put it. The floating Timelogs week popup now saves its position and size to your browser and reopens exactly where you left it, instead of re-centering every time. On open it re-fits the saved spot to your current window - so if you've since made the browser smaller (or saved it on a bigger monitor), it's pulled back and, if needed, shrunk to sit fully on-screen with a small border on every side (never edge-to-edge like a fullscreen dialog) instead of opening half off the edge; on a phone-sized window it still fills the screen. Only your own drags/resizes are remembered, so shrinking then re-enlarging the window doesn't lose the spot.
- Zoom the Timelogs calendar - "Visible hours" now controls how much of the day fills the screen. The Timelogs settings (the gear in the week popup) split what was one control into two. Work hours still sets your day's window - e.g. 09:00-17:00, the range the grid opens on and auto-expands to catch any stray entries - while a new Visible hours picker (4-24) sets how many of those hours fill the viewport at once. Leave it at 24 and the whole day fits exactly as before (no change for anyone who doesn't touch it); dial it down to, say, 4 and the calendar zooms in - each hour grows taller and the grid scrolls - so a packed day stays readable instead of being squashed into the panel. The choice persists per browser and is covered by Reset to default. (The gear's tooltip is now "Display settings," since that popover also holds Visible days and Capacity.)
- Sharing a board is now a first-class API/MCP action - and assigning a card no longer fails silently. Two gaps closed for agents and integrations. First, the bug: a board's
membersis a computed field (direct members ∪ everyone who gets in via a team), recomputed server-side on every write - so the oldPATCH /v1/boards/{id}with amembersarray (and theboards_updateMCP tool'smembersarg) was silently overwritten and never actually added anyone. Membership now has a proper surface:GET /v1/boards/{id}/memberslists everyone who can access a board with their role (admin/editor/viewer) and source (added directly vs. via a team), andPOST/PATCH/DELETE /v1/boards/{id}/members/{user_id}add (share), re-role, and remove a member - all writing the realdirect_members+member_roleslevers, all board-admin-gated, with guards against orphaning a board (can't remove its last member) and against trying to remove someone who's only there via a team. The MCP server exposes the same flow asboards_members_list,boards_add_member,boards_set_member_role, andboards_remove_member, andboards_updatenow takesdirect_members/member_rolesinstead of the no-opmembers. Second, the trap that made the bug bite: card assignment is not board access. Assigning a user to a card (cards.members) never added them to the board, so an agent that "assigned the work" left the assignee unable to see the card. Now every assignment surface -POST/PATCH /v1/cards, andbulk-manage-members- returns a non-blockingmembers_not_on_boardwarning naming any assignee who isn't a board member, and the MCP tool docs + server instructions spell out the flow: assignment ≠ membership, so checkboards_members_listand add withboards_add_member. - Agents can embed note
[[wikilinks]]without guessing. Notes link to each other with Obsidian-style[[Note Title]]syntax, which also renders as a clickable link inside card descriptions and comments - but an agent had no way to know the exact title that resolves (links match by normalized title within the same board), so hand-typed links risked silently dangling. A newGET /v1/notes/resolve-link?board=&target=(and thenotes_resolve_linkMCP tool) takes a title, path, or even raw[[Target|alias]]markup and returns the canonical[[Title]]to paste, whether it resolves, the matched note, and up to eight close-match candidates for disambiguation. The notes/cards/comments MCP tools now point at it, and the server instructions explain the model: links resolve by title within one board, a wikilink in a note's content becomes a tracked backlink, and the same syntax in a card description or comment renders clickably but isn't tracked. - Fill your timesheet from your activity. The Timelogs week view can now propose the time you forgot to track. A new suggestions engine reads your own board activity for the week (card creates, edits, moves), clusters events on the same card into work sessions - merging back-to-back sessions on the same task into a single block so sporadic edits across one stretch of work don't surface as several adjacent ghosts - leaves out work you've already tracked (including a whole session whose task you logged within 15 minutes either side, since the card-edit timestamps it infers from rarely line up exactly with the clock you logged, so it no longer stacks a ghost on top of an entry for the same task), and draws the remaining gaps as dashed "ghost" blocks right on the calendar - each labeled with the card and the inferred time. Click a ghost - or drag it up/down to move it, or drag its bottom edge (which shows the same up/down resize cursor as a real entry's handle) to resize the duration - and the entry form opens prefilled with that task, day, and start/end (with the usual AI note suggestions), so you confirm and tweak rather than retype; nothing is ever auto-created. A sparkle toggle in the toolbar shows how many were found and hides them for a clean grid, and the visible hours expand so no suggestion is stranded off-screen. It's self-only and honest about its limits: it sees board writes, not reading, meetings, or work done outside Truetask, so it's a memory-jogger that gets you most of the way, not a full reconstruction. Backed by a new
GET /v1/time-entries/suggestionsendpoint - the samelogs_projectssignal the Approvals queue already uses to flag "active this week but logged no time," now turned around to help the worker close that gap. The whole feature is opt-out per workspace - an admin can switch off Timelog suggestions in Settings → Workspace - and a suggestion you've logged stays gone for the session even if you moved or resized it to a different time. - A real progress bar for file uploads. The Files view showed only a spinner on the upload button while files uploaded - fine for one small file, opaque for a batch or a large one ("is it stuck, or just slow?"). Uploads now drive a real progress bar pinned to the bottom of the view - a sticky status bar that overlays the file list instead of reflowing it (so showing/hiding it never nudges the content) - which fills with the actual bytes sent across the whole batch (not a coarse file-by-file count), labels which file of how many is in flight ("Uploading 3 of 12"), shows a live percentage, and clears the moment the upload finishes - and it appears no matter how the upload was started (the header button, the sidebar button, drag-and-drop, or the destination dialog). Because PocketBase's SDK uploads over the Fetch API - which can't report request upload progress - file records are now created over XMLHttpRequest, which exposes byte-level
upload.onprogress, while the existing create-rate pacing and 429 retry are preserved unchanged. - Mark time billable at entry - and new time is billable by default. The add/edit time form (the Timelogs popup and the card Time tab) had no billable control at all, so a worker couldn't say whether their own time was billable - a manager had to fix it afterward - and every programmatic entry (timer start, the API, MCP) silently fell to non-billable. Now both the entry form and the timer's stop dialog carry a Billable toggle (checked by default; the worker unchecks it for the exception) - every surface that captures or edits time exposes it symmetrically - and a server-side default makes all new time billable unless explicitly set otherwise, so timer-tracked hours - the dominant flow - count toward revenue without anyone remembering to flip a switch (an explicit "off", like the unchecked box, is always respected). Because billable is now the norm, the UI flags the exception instead: a muted Non-billable marker on calendar blocks, the entry popovers, and the card Time-tab rows (the manager detail panel adopts the same convention), mirroring how the missing-notes dot flags a gap rather than the rule. The worker's entry popover also gains the task budget line (lifetime tracked vs estimate, red and "over by …" when over) that the manager's view already showed. And notes-required under billable-only mode is now exact - it asks for a note only when the entry is actually billable, instead of always. The control is also fully programmatic:
billableis exposed on the REST create / update and start / stop-timer endpoints and on thetime_entries_create,time_entries_update,timer_start, andtimer_stopMCP tools (omit it to inherit the default-on, or pass true/false explicitly), so agents and integrations are symmetrical with the UI. - Billing policies: time rounding, required notes, and overlap warnings (and a renamed Workspace settings section). Settings → Regional is now "Workspace" (with a fitting icon), home to two workspace policies an admin sets once: Time rounding (off / 6 / 15 min) rounds every duration shown in the Timesheets reports and exports - stored time and invoice revenue stay exact, only the displayed/exported figures snap to the increment; and Notes required (off / billable-only / all) mandates a note when logging time. Notes-required is enforced wherever time is written: the entry form blocks save (with a required mark), the stop-timer prompt asks for a note before it'll stop, and a PocketBase hook rejects note-less closed entries from the API and MCP too - while never blocking a running timer (you add the note when you stop it). And overlapping time entries are now flagged instead of silently inflating totals: the Timelogs calendar marks any block that shares a slot with another (amber warning) and shows an "N overlapping" count by the week total, and the manager Timesheets table flags cells whose entries overlap - hovering the warning icon, or opening the cell, now explains it and shows exactly how much time is double-counted (a destructive banner mirroring the over-budget one).
- Approval compliance: an audit trail and self-approval governance. Approval rows are upserted in place, so each decision used to erase the last - "who approved this week, when, and what did the note say before it was edited" was unanswerable, which is exactly what a payroll dispute asks. Now every approval create / update / delete is recorded to the audit log with before/after snapshots and the acting user, and each queue row gains a Decision history popover that replays that timeline oldest-first (status changes, note and reply edits, reopens). Self-approval - a manager signing off their own week - is now both visible and governable: a week a manager approved for themselves wears a Self-approved badge, and an OWNER/ADMIN can switch on Approval policy → Block self-approval, which refuses server-side any decision where the deciding manager is the timesheet's owner (off by default). True to the rest of the model, none of this makes a decision un-doable: the reopen-request flow still applies, so a contested approval stays auditable rather than frozen.
- Bulk approve and period close for managers. Month-end no longer means clicking Approve down the whole queue. When weeks are awaiting a first decision, the Approvals header shows Approve all - a confirm dialog sums up the scope (n timesheets · n people · total hours), lets you also approve the empty weeks (skipped by default), and signs them off in one sequential pass with a live "Approving 4/12…" indicator; a week that fails to save is reported at the end, not fatal to the rest. Close period… is the same engine with a cutoff date ("only weeks ending on or before {date}"): it approves and locks everything through that date for the selected people - and, true to the rest of our approval model, a closed period stays contestable, since workers can still file a reopen request, so a disputed close is auditable rather than impossible. (Bulk actions operate on the loaded date range - set the range to cover the period you're closing.)
- Daily totals and capacity targets in the Timelogs calendar. Each day header now shows that day's logged total under the date, and the week Total reads against a target - "32:00 / 40:00" - so "did I log a full Tuesday?" no longer means eyeballing block heights. Set your daily target in the Timelogs settings (defaults to 8h/day → 40h/week, stored per browser; set it to 0 to hide targets entirely). A day - or the week - tints emerald once you hit the target and amber when you go well past it (overtime); still-under-target stays neutral, so a normal mid-day isn't nagged, and weekends carry no target. Every colored figure also spells out its state in its tooltip and aria-label ("6:30 of 8:00 - under target"), so the meaning never rides on color alone.
- Your running timer now shows up in the Timelogs calendar - live. The week view filtered out in-progress entries, so the one surface built to show "my day as blocks of time" pretended your active timer didn't exist. Now a running timer appears as a distinct emerald block in its day's column, growing from its start time to now on a one-second tick with a pulsing live dot - sourced from the global timer state, so it shows up the instant you start a timer (from anywhere) and clears the instant you stop. It has no drag or resize handles (you can't reshape time that's still being counted), and its popover offers a single Stop button - plus a jump-to-task - that opens the same note-capture prompt (with AI suggestions) the topbar timer uses, so you record what you worked on before it settles into a normal block. The week Total keeps live and logged time honest and separate: "4:30 + 0:23 running".
- Finish your week and hand it in - Submit for approval. Until now approvals were manager-pull: a week with no decision simply sat in the queue as "Pending", which meant nothing - it was the default state, not a statement that you considered the week done. Tools people migrate from (Harvest, Clockify, Everhour, Tempo) are worker-push - you finish, hit Submit, and the manager reviews what was explicitly handed in. Now the Timelogs status bar carries a Submit for approval button whenever a week has logged time and hasn't been handed in yet; one click marks the week Submitted - its own sky pill on both sides of the loop - and drops it at the top of the manager's Approvals queue under a new Submitted tab, ranked above plain pending and counted in the pending-review badge. Resubmitting a week after a changes-request now lands in that same Submitted state, so the queue shows every week a worker has actually handed in - fresh or fixed-and-returned - in one place instead of scattering resubmissions back into the default bucket. Submitting doesn't lock the week (you can keep editing until a manager decides), and an empty week has nothing to submit. The whole action is available over the API and to agents over MCP (
timesheet_approvals_submit). - The timesheet approval loop now reaches you - notifications on every step. Until now the loop only updated windows that were already open: a worker never learned their week was approved or that changes were requested unless the Timelogs popup happened to be up, and a manager never learned of a reply, resubmission, or reopen request unless the Approvals queue was on screen. Now every status change sends a notification. Workers are told when a manager approves, rejects, or requests changes on their week (or a single day); managers are told when a worker resubmits a week for review or requests to reopen a locked one. Each notification names the period ("the week of Jun 8 - Jun 14" or a specific day) and quotes the note, and clicking it deep-links straight to where you'd act: the worker's Timelogs popup opened on that week, or the manager's Approvals queue. Self-approvals don't notify, and a plain note edit that doesn't change the decision stays quiet.
- Paint to log, drag the edge to adjust - the Timelogs grid learns the two calendar gestures. Press an empty slot and drag vertically to paint the exact start-end range a new entry should cover (15-minute snapping, works upward or downward), and release to get the entry form prefilled with the painted times - opening beside the painted range (flipping to the column's other side when space is tight), never on top of it. The painted range stays marked on the grid the whole time the form is open - it follows date and time edits live, and only clears when the entry is saved (replaced by the real block) or the flow is abandoned. The form itself keeps a fixed footprint - the AI note-suggestions area is reserved up front (hint → loading → results → a quiet "No suggestions") - so the dialog never jumps around the screen while suggestions stream in. The task picker is a proper combobox: the "Include completed" filter sits inside the search dropdown itself (it reveals done tasks you're assigned to or logged time on recently), and completed results wear a small badge so you can tell them apart. Every unlocked entry block also grows a bottom-edge resize handle: drag it to stretch or shrink the entry with the same snapping and a 15-minute minimum. And because a misdrop shouldn't silently rewrite times, moving or resizing an entry now shows an Undo toast that restores the previous times - matching what delete already did. Locked days refuse all three gestures and say why; the form remains the full keyboard-accessible path.
- The Approvals queue now shows who DIDN'T log time. Every selected person appears for every week in range - weeks with no logged time become "No time logged" rows (dashed badge, em-dash total) with their own "No time" filter tab. Each missing week is cross-checked against the person's board activity: "{n} board actions this week - but no time logged" flags someone who worked without tracking, while "No board activity either - likely away" suggests vacation. Empty weeks can still be approved (signed off) directly.
- Locked time can be contested - the reopen-request flow. Corrections to approved time are inevitable, so workers now have an undeniable channel: from a locked week or day, "Request changes" (with a required reason) flips the period to a new Reopen requested state. The period stays locked until a manager either reopens it for editing or keeps it approved - both one click in the Approvals queue, where the request arrives with its own violet pill, its own filter tab, and the worker's reason quoted.
- Approvals update live on both sides. The Approvals queue and the worker's Timelogs popup now subscribe to changes: a manager's decision appears in the worker's open popup without a refresh, and a worker's reply or resubmission lands in the manager's open queue the moment it's sent.
- Approvals now work per week or per day. A manager can still decide a whole week at once, but every week row in the Approvals queue expands into its days - each with its own total, status, and actions - so a single disputed Wednesday can be reopened or rejected while the rest of the week stays approved. A day's decision overrides the week's for that day; making a fresh week-level decision supersedes (and clears) that week's day decisions. The scope is now always spelled out: queue rows read "Week of Jun 8-14", the worker's chip popover says "Applies to the whole week", and day threads say "Applies to Wed, Jun 10 only". Day decisions show up in the worker's Timelogs as colored dots on the day headers - pulsing when they await an answer - each opening its own reply/resubmit thread, and the data-layer lock honors the same day-over-week precedence.
- The timesheet approval loop now has two sides. Workers see their week's approval status right in the Timelogs popup as a status chip next to the week label - with a small ping when a request awaits an answer. Clicking the chip opens the whole conversation in place (no layout-shifting banners): who asked, their avatar, the week, the note, your reply, a reply box, and a "Resubmit for review" button that returns the week to Pending. Since requests apply to a week, every entry popover in that week also shows the request - avatar and all - right above the edit form, where the fixing actually happens. Managers see worker replies threaded under their request in the Approvals queue, and every fresh decision starts a clean round.
- Approved weeks are truly locked. Approving a week now locks its entries at the data layer - edits, deletes, and new entries are rejected server-side no matter which surface tries (app, REST API, or agents over MCP), with one humane exception: a running timer can always be stopped. The Timelogs popup greys its editing affordances and says why, instead of letting a save fail.
- Timesheet approvals are live. The Approvals tab joins Table, Chart, and Calendar in the Timesheets view: managers see one row per person per week with its logged total, and can approve (locking that week's entries against edits), reopen, or request changes with a note the person sees. A pending-count badge on the tab shows how many weeks await review.
- Estimates vs actual in Timesheets. Now that tasks carry time estimates, the Timesheets report finally shows how reality compares: task rows in the table get a budget pill, the summary strip gains an "Est. vs tracked" card rolling up every estimated task in view, the detail panel shows the task's budget next to the day's entries, and CSV exports add an Estimate column next to the range total when grouped by task. The tracked number is scoped to the selected date range - matching the rest of the report - so an estimated task reads against the time logged in that window, not a lifetime lump sum. But over-budget is a lifetime judgement: a task whose all-time tracked time exceeds its estimate is flagged red with a warning even when little or nothing was logged in the window you're viewing (so an overage racked up in an earlier week is never hidden by a narrow date range), and the summary card counts how many estimated tasks are over budget. The task's own Time tab still shows the full all-time budget burn.
- Timesheets remembers how you like it. The selected view (table/chart/calendar), table grouping, hide-inactive toggle, chart grouping and style, the 0:00/0.00 time format, and the date preset now persist across reloads. Named presets re-resolve to current dates - a remembered "This week" means the current week - while custom ranges restore their exact dates.
- Boards have icons now - pick your own. Every board carries a Phosphor icon (default: a kanban glyph), shown in the sidebar tree and next to the board title so board rows finally line up with the icon-bearing nav items. Board admins can change it from the board's context/⋯ menu in the sidebar or by clicking the icon beside the board title - a compact picker of ~48 curated icons (Kanban, Rocket, Code, Palette, ChartLineUp, …). The choice is stored per board (
boards.icon) and syncs everywhere it appears. And when the active board sits inside a collapsed folder, that folder now shows a small accent dot (left of the caret) so you can tell where you are without expanding it. - Cloning a board can bring your view, not just the board's defaults. The Clone dialog gains an Include my view preferences toggle. With it on, the clone opens the way you have the source board set up - your default view tab, the tabs you've hidden or shown, and the saved view you've pinned for yourself - instead of only the admin-set defaults the clone already carried. Because a clone drops you onto the new board instantly, it now matches your working setup from the first paint. It's strictly your own preferences: the pinned-view carry is scoped to you, and it never changes what teammates see on the clone.
- The card comment box is now a floating composer that gives the whole thread back. The always-open composer used to eat ~40% of the comments panel just sitting there empty. It's now a floating action button pinned to the card frame's bottom-right; click it and it morphs into a docked composer - the surface unfolds from the corner while the paper-plane flies from the FAB into its place on the send button (a real shared-element hero, with an arc and a little overshoot, not a fade). Everything you had is intact: the same Milkdown editor, @mentions, and attachments. Enter sends and keeps the composer open, so you can fire off several comments in a row; Shift+Enter still adds a line. Click away or press Esc to fold back to the FAB (which keeps a dot when you've got an unsent draft) - and it won't fold while you're picking a file or dragging one in. The attach button gained a menu: add files from your computer or from the board - a new picker that browses the board's files (folders, search, multi-select, thumbnails) so you can re-attach something already here without re-uploading. Honors reduced-motion.
- Settings → Git, tightened up. Linking a repository to a board now has one home - the Link a repository wizard - instead of two: the Connections list dropped the inline repository/board picker that duplicated the dialog, and the list refreshes in place the moment you link from the wizard (no reopen). Team mapping is now expanded by default - one less click to map a teammate - and restyled to match the rest of the app: the heavy bordered card is gone in favor of quiet spacing and a single light row divider. And Connected repositories is renamed Linked repositories, consistent with the "Link" verb the panel already uses everywhere else (translated across all five languages).
- A cleaner, more capable Notes browser - with custom note icons. The Notes side panel got the same care the sidebar already had. Folders expand and collapse with the sidebar's slide animation instead of snapping, and when the open note lives inside a collapsed folder a primary dot marks it - scaling in with a soft overshoot, just like the sidebar's active-board marker. The chrome is quieter throughout: the stacked dividers around the header and search box are gone (the search is now a borderless filled field), rows breathe with a small gap instead of sitting flush, hover and active states use the same accent fill as the sidebar, the empty state drops its dashed box, and every browser icon now matches the sidebar's size. New: notes carry their own icon - click a note's icon in the tree (or beside its title in the editor header) and pick from a document-forward set in the same icon picker the boards use, hover-to-reveal exactly like changing a board's icon - and the chosen icon is kept when you rename a note inline (the field no longer reverts to a generic document glyph). (Notes were already searchable from the ⌘K command palette; that stays.)
Improved
- Adding a card between two cards now eases open instead of snapping in. Clicking the + on a Kanban card gap used to swap the dashed divider for the title input in a single frame - the field appeared at full height and shoved the cards below it down in one jump. The input now grows into the gap: the slot's height animates from zero so the cards under it slide down to make room, the field fades in and settles a couple of pixels into place, and blurring, pressing Escape, or submitting runs the same motion in reverse so it collapses away rather than vanishing. It reuses the same fast, reduced-motion-aware reveal the sidebar sections already animate with. No new strings.
- A card's agent status is one chip now, not two mismatched badges. The needs-input pill and the ready-for-review chip were separate components that sat side by side and shared no look - the review one a solid sky block with a bare "review" word that read like a status tag, the input one a soft violet icon-and-count pill. They collapse into a single agent chip that carries the card's one agent-attention state: a soft-tint pill built on the exact tag recipe, so it sits at the same height as the tags beside it and fits the row instead of towering over it. It's icon-led and compact - violet with a chat glyph and the open-question count when an agent needs input, sky with just an eye glyph (no word, its label lives in the hover tooltip) when it has proposed the task is done. Needs-input wins if a card is somehow both, since a blocking question is the more urgent action. One glance tells you whether an agent wants input or a review, in a single slot, identically on the kanban card, the Tasks row, and the List row. No new strings (reuses the existing chip copy).
- The task frame's tab bar now fills the frame instead of huddling on the left. Details / Files / Time / Activity / Code / Agent used to be hand-rolled buttons pinned to the left edge, so widening the frame just grew the empty space beside them and narrowing it changed nothing. They are now the app's standard tab component rendered as a full-width segmented control - equal-width segments in the same compact tray-and-pill styling as the board's view tabs (matching font size and height) that stretch or compress with the frame. Each label truncates gracefully once its segment gets tight, and below a narrow threshold the strip collapses to evenly-spaced icons (the active tab keeps its pill throughout), so the bar stays balanced from a wide centered modal down to a slim docked panel. Being real tabs, they also gained arrow-key navigation and proper tab semantics the old buttons never had. The metadata block above the bar (members, dates, tags, dependencies) shed its grey fill and the divider that ran against the tabs at the same time, leaving a single hairline under the card title so the whole header reads as one open surface.
- Dragging a floating frame is smooth no matter how much it holds. Moving a frame - most noticeably the Timelogs popup with a full week of entries on screen - used to stutter, because every mouse movement repositioned the dialog via layout properties, forcing the browser to re-lay-out and repaint the frame's entire contents dozens of times a second. Frames now move on the GPU compositor while you drag - a
translatedelta that never touches layout, promoted to its own layer only for the duration of the drag; at rest the frame stays transform-free, so viewport-anchored overlays inside it (like the Timelogs entry-drag ghost) keep their coordinates - and movement is coalesced to one update per display frame (Safari and high-polling mice could deliver more). Dragging is now just sliding a rendered layer around - the same cost whether the frame holds a card or a thousand-node time grid. Resizing still re-lays-out the contents by nature, but it rides the same per-frame coalescing. - Opening a task no longer jumps around while its pieces load. The frame's Details area (description, checklists, linked notes, comments) used to render each section the moment its own fetch landed, so the first few hundred milliseconds of every open were a cascade of reflows: the description editor mounted and shoved everything down, checklist items landed and pushed the comments, a linked-notes section popped in above the thread. The stack now lays itself out invisibly while the sections load and fades in once, as one settled unit, the moment every section has reported in - typically well under 300 ms, with a safety cap so one slow query can never hold the tab blank (anything still missing simply fades in on its own when it arrives). The fade is opacity-only and brief: content appears in place, nothing slides, scales, or pushes. The Details tab also stays mounted while you visit Files / Time / Activity, so switching back is instant - no refetch, no re-jump, and an in-progress description edit keeps its editor state. The last holdout was the comment bubbles themselves: each one used to boot its own read-only Milkdown editor, so bubbles painted as empty pills and filled in one by one as each editor finished (~a second of trickle on a 30-comment thread). Comment bodies now render through the same synchronous markdown viewer the AI chat uses - full-size text in the first frame, zero editor instances - and the viewer learned
[[wikilinks]]so note links in comments stay clickable pills. Form descriptions (builder preview and the public form page) shared the renderer and get the same instant paint. - A locked automation node now takes you to the plans instead of being a dead end. A plan-gated node in the automation palette wore its crown and a "Requires Pro/Team/Enterprise" tooltip, but that was the end of the road - there was nothing to click, so upgrading meant finding Settings → Plan on your own. Tier-locked nodes are now clickable: the tooltip adds a "Click to compare plans" hint and clicking the node opens the Plan view directly, mirroring the upgrade link every other gated surface (Timesheets, Overseer, saved webhooks) already had. AI-availability locks ("Requires AI on your plan") stay informational, since those are about configuring AI, not buying a tier. All five locales updated.
- The Forms view's card actions grew real tooltips and an unmistakable Open button. The per-form action row (active toggle, insights, automate, edit, duplicate, delete) and the share-link row leaned on the browser's native
titlebubbles - slow to appear, unstyled, and unlike every other toolbar in the app. All of them now use the standard app tooltip (same 300ms reveal the Files view's toolbar uses), and the launch action stopped being a mystery-meat ghost icon: it's a labeled primary Open button on the share row, so the most common action on a finished form reads at a glance. The generic "Copy" label also gained a real translation key (it was silently English in all locales wherevert('copy')was used); "Open"/"Copy" shipped in all five locales. - A note's Version history panel now reads like the card's activity feed. The history dock had its own heavier look - ring-wrapped avatars stacked on two-line rows - that clashed with the Linear-style timeline the card's Activity tab moved to. It now speaks the same language: a hairline spine threads small glyph nodes (each node's fill masks the line, so it reads as connected dots rather than a rail behind the text), and every snapshot is one flowing line - the author is the only emphasised token, trailed by the muted change summary (+N −M lines, Original version, Edited), with a small timestamp pinned to the row's right edge that reveals the full date on hover. The markers carry the feed's colour rules too: the current tip pops primary, the original snapshot gets the green plus, AI edits keep a violet spark, automations a violet bolt, and routine edits stay quiet pencils. Rows still expand in place to restore a snapshot - the whole row is the click target now, not just the text block - and the panel sits flatter and denser, so a 70-version history scans instead of scrolls.
- A checklist item's assignee dropdown now matches the card's Members picker exactly. Assigning someone to a checklist item opened a one-off list - bare avatar-and-name rows, a search box that only appeared past six members, and none of the board roles the card's own Members field shows. It now renders the same shared member picker the card frame uses, so both wear the identical search box, role labels (Owner / Admin / Editor), and AGENT badge, stay open as you toggle several people in a row, and scope to the board's members the same way. One component, one behaviour, whichever surface you assign from.
- The Time tab reads as one surface again. The timer + stats + budget header carried a full-width divider line under it, boxing it off from the entries below; that line is gone, so the header flows straight into the time-entry table (the dashed budget rail stays).
- The notifications pane uses the same tabs as the agent command center now. Its filter row was an icon-only strip that slid the active filter's label open on click - a different idiom from the labelled tabs the agent command center shows right beside it in the top bar. It now matches: text-label pills with a live per-category count (All, plus Comments / Assignments / Mentions / Due dates / System), the active one filled with the same soft
bg-accenttreatment rather than a heavy solid block. A category tab only appears once it holds something, so the bar stays compact, and if the filter you're on empties out it falls back to All instead of stranding you on a vanished tab. The labels ship in all five locales (previously hard-coded English, since only one ever showed at a time).
Security
- Public form uploads are now type-checked - no more arbitrary files dropped through a public URL. A public form's file field accepted any file type (up to 25 MB), and uploads are served from the app's own origin - so a submitted
.htmlor.svgthat a teammate later opened from the card could run script in their session (stored XSS). Anonymous uploads are now restricted to an allowlist of inert document, image, and archive types (PDFs, Office/text docs, common images, zip); active/renderable types (.html,.svg,.xml,.js, …) are refused with a clear message before the body is even buffered. The allowlist is overridable per deployment viaFORMS_UPLOAD_ALLOWED_EXTENSIONS, and the dangerous set stays blocked even if you widen it. - Public-form rate limiting now holds across API instances. The per-IP submission/upload cap lived in one process's memory, so the moment the cloud runs more than one API replica each replica enforced its own window - multiplying the real quota by the replica count. The window now lives in PocketBase (a locked-down
form_rate_eventsledger that only the API can read, swept by a 15-minute cron), so the cap is workspace-wide no matter how many API instances are running. Self-hosted single-instance behaviour is unchanged. - One public-form submission can no longer attach unlimited files - or files it never uploaded. Each upload was size-capped (25 MB) and rate-limited, but a single accepted submission could still reference an arbitrarily long list of file ids - and any file ids, not just its own uploads. Submissions are now capped at 10 attached files (overridable via
FORMS_MAX_FILES_PER_SUBMISSION; the public page blocks over-cap picks at selection time with a clear message, and the server 422s whatever sneaks past), and the submit path only attaches ids that resolve to recent anonymous uploads - a crafted submission pointing at pre-existing workspace file ids just gets them silently dropped instead of grafting someone else's attachment onto a public card. - Form view/submission counters stopped losing counts under concurrent traffic. Both bumps were read-modify-write (fetch the count, add one, write it back), so two simultaneous visitors could read the same value and one increment vanished - the same insights that already divide by a refresh-inflated view count didn't need the denominator quietly shrinking too. Both counters now use PocketBase's atomic increment modifier, so every view and submission lands exactly once no matter the concurrency.
Fixed
- Deleting a coding agent no longer fails with a 500 once it has actually worked. An agent that had ever run a workflow, asked a question on a card, or saved a board view was the target of a required database reference, and PocketBase refuses to delete a record something still requires - so the delete threw a 500 and the dialog showed a bare "Failed to delete the agent". Deleting an agent now cleans up first, in one transaction: its own workflow runs are deleted (cascading their steps and logs), and everything it authored (saved views and filters, dependencies, forms, note publications, git connections and repositories, card questions) is handed back to its owner - the human accountable for it - so the required reference stays valid and no content is lost. The confirm dialog now says what will happen up front (removed from every board, its runs deleted, anything it created reassigned to you), in all five locales.
- Acting in the Agent workflows dialog no longer reloads the whole dialog. Every action - creating a workflow, setting the default, duplicating, archiving, promoting to a template, renaming or removing a template - called one
load()that flipped the dialog into its full-screen loading spinner and refetched both lists, so a small change flashed the entire two-column layout and reset the editor pane (dropping any unsaved edit). The loaders are split by section now: a workflow action refetches only the workflow list, a template action only the template list, and the full-dialog spinner is reserved for the initial open - so each action refreshes just the section it touched, and a template change (rename / remove / promote) leaves the workflow editor and its unsaved edits untouched. - Linking or embedding a task in a note no longer offers deleted tasks - and reopening the picker can't re-insert the previous pick. The note editor's task picker (the
#mention and the slash menu's Link to task / Embed task) queried every card that wasn't archived - including soft-deleted ones, which actually dominated the "recent" suggestions because trashing a card bumps its updated stamp - so the picker happily offered a task whose chip then opened to "This card was deleted." It now excludes trashed cards and other people's drafts. Closing the picker also clears its results and cancels the in-flight search: reopening it used to re-show the previous session's list until the fresh search landed, so a quick Enter or click re-inserted the task you picked last time instead of the one you meant. While the first fetch is pending the popup says "Searching..." instead of flashing "No matches found", a superseded search can no longer overwrite a newer one's results or blank the list, and a popup with nothing to pick now closes on Enter instead of swallowing the key (a no-match search used to eat every following Enter and leave the editor feeling stuck). Card-embed chips, the card opener, and the dependency views also share one soft-deleted check now - one that tolerates the Go zero date, so a live card can never be mistaken for a deleted one. - The Note Created automation trigger never fired - a truthy empty date guard swallowed every event.
record.get("deleted_at")returns a truthy object in PocketBase hooks even when the date is empty, so the trigger's tombstone check rejected every newly created note. String-coerced; Note Created graphs now actually run. - The self-hosted contact form actually sends your request now. The Plan view's "Self-Hosted / Enterprise" contact dialog showed a friendly success toast - and dropped everything on the floor: the email, phone, and message never left the browser. Submitting now relays through the instance (
POST /api/manage/plan/self-hosted-contact) to the Portal's public self-hosted request endpoint, which records the request and notifies sales by email; the submit button shows progress, a failed send surfaces a real error toast instead of a false success, and demo mode declines up front like every other outbound action. The relay also attaches non-sensitive, server-derived instance context - the Cloud workspace id, site mode, plan slug, seat count, instance URL, and install date - so the sales follow-up can be prepared (who is asking, how big, how long with us) instead of starting from a bare email address; the dialog's note says so, and the Portal-side rendering of that context ships with the Portal follow-up card. While in there, the entire contact dialog - field labels, the topic cards, the reason placeholder, the reassurance note - was finally translated (it was English-only in Spanish, French, German, and Portuguese), and the form's footer tray was replaced with a plain Cancel / Request contact row that stays inside the centered form column instead of stretching a gray band across the panel. All five locales updated. - Fresh installs seed the current Free plan snapshot instead of a stale one. The Free
cloud_limits_snapshotwritten on first boot predated the Portal's relaxed Free plan: it still capped boards, cards, custom fields, forms, and automation definitions/nodes at small finite numbers, granted 0 API tokens, and said 10 seats. It now matches the Portal's Free plan exactly - those per-object caps are unlimited (-1), Free ships 2 API tokens, 5 seats, and the managed-AI credit allowance - in both bootstrap seed paths, with an append-only migration refreshing installs still carrying the Free slug (paid snapshots are Portal-synced and left alone). The snapshot is cosmetic at runtime - self-hosted is never gated and Cloud re-pulls the authoritative plan - but what a fresh install shows should be true, and now it is. - Navigating from a board to My Tasks no longer logs a Svelte
derived_inertwarning in dev. The page-provided toolbar snippets (board title, view tabs) render inside the app layout but close over the page component's derived state. On navigation the outgoing page was destroyed in the same reactive flush that re-rendered the toolbar, so effects still mounted inside the old snippet - concretely, the view tabs' context menu keeping its visible-views set in sync with the board page'sview_ctx_props- got dirty-checked against the dead page's deriveds, and Svelte 5 warned about reading a derived belonging to a destroyed effect. The layout now unhooks the toolbar snippets inbeforeNavigate, while the outgoing page is still alive, so the snippet branch unmounts cleanly before the page is torn down. A param-only navigation (board to board) keeps the snippets, since the page component is reused and its one-shot toolbar effect would never re-register them; and a cancelled navigation (e.g. the no-access board guard) restores them, since the page never unmounted. - A note's cover banner no longer shrinks when you open the outline / comments / history panel. The cover lived inside the editor column, so opening a side panel (a fixed-width sibling in the same flex row) squeezed the editor - and the cover along with it - narrower, while the panel's title floated up next to the cover instead of lining up with the note's header controls. The cover now spans the full content width above the editor/panel row, so a panel slides in under the cover rather than pushing it, and the panel's title row re-aligns with the header - matching how cover-less notes already behaved.
- Note wikilinks are indexed again - backlinks and the new note graph finally have data. Every
[[Note title]]link between notes is meant to be indexed intonote_links(which powers a note's backlinks and the new graph view), but the indexing had silently stopped producing any rows. The vault hooks tested deletion with a bareif (record.get("deleted_at")), and in PocketBase's goja runtime an unset date field is a truthy empty object - so every live note edit was mistaken for a delete: the save routed into the delete branch andrefresh_note_linksreturned before writing a single link (and a straydeleted_bygot stamped onto live notes along the way). The identical trap had already been fixed in the note-to-card cross-link hook but never in the notes-vault hooks; they now string-coerce the check through a sharedis_blank_datehelper, so[[links]]are parsed and resolved intonote_linkson save and both backlinks and the graph populate correctly. - Updating a card via the API or MCP no longer risks moving it out of its column. When a card update sent the
listfield as an empty string (rather than leaving it out), the API took that literally and cleared the card's list -listis a required relation, so the card ended up with no column and surfaced in the board's first list / orphan rail, looking like it had silently jumped to the backlog while only the dates you actually changed should have moved. A blankliston update is now treated as "do not change the column" - identical to omitting it - so only a real list id ever relocates a card; toggling completion still auto-moves to the matching done/active list as before. - Note↔task linking: composer fix, working click-through, and a flush notes browser. Linking a note from a card's comment composer no longer mis-renders - the
[[/#picker was being re-anchored by the composer'swill-change:clip-path(which trapsposition:fixed) and rendered far from the cursor; it's now portaled toso no ancestor's containing block can trap it (fixes the picker in any transformed/clipped container). Clicking a card's Linked notes entry now actually opens the note - it switches the board to the notes view first, mirroring how a[[note]]mention in a description opens. The notes browser is now a flush, outline-free panel - no card and no per-section horizontal padding, so the header, search, and rows align to one left edge (Linear-style), set apart from the editor by a subtle background weight rather than a border. And the Publish dialog reads clearer: the scope tabs are now "All notes" / "Current note" (were "Entire notes section" / "Note"), plus a From title button that slugifies the note title straight into the URL endpoint. The note editor's right rail (comments, backlinks, linked tasks) is a floating panel now too - content-height when it's just links, full height when comments are open - shedding theborder-lthat seamed against the header, the per-sectionborder-tdividers, and the per-row boxes in favor of quiet uppercase labels and borderless hover rows, with each linked task carrying its board's own icon (not a generic glyph). And the note editor's portaled floating UI - the selection toolbar, the slash (/) menu, and the mention picker - now hides when a card frame or side panel opens over the notes view, instead of floating above the overlay (a card's own description editor inside a frame keeps its toolbar, so editing there is unaffected). - The Publish-notes dialog's footer is no longer broken. Its Close/Publish bar sat misaligned, hanging past the dialog's edges: the dialog overrode its container padding to zero, but the shared footer pulls itself flush with negative margins that assume the standard padding - so with none to cancel, the tray jutted out on three sides. The dialog now keeps the standard padding (the footer bleeds correctly into a clean
bg-paneltray), and the whole form got the same line-shedding the rest of the app received: the header divider and the nested bordered boxes are gone in favor of quiet spacing, the scope switch is a proper segmented control (replacing buttons that referenced a non-existent variant), inputs are pinned to the app's small text size, and the remaining group fills use a tone that's actually visible on the dialog surface in dark mode. - A note's title header now lines up with its body text. In the in-app note view, the title header (the icon, name, and path) didn't line up with the note body: with Readable line length on, the body renders in a centered, capped reading column while the header stayed pinned to the far left, and even in full-width mode the icon medallion hung out past where the text actually begins. The header now mirrors the body's column and uses its exact text padding, so the left edge of the icon medallion lands precisely on where the body text starts - in both readable and full-width modes - with the title flowing in just after it. And to keep header and body locked together even when a comments / version-history panel is open (which narrows the editor), the header now lives inside the editor's column instead of spanning the full width above it, so both re-center as one instead of drifting apart by the panel's width.
- The Calendar view's mini-calendar got its styling back. The month/year date-picker in the Calendar sidebar had collapsed into a wall of unspaced digits - the weekday header and day grid rendered with no sizing at all. The shadcn calendar re-pull during the Tailwind v4 migration moved cell sizing onto two CSS variables (
--cell-size,--cell-radius) that the shared root component declares, but the Calendar sidebar drives its ownCalendar.Rootinstance (so it can wrap the custom month/year dropdowns) and never set them, so every cell sized to zero and the grid imploded. The instance now declares both variables exactly as the shared component does, restoring the proper seven-column grid - today highlighted, out-of-month days dimmed. The header controls shed their outline boxes too: the prev/next arrows and the month/year selectors are now ghost (and the selectors stretch to fill the header row instead of hugging their text), matching the clean, frameless look the rest of the picker already had. - The List view's priority dropdown now matches the card frame's - and its options highlight on hover. The priority picker opened from a List-view cell was a different, scrappier control than the one on a card: a command-palette rendering that truncated the Unprioritized row to "Unprioriti…", padded its rows unevenly, and styled the selected item differently - and, like the frame's own picker, it hovered to
bg-muted, which in dark mode is the same tone as the popover surface (38 38 38), so hovering an option gave no visible feedback. Both pickers now render through one sharedPriorityPickerPanel(the samecards[]-driven pattern the member and tag pickers already share between the frame and the List view), so a single-row edit and a bulk-selected edit run through identical markup, the rows read in full, and hover/selection usebg-accent- clearly above every dark surface. The card frame's milestone picker got the same dark-mode hover fix. - The List and Timeline status bar no longer gets shoved aside when a panel opens. The bottom status bar - task counts, overdue, and the completion progress - lived inside the scrolling view, so the moment you opened a docked panel (the card panel or the Statistics panel) the view shrank and the status bar shrank with it, squeezed into whatever sliver was left beside the panel. It's now a full-width footer pinned to the bottom of the workspace: it spans the entire width and stays put, and the docked panels float above it, their bottom edge sitting the same comfortable gap from the bar as their right edge sits from the screen - so the panel reads as a floating card hovering over a continuous footer instead of standing on a chopped-off one. Looks identical when no panel is open; only the views with a status bar (List, Timeline) are affected.
- Ghost buttons now show a hover in dark mode everywhere. The shared ghost button variant (toolbar actions like Archived / Import, icon buttons, menu triggers - used app-wide) hovered to
bg-muted, which in dark mode is the same tone as the popover/dialog surface (38 38 38), so on any dark dialog or panel the hover was invisible - the button gave no feedback. Ghost hover (and the open/expanded state) now usesbg-accent, which sits clearly above every dark surface and matches the upstream shadcn default; light mode is unchanged (the two tokens are identical there). - A board's default (or pinned) List view now applies even when it's set or loaded after you open the board. On entering a board, the List view resolves which preset to apply - your pinned view, else the board default - and was meant to do it once per visit so it wouldn't fight your manual view switches. But it marked the visit "resolved" even when it found nothing to apply, then never tried again. So if the default/pinned view became available only after that first check - you starred a view while already on the board, an admin set the board default, a shared view finished loading, or a freshly-created board's seeded "Default" arrived over realtime - it stayed unapplied and the view picker showed "No view" until a full navigate-away-and-back. The auto-apply now commits the "done for this visit" latch only after it actually applies a view; until then it keeps watching this board's views and preferences and applies the default the moment one appears. Switching views by hand afterward still sticks (the latch holds once something's applied), and a board with genuinely no default still shows "No view" without clobbering a manual pick. The
/tasksdata loader read the signed-in user's id without first checking there was a signed-in user. On an origin with no stored session - most visibly the first time the app is opened through a different hostname, such as a tunnel or preview domain, which carries its own empty browser storage - that loader runs in parallel with the app layout's auth check, so it reached a null auth store and threw before the redirect to login could land, leaving a dead 500 page. The loader now guards on a valid session exactly like the app layout already does, returning empty data (and letting the login redirect take over) instead of dereferencing a null user. A logged-out visitor who lands on/tasksdirectly now gets the login screen rather than an error. - Favicons and the web-app manifest load on every route, not just the home page. The icon and manifest
s in the page shell used the framework's relative asset prefix, so on any nested route -/board/…,/auth/…- the browser resolved them against the current path (/board/icons/favicon.ico) and got a 404, dropping the tab icon and the installable-app manifest. They're now absolute paths, so they resolve identically from anywhere in the app. - A quieter dev build. Cleared the Svelte 5 compiler warnings that streamed on every dev compile: a set of
state_referenced_locallynotices on local state intentionally seeded once from a prop (now marked withuntrackto say so), and anon_reactive_updateon a branch-template input reference (now declared with$state). The a11y interaction-warning suppression insvelte.config.jshad been written against pre-Svelte-5 dashed warning codes that silently matched nothing - it now uses the current underscored codes. Andjszip(reached only via a lazy import in the workspace export) is pre-bundled, so Vite stops discovering it mid-session and forcing a full-page reload. - Bulk edits no longer cap out at 50 selected cards. Every bulk action in the List view - set priority, due date, list, members, tags, complete/incomplete, move, archive, and every custom-attribute edit - sends one request per selected card inside a single PocketBase batch transaction, and that batch had a server-side ceiling of 50 requests. Select 60 rows and change their priority and the whole thing failed silently (the change was caught and dropped, the popover just closed). Two changes lift this: the server ceiling is raised to 200, so a typical large selection still commits as one atomic transaction; and a shared
send_batchedhelper now transparently splits anything bigger into sequential chunks of 200, so there's no hard upper limit - a 1,000-row edit just sends five batches. Chunks are sent with auto-cancellation disabled, otherwise the SDK would derive the same request key for each/api/batchcall and every chunk would cancel the one before it. The Kanban batches go through the same helper now too - rebalancing a list's card positions, reordering lists, and the bulk archive/move when a list is deleted - so none of them cap out either. (Beyond a single chunk the edit spans several transactions, so a late failure can leave earlier chunks applied - the same partial-progress behavior these edits already had when they looped one request at a time.) - Board Flow's card-status flips now go batch-by-batch, and swapping which column is Done no longer aborts. Promoting or demoting a list between Done / Cancelled and the active states flips its cards'
completed/cancelledflags through a bulk route - and those calls fired with the PocketBase SDK's default per-path request key. So a Done⇄Done swap (one list demoted to In Progress, another promoted to Done in the same Save - both POSTing to/api/cards/bulk-completedat once) made the second request auto-cancel the first: the cards were checked optimistically in the UI but never persisted, the only trace a console "request was aborted / autocancelled" error sitting under a misleading "Board flow saved" toast. The flips now run through a shared helper that sends them in sequential batches of 200 - one server transaction per batch, applied one after another, so an arbitrarily large list never lands as a single giant transaction and the board flips in controlled waves instead of dragging through every card one at a time - with auto-cancellation disabled (the same fix the bulk-edit helper already uses), and it marks each batch's cards pending right before that batch is sent so the ~2s realtime echo-suppression window lines up with each round-trip rather than expiring mid-run. Because the dialog now awaits the flips, a failed batch surfaces a real error toast and keeps the dialog open instead of silently dropping the change under a success toast. A list's own Done / Cancelled toggle in the Kanban menu uses the same helper. All five locales updated. - Deleting every card in a list (via the delete-list dialog) no longer errors out. Choosing "delete the cards" when removing a list batched the card deletes into one transaction - but card deletes are soft-deletes (the hook answers
204and moves the card to Trash instead of removing it), which a PocketBase batch rejects as a failed transaction, so the whole list-delete threw before the list was removed. Card deletes now run through a bounded-concurrencyrun_chunkedhelper (the same approach the List view's bulk-delete uses), which both fixes the error and caps how many delete requests are in flight at once for large lists. - Bulk-editing a custom attribute across selected rows now commits in one shot, not row-by-row. With several rows selected in the List view, changing a custom-attribute cell - a select, multi-select, date, checkbox, or free-text value - used to write each card's value in its own request, one after another, so the column visibly filled in a row at a time as each change round-tripped and echoed back over realtime. The built-in columns (priority, due date, list, members, tags) had already moved to a single transactional batch; custom attributes were the last holdouts still looping. All six custom-attribute edit paths now build one
pbbatch and send it once, so the whole selection updates together - matching the default fields and making the edit land in a single tick instead of a trickle. - Deleting a custom attribute is now a single request, not one per card. Removing a custom-attribute column - from the List view's column menu or a card's custom-fields panel - used to fetch every stored value for that field and delete them one at a time before removing the field itself. On a board with hundreds of cards that meant hundreds of sequential network round-trips, so the delete crawled and could fail partway through. None of that was necessary: the value→field relation is already set to cascade-delete, so removing the field alone makes the database drop all of its values in one transaction (the server-side API has always relied on exactly this). Both delete surfaces now just remove the field - instant regardless of board size, and atomic - and a stale comment claiming the per-row loop was required to get past a relation constraint has been corrected. As a bonus, the card-panel path's old loop only ever covered the open card's value, so on multi-card boards it had been orphaning the other cards' values; the cascade now clears them all.
- The provider tiles in Connect AI integration now show a real hover in dark mode, not just an outline. The connector dialog opens on a grid of clickable tiles - Claude, ChatGPT, Codex, Gemini CLI, LM Studio, Other - each meant to lift on hover with a soft fill, a hairline ring, and a faint shadow. In dark mode only the ring and shadow appeared: the tile's
hover:bg-mutedfill was invisible because--mutedand--popover(the dialog's own surface) are the same value in the dark theme, so the wash composited straight back to the surface color - the same collision behind the dialog-footer fix below. The hover fill now usesbg-accent, which sits distinctly above the dialog surface in dark mode and equals the oldmutedvalue in light mode, so the tile reads as a subtle-but-visible lift on hover in both themes with light mode unchanged. - A Select field's cell in the List table is transparent in dark mode, like it already was in light. A single-select custom-attribute cell shows its value as a pill inside an inline picker. In light mode the cell behind the pill was transparent; in dark mode a rounded gray fill sat behind it, so the same cell looked boxed-in on a dark board and clean on a light one. The inline picker is a shadcn Select trigger, whose default styling carries a dark-only
bg-input/30background - the cell zeroed out the base background but not that dark-mode variant, so the fill showed through only in dark. The cell now clears the dark background (and its hover) as well, so only the value pill is filled and the cell reads identically in both themes. - The List view's row hover and selection highlight now reach the add-column lane. The table reserves an 80px lane on the right for the + add custom field header, but body rows only rendered cells for the real columns - leaving that lane as a CSS "missing cell" that always painted the bare table background. Hovering or selecting a row tinted every column except that last strip, which stayed stubbornly white, and the row's bottom border stopped short of the right edge. Each row now carries an empty, non-interactive trailing cell covering the lane, so the hover tint, selection fill, and row divider run continuously across the whole row; the group-header band was widened the same way to stay flush. The spacer has no column id, so keyboard cell-navigation and click-to-focus skip right over it.
- Dialog footers read the same in dark mode as in light - everywhere. A dialog's button tray sits in a slightly recessed footer - a subtle fill change plus a hairline divider that sets the actions apart from the body above. In light mode that tray was a touch darker than the white surface; in dark mode it vanished entirely, the footer blending into the dialog with no contrast at all. The cause was the footer's
bg-muted/50fill: in the dark theme--mutedand--popover(the dialog's own surface) are the same value, so a half-opacity muted wash over the dialog composited back to exactly the dialog color. The fix is one rule applied across every dialog footer in the app - the opaque--panel"midpoint" token - which in light mode equals the old composited color exactly (so nothing changes there) and in dark mode renders a genuinely darker tray that recedes toward the page background, with the divider popping against it. That now covers both shared footer primitives (the shadcn dialog and alert-dialog footers behind ~100 dialogs) and the half-dozen hand-rolled footers that bypassed them - Edit Profile, the onboarding wizard, board import, the file picker, the Git connect wizard, and the shared dialog shell that powers the Git-accounts, API-tokens, and MCP-connector dialogs. Every dialog footer, current or future, now draws from the same token, so the recessed-tray look is identical in both themes with nothing to remember per dialog. - The Done-list indicator is calmer. A list marked as Done wore a filled, bright-green check-circle in its header - loud enough to pull the eye off the column itself. It's now a quiet double-check glyph in the default text color, sized to match its neighbors (the collapse and ⋯ buttons), so it reads as a subtle status marker rather than a badge.
- Dragging a Kanban card now glides instead of snapping. When you picked up a card, the cards it displaced jumped aside almost instantly, so reordering felt jumpy compared to reordering the widgets inside the board-stats panel - even though both use the same drag library. The difference was a single setting: the card drag animated displacement over 80ms (too fast to read as motion), while the stats widgets used 200ms. The card drag now matches it at 200ms, so neighbors slide smoothly out of the way as you drag across a list; the drop itself still settles without animation to avoid any flicker as the board re-renders.
- Docked side panels now read as proper floating cards, lifted on every edge. The unlinked issues/PRs rail, the side-docked card panel, and the docked board-stats panel were separated from the canvas on their top and bottom but sat flush on the left and right - the border and shadow were cut off there, so the panels blended into the background on the sides instead of looking lifted, and the title-bar made the panel look like two stacked pieces rather than one card. The cause was layered: each panel's gutter (the small gap its ring and shadow paint into) was applied only top-and-bottom, while the left/right spacing lived outside the wrappers that clip these panels for their slide/resize animations - so the side ring and shadow were clipped away. The gutter is now applied evenly on all four sides inside the clip (and the external horizontal spacing that used to live in the dock row was removed so nothing doubles up), and the hairline border is drawn outside the card box so the title bar's fill can't paint over it - it runs continuously around the whole unit. The panels keep their exact size and position, and now read as soft cards matching the rest of the app - a muted toolbar over a lighter body, a hairline border, and a gentle shadow on every side (the stats widgets inside got the same treatment) - so they finally look like the floating cards they were meant to be.
- Closing a docked panel no longer logs a Svelte warning to the console. Tearing down the docked board-stats panel - or any panel hosting a tooltip or dropdown - made @floating-ui's position observer fire one last
update()against the floating layer that was already unmounting, reading its now-inert$deriveds and tripping Svelte'sderived_inertwarning on every close. The "stale value" it cautions about is discarded the instant the layer is destroyed, so it was harmless noise; it's now filtered in the client hook, scoped to @floating-ui's own teardown frames so genuinederived_inertwarnings from our own code still surface. - Assigning a member from a Kanban card now behaves the same every time - and never opens the card. The avatar control in a card's corner did different things depending on the board and the card: on a single-member board a blank card auto-assigned the member but an already-assigned one opened the card frame; on a multi-member board a blank card opened the member picker but an assigned one opened the frame. So the same click meant "assign," "open the picker," or "open the card" with no way to predict which. Now it's consistent - on a single-member board the control toggles that member on and off, and on a multi-member board it always opens the member picker, assigned or not. Either way the click is handled in place and never falls through to opening the card. And the picker is now the same searchable dropdown as the card detail's Members field - filter by name, see each person's role (Owner / Admin / Editor / Viewer), and assign or unassign several people in a row (it stays open until you click away, instead of the old list that snapped shut on the first pick) - with a wider panel so longer names aren't clipped.
- Cloning a board no longer bounces you to your tasks with a "no access" toast. Right after a clone, the app sometimes redirected to My Tasks with You no longer have access to this board, and only a page refresh recovered. The clone was always correct in the database - you were the owner the whole time - but the browser navigated to the new board before it had registered your membership: the one-shot access pre-approval was cleared by the incoming realtime "board created" event before the board settled into your loaded set, so the route guard saw neither and redirected. Now the clone confirms your membership and seats the board into local state before navigating (the membership-gated fetch is the access check), and the server stamps the cloner as a direct member on the board's first save rather than leaning on the after-create recompute - so you land on the clone immediately, no flicker and no refresh. The same guard-the-navigation hardening now covers the other create-then-open flows too - create a board from a template and import a board (Trello, Asana, Linear, Jira, GitHub, Todoist, Notion, TrueTask) - so none of them can flash a no-access bounce either.
- Opening a PR from Reviews no longer blanks the next git board you visit. Clicking a pull request in the Reviews inbox, then navigating to the board that PR belongs to, left the board completely empty - every view (Kanban, Timeline, Forms…) blank, no error, no spinner - and you had to bounce to another board and back to recover. Opening a PR was quietly pointing the app's "current board" at the PR's board to scope the review drawer's author/avatar mapping; arriving on that same board then looked like "no change," and a readiness flag that gated the whole view never recomputed, so it stayed frozen on its initial not ready. Two fixes: the review drawer now scopes its git user-map to the PR's own board directly (no global pointer to hijack), and the board's readiness flag is now properly reactive so it can never get stuck - boards always render on entry regardless of where you came from.
- The card key, branch, and review pills no longer show on boards without a git provider. A card's header carried the key badge (e.g.
WELC-1), the copy-branch-name button, and the open-review pill on any board with a key prefix - including boards with no repo linked, where those controls do nothing. They now appear only when the card's board actually has a connected git repository, matching the Code tab's own gating. The key and branch buttons also gained proper hover tooltips (the shadcn component) instead of nativetitleattributes. - Git Code-surface polish. A sweep over the git review surfaces. Every git author and commenter - issue descriptions, comment threads, and inline diff comments - now renders as the matched teammate (avatar + name) through the shared component, never a raw login. In the review drawer, the conversation and inline line-comment composers use the same Milkdown editor as the rest of Truetask, and an in-progress review (its inline comments plus the verdict note) is now kept when you switch PRs or close the drawer instead of being silently discarded. Comments anchored to lines outside a truncated diff are surfaced ("Comments on lines not shown") rather than vanishing. The orphans rail's link picker refreshes each time it opens, so a card you just promoted is immediately linkable. The board Code view and the orphans rail now show a real error with Retry when a load fails, instead of an empty state that read as "nothing here." And the per-card Code tab subscribes to realtime, so a linked PR or issue's state, labels, and review update live - matching the board view.
- Side-by-side diffs + syntax tint in the review drawer; agents can read a card's key. The code-review drawer's file diff gains a unified ↔ split (side-by-side) toggle (remembered per browser) and a lightweight syntax tint for comments, strings, and numbers - inline commenting works in both modes. The PR mirror now also tracks each PR's requested reviewers (which powers the Reviews inbox and lights up the review badge in the board Code view). And card responses over the REST API and MCP now include the card's
numberand computedkey(e.g.DEVE-123), so an agent can name a branch or PR that magic-links back to the card without guessing. - Git UX polish. A pass over the git surfaces from hands-on use. The card Code tab consolidates its four actions into three split-buttons (Issue · PR · Branch, each with a caret menu) with lighter icons, and an issue's title now opens the in-app issue drawer (the ↗ icon still opens the provider). The unlinked rail beside the board is drag-resizable (width remembered per browser) and slides with an ease-out only. The Reviews sidebar entry shows only for people who are on a git-connected board. The branch-name template field matches the app's font and its placeholder tokens are click-to-insert at the cursor. And Settings → Git replaces the long per-repo list with searchable repo + board comboboxes (repo shows branch/language/updated/visibility; board shows its folder path).
- Dragging an unlinked issue onto an empty list now lands where you aim. Picking up an issue or PR from the unlinked rail opens a drop zone in every empty list the instant the drag begins - the same height a card drag opens, with "+ Add task" pushed below it - instead of staying collapsed until you happened to hover the exact right spot. The list under the pointer still gets the dashed target outline on top. Previously the target only grew (and only slightly) on hover, so empty lists were an easy miss; it now mirrors the card-drag behavior exactly.
- Short time entries no longer clip their own label in the Timelogs calendar. A 15-minute block is barely tall enough for a single line, but its fixed vertical padding ate most of that space and cut off the task name. The padding is now reactive to the block's height - the same comfortable spacing when there's room, tapering toward zero only for the shortest blocks - so even a minimum-height entry shows its label in full.
- End-of-day entries and suggestion ghosts no longer get clipped in the Timelogs calendar. The week view already grew its visible hours to fit time that falls outside your set range, but it stopped exactly at the last block's hour - so an entry or a suggestion ghost ending late in the day sat flush against the grid's bottom edge, where its minimum rendered height spilled under the status bar and got cut off. The window now reserves a full row of breathing room past the last block (counting suggestion ghosts, not only logged entries), and as a backstop every block is kept within the grid's bounds, so a short one near the bottom is nudged up to stay fully visible rather than clipped.
- Rescheduling time in the Timelogs calendar no longer trips the notes-required policy. With Notes required set to billable-only or all, dragging a note-less block to another day or time - or resizing it - failed with a generic "Something went wrong" error: the server re-ran the note check on every edit, including a pure move that records no new time and offers nowhere to type a note. The check now fires only where time is actually recorded or the note is touched - creating an entry, stopping a timer (the running→stopped transition), or any explicit edit form (all of which submit the note field) - so moving and resizing existing entries on the grid just works, while timer-stops and manual edits still require their note. And a drag that would legitimately need a note now surfaces the real reason ("This time entry needs a note") instead of the generic message.
- Image uploads now explain a wrong file type. Avatars, card covers, and the workspace logo accept images only; picking a non-image (say a PDF) used to fail with a generic "Upload failed. Please try again." It now shows "This file type isn't supported," so the reason is clear. (Regular file uploads no longer restrict type at all - see Changed.)
- The "drop files here" overlay no longer scrolls away. When dragging files onto the Files view, the drop overlay was anchored inside the scrolling file list, so on a scrolled view it drifted out of position (sometimes half off-screen). It's now pinned to the files panel itself and stays centered in view no matter where the list is scrolled.
- Deleting a time entry from the Timelogs calendar now closes the confirm dialog. Confirming "Delete time entry" removed the entry but left the dialog sitting open over the grid - its handler cleared the target but never reset the dialog's
openflag (the confirm dialog bindsopenand relies on the caller to close it, as every other delete in the app does). The dialog now dismisses immediately on confirm. - You can no longer start a timer on an approved (locked) week. The data-layer lock blocked editing and adding closed entries to a signed-off period, but a brand-new timer could still be started on it - so fresh time quietly began accruing against a week that was already approved. Starting a timer on a locked day is now refused at the data layer (every surface - the topbar button, a card's Time tab, a task row - shows a prompt to ask a manager to reopen the week first). The humane exception is preserved in the other direction: a timer that was already running when the week got locked can still be stopped, so an in-flight timer is never stranded.
- The approval week now follows your "Week starts on" setting. Approvals were always bucketed by Monday-Sunday weeks regardless of the workspace's first-day-of-week preference, so a Sunday-start workspace fell out of alignment in two visible ways: the Approvals queue for a single visible week (Jun 7-13) returned rows from two different Monday-weeks (Jun 1-7 and Jun 8-14), and in the worker's Timelogs the Sunday column never locked even when the week was approved (the lock was keyed to the Monday-Saturday it computed instead). Every place that keys a week - the queue's fetch range and weekly rollup, the per-day lock lookup, the Timelogs week chip, and the day-belongs-to-week check the server enforces - now anchors on the configured week-start, so a Sunday-start week maps to exactly one approval row and locks all seven of its days. Monday-start workspaces are unaffected (the keying is identical). Note: approvals recorded before this fix were stored under Monday-weeks, so after switching a workspace to Sunday-start, re-approve a week once to re-anchor it.
- Approving an empty ("No time logged") week now actually sticks. Signing off a zero-time week showed the success toast but the row never changed - it stayed "NO TIME LOGGED" with an Approve button and never moved to the Approved tab, because the row's whole display keyed off "has no time" rather than its decision. Empty weeks are now treated as "needs attention" only while undecided: once signed off they show their Approved pill, offer a Reopen action, and move into the Approved tab (and out of "No time") like any other decided week.
- An AI hiccup can no longer log you out. Any
/api/ai/*request that returned 401 - which happens when the upstream provider or key fails, not just when a session expires - used to trip the global "expired token" handler: auth cleared, hard redirect to the login page, right in the middle of whatever you were doing. AI endpoints are now excluded from that rule, and AI note suggestions fail fully silently on any error (unreachable API, upstream failure, malformed response, or the new 6-second timeout): no toast, no broken form, just no suggestions. - Some toasts no longer show raw translation keys. The undo button on the timesheet detail panel's delete toast read "tasks.time.undo" instead of "Undo", and several generic error toasts read "common.error" - both keys now exist in all five languages.
- Editors recover themselves when the app updates underneath an open tab. When the rich-text editor's code chunks can't be fetched because they no longer exist on the server - typically a tab left open across a redeploy - the app now reloads itself once to pick up the new version, instead of silently degrading every description and comment box to a raw monospace text area. The reload is one-shot and time-guarded, so a genuinely broken build still falls back to the plain-text editor rather than loop.
- Editing timesheet entries from the report works again. The docked detail panel - edit an entry's times, note, and billable flag, delete with undo, export a day's entries - existed in the code but nothing in the UI could open it. Table cell popovers and calendar entry popovers now carry a "View & edit entries" button that opens it, and the panel handles task-day, person-day, and person-task-day scopes (showing the task's budget line when there is one).
- Approval totals no longer change with display filters. The weekly totals a manager approves are now computed from all of that week's logged time; previously an active board/tag/priority filter silently shrank the number being signed off.
- The Timelogs week-thread caption labels the week the approval actually covers. The "Applies to the whole week · …" range was derived from the calendar's view week; it now reads the approval row's own
week_start, so the caption can't drift a day from the row it describes (a real risk for a row created under a different week-start). - The Timelogs popup live-updates its own entries. It subscribed to approval decisions but not to time entries, so editing time from a card's Time tab while the popup was open left it stale until you navigated weeks. It now refetches on your own entry changes in real time (scoped to you, so a coworker's edit on a shared board doesn't churn it).
- The Timelogs popup goes fullscreen on phones. Its 520px comfortable width left the floating frame overflowing and off-center on narrow viewports; when the screen can't fit that width the popup now fills the viewport (and the resize floor follows suit) instead of a cramped, half-off-screen window.
- Faster activity lookups on large installs. Added an
(actor, created)index to the activity log (logs_projects); the Timesheets missing-week / activity check filters by actor + time and previously table-scanned with only the(board, created)index. (Applies on the next PocketBase restart.) - Editing a Gitea issue's labels works. Gitea's label-replace API takes label IDs, not names - but the code reused GitHub's name-based call, so setting labels on a Gitea issue (and the tag↔label sync that rides on it) silently did nothing. Gitea now resolves the chosen names to IDs first, the same way creating an issue already did.
- Connecting a Gitea account no longer fails validation on some versions. Gitea's
/userreports the handle asusernamewhere GitHub useslogin; the connect flow only readlogin, so a valid token came back with an empty account and was rejected. It now accepts either. - Marking a GitHub Enterprise pull request ready/draft works. The draft toggle is a GraphQL call, and on GitHub Enterprise GraphQL lives at
{host}/api/graphql- not under the REST/api/v3prefix the call was using - so the card → PR draft / ready-for-review automations failed on self-hosted GitHub. They now target the right endpoint per host (GitHub.com is unchanged). - Disconnecting a repository removes its webhook from the provider. Unlinking previously left the inbound hook in place, so the provider kept POSTing deliveries for a repo that was no longer connected. Unlink now deletes the hook (best-effort - a provider hiccup never blocks the disconnect).
- Editing a git issue's assignees from the board updates the board immediately. The change was written to the provider but the local mirror wasn't - unlike label and state edits, which already mirrored - so the assignee list looked stale until the next resync. It now updates in place.
- Provider rate-limits and gateway blips no longer fail a git action outright. Outbound calls to GitHub/GitLab/Gitea now retry a
429or502/503/504up to twice with backoff, honoring the provider'sRetry-Afterheader. - A re-sent webhook delivery no longer double-acts. If a provider re-delivers the same event (matched by its delivery id), it's now deduplicated - so a status-sync automation doesn't fire twice and a provider-comment notification isn't created twice.
- The webhook rate-limiter keys on the real client IP. It read the client-supplied (spoofable) leftmost
X-Forwarded-Forentry; it now uses the rightmost hop your reverse proxy actually set. - The Code view no longer goes stale when a PR/issue closes off-screen. The board's Sync used to pull only open items, so a pull request that closed or merged while your instance missed the webhook (e.g. it was briefly down) kept showing as
openforever - especially ones not linked to a card. Sync now also reconciles the records it already mirrors against the provider, refreshing any that went closed/merged. - Large repos no longer truncate at 100 pull requests / issues. Provider list calls (GitHub, Gitea, and GitLab) now page through results instead of stopping at the first 100, so the Code view and Sync see everything.
- A "request changes" review on GitLab now sticks. GitLab has no native request-changes state - it's recorded as a note - so the verdict was invisible after you submitted it and never moved the PR's review state. It now round-trips: the review shows up and the PR reads changes requested, like GitHub/Gitea.
- Horizontally-scrolled content no longer bleeds through the seam between the sidebar and the workspace. The sidebar's drag-to-resize handle was a thin in-flow element sitting in its own 2px-wide slot between the sidebar and the main content - a transparent gutter that the main view started to the right of. In views that scroll horizontally behind a pinned first column (List, Timeline), that pinned column couldn't cover the gutter, so as you scrolled you'd catch a sliver of the moving rows slipping through the gap at the very left edge. The handle is now an absolute overlay sitting on the sidebar's right edge - it takes up no width of its own, so the workspace butts flush against the sidebar and there's no gutter left to bleed through. It drags and double-click-resets exactly as before; this mirrors the flush-edge resize handle the docked Statistics and task panels already use against the gutter-less main content.
- The List view no longer leaks a sliver of a scrolled tag through its frozen first column. Each List row carried a 2px left border - transparent normally, coloured to mark the row whose card is open (or a draft). Because that border lived on the row (
), it sat just outside the frozen leading column's opaque fill, so the frozen column started 1-2px in from the absolute left edge. Scroll the table sideways and a card's coloured chip (e.g. a blue git tag) would slide under the frozen column and show through that 1-2px gap as a thin vertical bar hugging the sidebar - only on rows that actually had a coloured tag, which is why it looked so arbitrary. The row border is gone; the open/draft accent is now drawn inside the frozen first cell (the same opaque, left-pinned layer that already blocks horizontal bleed-through), so the column reaches the true left edge and nothing slips past it. The accent looks identical - a 2px bar at the row's left - and the header checkbox, which had a 2px nudge to line up with the old bordered rows, drops back to its natural inset. - The List view's status dropdown pins its selected check to the right edge. Opening a card's status (list) picker from a List-view cell, the checkmark on the current list sat right after the list name instead of out at the right edge, so it read as part of the label rather than a right-aligned marker. The row already grew the name with
flex-1, but the sharedCommand.Itemalways renders its own dormant check indicator (invisible, carryingml-auto) after the row's children, and that trailing auto-margin swallowed the free space and cancelled the name's grow, so the manual check landed flush against the text. The dormant indicator is now hidden for this picker (the same way the git repo and board pickers already neutralise it), so the name fills the row and the check is pinned to the far right. No new copy, so all locales are unaffected.Changed
- A fresh workspace now opens with the sidebar as the icon rail, not fully expanded. The compact icon rail - the strip that keeps the nav icons and your pinned boards one click away - is the sidebar's default the first time you load Truetask, in place of the full-width expanded panel. The toggle (the
Bshortcut, the toolbar caret, the command palette) still opens it, and your choice is then remembered per device. Only brand-new installs are affected: anyone who already had a sidebar state keeps it exactly (the legacy open/closed preference still migrates as before), and the When collapsed choice in Customize sidebar (Icon rail or Hidden) is unchanged. No new copy, so all locales are unaffected. - The command palette leads with navigation, not automations. Opening the ⌘K palette used to stack the automation groups (Run automation, jump-to-automation by name, Open automations / Browse templates) above everything else, pushing Navigation and your favorites below the fold. The sections now follow what the palette is actually reached for: Navigation (My Tasks, Timesheets, Overseer) first, then Favorite Notes with favorite cards right beside them, then Boards and the card / note search results, with the three automation groups settled near the bottom, just above Integrations, Settings, and Actions. Same items, same role and plan gating - only the order changed - so the first keyboard selection now lands on My Tasks instead of Open automations. No new copy, so all locales are unaffected.
- The note graph gets a recenter button and Obsidian-style hover focus. Panning and zooming around a big graph had no way back - the dialog header now carries a crosshair button that refits the whole graph in one click (the same framing the graph opens with). And hovering a node focuses its neighbourhood: the node, the notes it links to, and the edges between them stay solid (linked edges also draw brighter) while every unrelated node, label, and line fades back, so a dense graph reads one cluster at a time - the same move Obsidian's graph view makes. Reciprocal or duplicate links between the same two notes now collapse into a single edge, so the link count and node sizing reflect distinct connections. One new string in all five locales.
- The card comment composer is just a box now - the animated FAB is gone. Writing a comment used to start with a black floating action button pinned to the bottom-right corner (where it overlapped the newest message bubbles); clicking it launched a paper-plane "hero" that physically arced from the FAB to the send button while a panel clip-path-revealed itself from the corner - two competing animations, plus a whole collapse-on-blur state machine (fold back on Esc / click-away, guards for the attach menu, the file picker, drag, and frame-drag) to manage. It was clever and it worked; it wasn't worth the friction on a high-frequency action or the maintenance surface. It's now a persistent, Linear-style box docked at the foot of the thread - always visible, click-and-type, no gate: a white card (card-toned in dark) with a hairline border and a tiny shadow, "Write a comment…", and the attach + send controls grouped at the bottom-right. Attach keeps its source menu (from your computer / from the board's files) - now a plain paperclip whose menu opens upward, end-aligned to the pair - and drag-and-drop a file onto the box still works. Send is flat (no border, no shadow) and muted until there's something to send, then fills (primary) the instant a character lands (it reads the editor's own keystrokes, not the debounced markdown value, so it never lags fast typing). Firing off several comments in a row keeps focus in the box, and a comment you send now smooth-scrolls into view as its realtime echo renders, instead of snapping or landing short. It carries an equal margin to the frame's left / right / bottom edges and resizes with the frame, its corners match the frame's radius, and a background-matched fade scrim sits between it and the thread so messages dissolve into the feed background as they scroll toward it instead of poking out around the box. Under the hood this deletes the entire FAB/morph component and its geometry + collapse machinery, and fixes two rough edges in the same pass: sending now reads the editor's current content, so a fast type-then-Enter no longer drops the last keystrokes and silently no-ops (the send used to read a microtask-lagged mirror of the text); and the composer clears in place after each send instead of tearing down and rebuilding the whole Milkdown/ProseMirror instance, so the text-vanishes → placeholder-gone → box-shrinks → placeholder-back rebuild flicker is gone (two tiny imperative methods - read current markdown, clear - were added to the shared rich-text editor for this). It reuses the existing composer strings, so all locales are unaffected.
- The colour picker was redesigned - the chosen colour is finally obvious, and a stray click can't blank a field. Everywhere you set a colour (list colours, tag colours, milestones, the card cover tint, profile colour, and automation sticky-notes / subflows) opened the same popover: a dense wall of 108 flat rectangles where the current selection was marked only by a hairline outline and a slight scale bump, all but invisible mid-grid. The popover is rebuilt around a spectrum matrix - hues run left to right across the rainbow, shades top to bottom from light to dark - so it reads like a real palette instead of noise, and the selected swatch now carries a clear ring halo and a contrast-checked tick that stands out in both light and dark. A live header names the current colour in plain terms (for example "Blue 500") beside its hex. Crucially the "No color" option is now off by default and opt-in per surface - it appears only where clearing is genuinely meant (the card cover tint), so a colour a list or tag intrinsically needs can no longer be wiped to empty. The trigger buttons are unchanged. Three new strings in all five locales.
- The My Tasks detail pane has a calmer empty state. With no task selected, the right pane drew a boxed medallion icon over a heading and a sentence of explanation; it now uses the same quiet, Linear-style placeholder as the card comments feed - a single thin clipboard glyph over one muted "Select a task" line, no box and no sub-text. No new copy.
- The activity feed now labels every change in plain, translated language. Both the card Activity tab and the Board Activity dialog fell back to a generic renderer that printed raw database column names for any change they didn't special-case, so a board setting read
updated show_git_orphans, a reorder readupdated position, a recolour readupdated color, and the entity noun came through untranslated (created cardstayed English in every locale). Every field a card, list, or board can record now has a real phrase in all five languages (for example "changed the git orphans visibility", "moved to a different list", "changed the list state", "changed the default view", "changed the member roles", trash and restore, WIP limit and mode), entity nouns are translated and sentence-cased ("moved card", "deleted list"), and note activity (which surfaces in the board dialog) gets its own icons and labels. Two internal notification flags (notified_overdue,notified_soon) are system bookkeeping rather than user actions, so they no longer appear; and a no-op save whose only diff is a phantom date field now reads "made changes" instead of a bare "-". And every entry is attributed to a real source: a change with no human actor now reads "System" (a backend or cron action, with a gear marker) or the named automation that ran it, an AI dispatch shows its persona, and a member or tag removed since the change reads "a former member" / "(deleted)" - nothing in the feed ever says "Unknown". About 40 new strings, all five locales. - The card Activity tab reads like a feed now, not a busy timeline. A card's Activity tab drew every row twice over - a chunky coloured action pill on the spine and a repeated user avatar in the sentence - and split each entry across two lines (bold name and action, then the timestamp floated off on its own row), so a card one person had touched many times read as a cluttered, jagged wall. It's one aligned line per entry now, hung on a hairline timeline: a small marker rides the spine as a connected dot, its glyph keyed to what changed (a person for assignment, an arrow for a move, a calendar for dates, a tag for tags, a check for completion) and coloured only for the events that carry weight - moves, assignments, creation, completion, deletion - while routine field edits stay muted. The actor's name is the one emphasised token, and the description trails into a middot-separated relative time. The filter row shed its sort-caret column-header look - a funnel icon now labels the User / Action / Date filters and they stay muted until active - and the bar shares the card frame's own background so there's no stray header band. That filter bar is also now genuinely sticky: it had been detaching after roughly a screen of scroll because its containing block was capped at one viewport height; it now pins for the whole feed. Filters, data, and behaviour are unchanged - presentation only. No new copy, so all locales are unaffected.
- The Board Activity dialog was rebuilt to match. The board's ⋯ → Activity dialog was a dense bordered table (a boxed
bg-mutedfilter bar, an outlined table,outlinebuttons) that looked nothing like the card feed it mirrors. It's the same Linear-style timeline now: a hairline spine of connected colour-keyed dot markers, one flowing line per entry with the actor (avatar + name), a muted change summary, a subtle entity chip (which card, list, or board the change hit, since board activity spans many), and a relative time. The whole surface follows the Design Language note: the dialog onbg-popover, the header divider dropped for whitespace, the filter bar de-boxed into inline filled borderless controls, the scroller transparent with.stealth-scroll, a delayed spinner so quick loads don't flash, and pagination reduced to a count plus a quietghostpager (no divider). Agent-authored entries carry the persona marker and AI badge, same as the card tab. Filters and data are unchanged. No new copy, so all locales are unaffected. - Board Activity loads 500 events per page now, and you can change that. The dialog fetched a fixed 100 rows per page; the default is now 500 (the most PocketBase will return in one page is 1000), so paging through a busy board's history takes far fewer clicks. A Per page control in the footer switches between 100, 250, 500, and 1000 - picking a size jumps back to the first page and refetches, and the count and pager update to match. One new string ("Per page") in all five locales.
- Board Activity stays smooth at any page size, and shows a spinner while it loads. Rendering a 500- or 1000-row page used to lock the UI for a beat while every row mounted (a thousand rows, avatars, and tooltips built at once). The feed is virtualized now - only the ~30 rows actually in view are in the DOM (each a fixed-height single line, so the window maths needs no measuring), so switching to 1000 rows renders instantly and stays scrollable and clickable the whole time. Rows too long for one line truncate, with the full text on hover. And if a query takes more than 500ms to come back, a spinner shows centered in the feed until it arrives, instead of a blank panel.
- Set a card's milestone straight from the List view. The List view's new Milestone column was read-only - you could see a card's milestone but had to open the card to change it. Clicking the cell now opens the same milestone picker the card frame uses (pick one, clear it, or create the board's first milestone inline), bringing it to parity with the status, members, priority, tags and due-date cells that already edit in place - and, like those, a click on the cell edits the whole bulk selection when several rows are selected. The picker's body was lifted into one shared
MilestonePickerPanel- the samecards[]-driven pattern the priority, tag and member pickers already share between the card frame and the List view - so a single-cell edit and the frame's own picker run through identical markup and can never drift apart. No new copy, so all locales are unaffected. - The view toolbar was regrouped so its icons read by what they do. The right-hand cluster was an arbitrary row mixing unrelated kinds of control; it's now ordered groups, left to right, separated by subtle dividers: view-specific tools, then panel toggles, then the shared Filter / Milestones / Preferences popovers, then Search. The Statistics and git Orphans-rail buttons - which aren't menus, they show / hide a docked side panel and carry an on/off state - are now real toggle buttons (a pressed/filled state when their panel is open, the standard
aria-pressedtoggle). Tools that belong to only one view - the List view's saved-views / export / add-field controls and the Calendar's jump-to-today - now lead the cluster, fenced off by a divider, so the controls shared across every view keep the same position instead of being shoved sideways whenever a view's own tools appear. Everything that comes and goes (the view-specific group and the toggles) grows / shrinks in place as you switch views, so the toolbar slides rather than pops. And the display-preferences button dropped its misleading on/off-switch glyph (it opens a popover, it isn't a toggle) for a paintbrush, so it's no longer confused with the real toggles beside it. - The view toolbar's popovers got a consistency pass. Every panel-style popover reachable from the board's view toolbar - Filters, Milestones, View preferences, Tweaks, and the List view's Add field - now shares the same padding with rounded, inset hover rows, so a row's highlight never runs flush to the popover's edge the way the Milestones list used to (the Filters popover was already the reference; the others were brought in line; the multi-mode view-switcher menu keeps its tighter menu-style spacing as a separate family). The Milestones popover in particular was rebuilt to match it: inset rounded rows, a tighter vertical rhythm so its height tracks its contents, and a clean divider above Automate milestones instead of a full-bleed list. Three icon buttons that still leaned on the browser's native
titlehover box - Milestones, View preferences, and Share - now use the same shadcn tooltip as the rest of the toolbar (the Milestones button had no tooltip at all before). No new copy. - Every list now looks the same everywhere - its flow-state icon, painted in the list's own colour. A list used to be drawn two different ways: the Kanban column header already showed a state-shaped icon (dashed for Idle, a half-filled circle for In Progress, a check for Done, a prohibition sign for Cancelled) tinted with the list's colour, but every other place a list appeared - pickers, dropdowns, tooltips, table cells, menus - fell back to a plain coloured dot that told you the colour but not the state. They're unified now: one element carries both the list's state (the icon shape) and its identity (the colour), matching the Kanban header. The convention reaches the list-view list cell and its move-to-list menu, the calendar (new-task list picker, the event's list line, and the hover card), the timeline hover card, the card frame's in-list picker, My Tasks (the list-group headers, each row's list chip, and the complete-task list picker - which now shows each target list's real state instead of a generic bullet), the board Statistics Cards per list labels, the form builder's "submissions land in" select, the in-note board and card embeds (both the live editor and the public published-notes reader - the card-embed status chip now shows the list's state icon in its colour instead of bare text), the right-click Move card menu (which previously showed only a generic list glyph), the Board Flow dialog's list tiles, and every automation list/flow-state picker (Card moved, Create/Duplicate card, Move to board, Schedule, For each, Target card). It's all driven by one new shared
ListStateIconcomponent reading the singleflow-lanestable (icon + weight per state), so the four states can never render inconsistently again; the old per-panel colour-dot helper is gone. Plain-text list mentions in prose (e.g. the search breadcrumb "Board / List") stay as text. No new copy, so all locales are unaffected. - Flow-state list icons are now duotone, for a softer and more consistent look. Each list's state icon is painted in the list's own colour, but the four states didn't read as a set: In Progress, Done and Cancelled were solid
fillwhile Idle was a plain dashed ring (aboldoutline) that showed almost none of its colour - just a thin tinted stroke. All four now use Phosphor'sduotoneweight, so every state reads the same way: its shape in the list's colour over a faint fill of that colour. Idle gains a visible fill inside its dashed ring (its colour finally shows at a glance), and the filled states lighten into a two-tone look that sits better beside it. It's driven by the sharedflow-lanestable, so it applies everywhere the icon appears - Kanban column headers, List-view cells, every picker and dropdown, calendar, timeline, the Board Flow dialog (both the lane headers and the list tiles), and in-note card embeds - with the live card-embed's hand-drawn SVG twin updated in lockstep so it stays pixel-identical with the published reader. No new copy. - The board's ⋯ menu is shorter, grouped, and ordered by what you reach for most. The board-header menu had grown into a flat list of fourteen items - duplicate, export, form, webhook, repository and notification actions all stacked at one level - so the things you actually open daily were buried among setup chores. It's reorganized now around two ideas: importance on top and like-with-like in submenus. The actions you use to operate a board lead - Board flow, Activity, and Open repository (only when a repo is linked) - with AI Context sitting above them when AI is enabled. The occasional actions fold into two clearly labelled submenus: Duplicate & export (Clone · Save as template · Export board) and Integrations (Create form · Manage webhooks · Link a repository). Subscribe to digests and Archive & Trash form a quiet utilities group beneath them, and the board-lifecycle actions stay last and apart - with Delete board now flagged destructive (it reads red) so it can't be fat-fingered for an everyday item. Same actions, same permissions, half the visible length. All five locales updated.
- The public published-notes page got the reader-grade polish the in-app notes view has. The shared read-only page (the link you hand out) now mirrors the app's own notes sidebar: folders animate open and closed, a hairline guide drops from each expanded folder to show the nesting (the active row now sits cleanly inside that guide instead of overhanging it), each note keeps its own chosen icon rather than a generic page glyph, and a small dot marks a collapsed folder that holds the note you're reading - all on the same compact type scale and muted palette, instead of the old flat, oversized list. The sidebar is now a resizable panel (drag the edge; the width is remembered) with a show/hide toggle that slides it away - and the toggle rides with the panel, sitting in the sidebar header while it's open and hopping to the main view once hidden - and the stray divider line under the title is gone - the only seam is the resize handle, invisible until you reach for it. And the reading surface gained the two controls a reader expects, tucked into one quiet menu: a light / dark / system theme switch and a Readable line length toggle (both remembered per browser), so a visitor can tune the page to how they read.
- A note with no comments now shows a real empty state. The comments panel used to print a stray, left-aligned "No comments yet." that didn't line up with the panel's padding. It now shows a centered slashed-chat glyph with a quiet "No comments" line - the same icon, weight, size and wording as a card's comments feed - so the surface reads as intentional and consistent with the rest of the app.
- Comments and version history are now one tab switch in the note header. The two icon buttons that opened a note's Comments and Version history panels are now a single segmented tab control, so it reads as two views of one docked panel rather than two independent toggles. The motion matches the tab metaphor: opening a panel - or closing it from its X - slides the panel in or out, but switching between Comments and Version history while it's already open swaps the content instantly, with no slide. (Both panels are now one shared sliding container, so the slide only runs when the panel itself appears or disappears.) When neither is open the control simply sits unselected, doubling as the always-visible way to reopen either view. And the panel now remembers itself (per browser): whichever view you left open - or that you closed it - is restored as you move between notes, switch board views, and across reloads, appearing already in place with no slide; only your own open/close/switch animates.
- The Publish notes dialog grows and shrinks smoothly instead of popping. Turning on Require password, or switching to the Selection scope, used to snap the dialog to its new height in a single frame. Now its body animates between sizes on the same motion the Connect a repository wizard uses, and the content that appears - the password field, the selection tree, the public-URL preview - slides and fades in as a secondary touch rather than blinking into place. The open itself still paints at its final size (the height transition only arms after the first measure, so there's no intro pop), and when an inner reveal runs its own slide the outer easing steps aside for it, so the two never compound into a laggy clip.
- The Files and Notes views now line up when you switch between them. Both are the same shape - a browser column on the left, a wider content pane, and an optional slide-out panel - and each looked fine on its own, but flipping between the two jolted: the whole Notes column sat about 8px higher than Files, the Notes panel header had no icon next to its label while Files did, the Notes title carried a bare glyph where Files boxed its icon in a soft medallion, the two search fields were styled differently (Files a bordered white input, Notes a borderless soft fill), and the header buttons hovered in two different ways. They're reconciled now. The Notes panel header gains the document icon beside its label (mirroring Files), both title icons sit in the same rounded medallion (the Notes one still opens the icon picker on click), both search fields use the one borderless filled style, the header action buttons share one muted ghost + soft-hover treatment, and the Notes column picks up the same
--dock-gaptop breathing as Files - so the panel header, the search field, and the title icon land at the exact same position in both views (verified to the pixel), and the two browser panels start at the same default width. Switching Files ↔ Notes now changes only the labels and the content, not the furniture. - The Files view caught up with the rest of the app - docked floating panels, fewer lines, a status bar. The board's Files view still wore the old boxed-in look: a hard-bordered browser sidebar and details panel, harsh dividers under every header, dashed-border empty states, and file/folder tiles framed by borders and drop shadows. It's been rebuilt to the current Rhea look. The browser sidebar, the file area, and the details panel are now three soft "floating cards" - rounded corners, a hairline ring, and a gentle shadow inset by the same
--dock-gapgutter the Kanban rails and Statistics panel use - set apart by tone and shape instead of slabs and lines; headers carry a faint wash, tiles drop their borders for clean hover fills (a subtle ring keeps thumbnails defined), and the empty states lose their dashed boxes for a soft icon medallion. The thumbnails / list switch is now the app's segmented tab control (the same one the board view switcher uses), and every toolbar control - type filter, sort, the view tabs, the details toggle, Upload - now shares one height. Toggling details no longer pops the panel in and out: it slides on the shareddock_slidemotion the Kanban rails use, and the panel is now resizable by dragging its left edge (double-click to reset, width remembered per browser). And the view gains a full-width status bar along the bottom - visible files, folder count, and the total size of what's shown - that, exactly like the List and Timeline views, spans the entire width with the side panels floating above it rather than being squeezed beside them. The upload progress bar and drag-to-upload overlay were restyled to match (no more dashed drop border). - The Calendar view now speaks the same milestone icon and tab control as everywhere else. The earlier consistency pass moved milestones onto the flag icon and the view switches onto segmented tabs, but the Calendar view had been left behind on the old diamond and a row of look-alike toggle buttons. Its Month / Week / Day switch is now the same segmented tab control the Timeline and the board view switcher use - same height, same inline calendar icons - and the diamond is gone for good: every milestone affordance across the app now wears the flag, including the Calendar's day pills and its Add milestone here context menus, the List view's milestone group headers and chips, the Kanban card's milestone chip, the card frame's milestone picker, the My Tasks milestone grouping and filter, and the card-display toggle that shows or hides milestones.
- The Timeline toolbar is one clean bar, and its controls moved home. The Timeline view's toolbar had grown inconsistent: the date-range preset sat in a filled dropdown that hovered differently from the ghost buttons beside it, a divider chopped the bar into a sidebar-width left half and a right half, and the view's own actions - group-by, jump-to-today, fit-to-view, export PNG, add-milestone - lived up in the page toolbar a row away from everything they belong with. It's now a single continuous bar with no internal dividers, where every control shares one spec (same height, icon size, padding, and hover) so undo/redo, the zoom switch, the dates, the preset, and the relocated actions all read as one family. The Day / Week / Month switch is now the same segmented tab control as the board's view switcher - keyboard-navigable, and properly disabled when a zoom level can't apply at the current scale - instead of a row of look-alike buttons. The seam between the task list and the gantt grid is now draggable: pull it to give long card titles more room or hand the space back to the chart, double-click to reset, and the width is remembered per browser. The redundant overview minimap is gone - the horizontal scrollbar and zoom controls already covered it - and on narrow widths the explicit date buttons fold into the preset so the zoom controls are never clipped. Several rough edges went with it. The toolbar now stays put on the empty state, so when no task is dated yet you can still switch zoom or add a milestone instead of staring at a bare placeholder. The gantt's vertical grid runs the full height of the view - day/week columns, weekend shading, the today line, and milestone markers no longer stop at the last row, so a board with only a couple of dated cards stops looking pinned to the top (the horizontal row lines still stop where the rows do). You can assign members straight from the timeline: the sidebar avatars are now a button - and memberless rows reveal a dashed + on hover - that opens the very same searchable member picker the Kanban cards use, anchored to the right of the row. And the Data range preset is now plainly labelled All tasks. Right-clicking a task - in the sidebar list or on its gantt bar - now opens the same card context menu Kanban cards have (open, assign, complete, tags, priority, members, archive, delete), built on the same mount-once architecture so a board with hundreds of tasks doesn't pay for a menu per row. Right-clicking any empty day drops a milestone there (it was previously only possible from the date header), and the sidebar's right border and background now run to the bottom alongside the grid, so the split doesn't dead-end at the last row and scrolled gantt shading can't bleed under the task list. The task list itself reads more cohesively: the gray calendar icon that singled out unscheduled tasks is gone - scheduled vs unscheduled now differ only by the same italic + dimming the rest of the app uses, with each prioritised task now showing its actual priority icon (small) in a reserved slot that's always present, so titles never shift when a task gains or loses a priority - and group headers (To Do / In Progress / …) are shaded the same
bg-muted/40as the List view, so they're set apart by tone as well as height. And a sidebar task opens on a single click now (cmd-click still pops a floating frame), instead of forcing a right-click → Open. Finally, milestones speak one icon everywhere: the timeline's own (duplicate) milestone-add button is gone in favour of the shared Milestones button that's on every view, and that button - plus every other milestone affordance - now wears the flag icon instead of the diamond. And collapsing a group is now animated - the rows below slide to their new positions, the task rows fade and fly as they leave or return, and the caret rotates, all on the same 180ms cubicOut curve the sidebar folders use (and honoring reduced-motion); it stays smooth on big boards because the rows keep a stable identity instead of re-rendering, and plain scrolling never animates. - The docked task panel slides in and out instead of popping. Opening a card into the right-hand side panel (e.g. from List view) and closing it again used to be an instant snap. It now slides on the same quick width animation the git orphans rail and the Statistics panel already use - so all three docked side panels feel of a piece. The three were sharing identical copies of the transition; they now draw from a single shared
dock_slideso they can't drift apart. No change when you switch from one card to another with the panel already open - that still swaps in place. - The Automation Library caught up with the rest of the app - fewer lines, flatter, rounder. The dialog had aged: heavy outlined tab pills, list rows boxed in by a border and a divider under every row, an Open button and a ⋯ menu that shared no styling, and a Templates tab that was a wall of bordered cards with a filter-tab strip and an archaic search field. It's been rebuilt to match the board's current look. The Automations / Templates switch is now the same compact segmented control as the board's view switcher. The automations list loses its frame and per-row dividers for clean rounded hover rows; each row's flow chips and run status (Paused / Never triggered / “19 runs · 4d ago”) sit together on one muted line, and Open + ⋯ are now one matched ghost cluster instead of two unrelated buttons. The Templates tab drops the filter tabs in favor of labelled category sections (Cleanup, Notifications, …) over a flat search field; each template is a borderless rounded card on a soft fill with its hero icon vertically centered and a new meta line that previews the trigger→action flow and step count, the same way an automation row reads - so a template tells you what it does at a glance instead of just a title and blurb. All the group fills use a theme-safe tone so the dark-mode dialog reads with real depth instead of washing out.
- The Customize sidebar dialog now reads as an extension of the sidebar it configures. It had the same boxed-in look the rest of the app has been shedding: each group was wrapped in an outlined card with a divider under every row, every item carried an oversized icon and label (larger than the actual nav they mirror), and the visibility control was a wide Always show / Don't show dropdown - a dropdown for what is, for every item, a plain on/off choice. It's been rebuilt to match. The group frames and row dividers are gone in favor of clean rounded hover rows, and each item's icon and label are sized to exactly match the live sidebar, so the dialog looks like the nav it edits. The dropdown is replaced by a single Switch you can toggle by clicking anywhere on the row (keyboard-toggleable too); a hidden item dims its icon and label so you can see at a glance what's off, and the sidebar updates live as you flip each one. Items that actually expose a badge still get the full Always / Show when badged / Don't show choice. The hover fill uses the same theme-safe tone as the rest of the app so it reads with real depth in dark mode instead of washing out.
- Segmented tabs read correctly in dark mode everywhere. The selected tab in the app-wide segmented control (board view switcher - Kanban / List / Calendar … - the Automation Library, and every other place that uses it) had a dark-mode bug: the active pill filled toward background (near-black) with only a faint lift, so on a dark surface it blended into the page instead of looking selected - the opposite of the light theme, where the active tab is a clean raised white pill on a grey track. The active tab now lifts to a distinctly lighter surface in dark mode - the dark-theme analog of light's white pill - so a selected tab always reads as raised and selected, on any surface, without resorting to a black fill that clashes with the page.
- The Add-time form's Billable and AI-suggestions sections are real panels now, not a dashed afterthought. In the time-entry popover (week calendar, card Time tab) the Billable row and the Suggestions area were outlined boxes - the suggestions one with a dashed border - filled with a tone that's invisible on a dark surface, so in dark mode they read as empty wireframe rectangles tacked onto the form. Both are now solid, softly-filled rounded panels (the same grouped-section fill used across the app), so they carry real depth in dark mode and a gentle tonal grade in light: the panel sits above the form surface, and suggestion items sit as distinct wells inside it. No dashed borders, consistent with everything else.
- Custom Select fields got a real options editor - single vs multiple, and add / rename / reorder. Adding a Select custom field used to drop you into a cramped outlined box: a wrapping cloud of option chips, a separate add row, and an easy-to-miss Allow multiple checkbox tacked on at the bottom - it read as an afterthought. It's now one cohesive, borderless panel. Whether the field holds one value or several is the first decision: a labeled Single / Multiple segmented toggle - each with a one-line "One value per card" / "Several values per card" hint - instead of a buried checkbox. The choices are a tidy list of rows you can rename in place (click the text, it's pre-selected to retype), remove (an ✕ that surfaces on hover), and drag to reorder by the grip handle, added from a single input well that keeps focus so you can type several in a row. And the exact same editor now powers the card frame's manage options surface, so configuring a select field looks and behaves identically whether you build it in the List view or edit it later on a card.
- The Timelogs week picker shows the week, not a redundant date. The date-picker button in the Timelogs week navigator displayed the week's start date (Jun 22, 2026) right beside a standalone label that already spelled out the full range (Jun 22 - Jun 28, 2026), so the start date appeared twice. The button now carries the whole week range itself - click it to jump to any week exactly as before - and the duplicate standalone label is gone, trimming the toolbar to one clear, clickable week indicator.
- A kanban list's Collapse and Sort swap places. The list header's quick Sort button is now a one-click Collapse button (it folds the column to a slim strip, same as before - just promoted out of the menu), and sorting moved into the list's ⋮ menu as a Sort by submenu holding the same options (manual, plus due-date / priority / assignee ascending or descending). The ⋮ menu - previously admin-only - now opens for everyone, so sorting stays available to every role exactly as it was; the admin-only Set as done and Delete are still there, gated to admins inside it. A list that's sorted by something other than manual still flags it at a glance: the active-sort dot now rides the ⋮ button (and the Sort by row tints) instead of the old Sort button.
- A kanban list's color is a quiet dot until you reach for it. The swatch to the left of each list's title used to sit at full size all the time. It's now a tiny, fully-rounded color dot - a calm indicator - that blooms into a full, clickable swatch as your cursor comes near it. The reveal is driven by proximity, not a plain row-hover: the dot grows once the pointer is within a short, tweakable distance of it, so it feels deliberate - like the control is reaching back toward you - rather than firing the moment you brush the header. The growth is the affordance: the dot stays a clean circle throughout and simply swells from a quiet indicator into a full swatch on a gently overshooting curve, and bringing the pointer onto the swatch itself pops it a touch larger with a faint ring - so an admin always has a comfortable target to click even though the resting state stays minimal (the hit area never actually shrinks, only the dot does, and the picker stays open-aware, holding the swatch expanded while you choose). A list with no color shows a faint placeholder dot that reveals the palette icon as you approach; for editors and guests - who see the color but can't change it - the dot simply stays small as a pure indicator.
- The Stats panel looks the same floating as it does docked. Floating, it had a different corner radius, a heavier shadow, and a shorter toolbar than the docked version, so changing its placement changed its whole appearance. Both placements now share the same soft-card styling and toolbar. Its surface is also a solid color a half-step between the page and the muted gray (so it still reads as lifted) instead of a half-transparent fill - which, on a floating panel, had let the board cards behind it bleed through.
- The "Open in board" button only shows where it's useful - in My Tasks. A card open in the docked side panel had an Open in board button in its toolbar, including when you were already on that board (where it does nothing useful - the card is right there). It now appears only in the My Tasks split view, where the card detail isn't on a board and jumping to it makes sense. On a board, the docked panel's toolbar matches the floating and centered card frames.
- Toasts are quieter - Linear-style. The notification toasts were a bit loud: 14px text, a heavy drop shadow, and - worst - an error turned the whole card red. They're calmer now. The toast type shows up only in the icon (a small red glyph for an error, a muted gray dot for info, the familiar check for success) while the card itself stays neutral in both light and dark - no more wall of red for a failed save. The text drops to 13px with a crisp title over a muted description, the icon shrinks to 16px and top-aligns so multi-line toasts read the way Linear's do (title + secondary line), and the hard drop shadow is replaced with a soft, low-opacity float. Nothing about when or what toasts fire changed - only how they look.
- Linking a repo now tells you what it pulled - and an empty repo reads as empty, not broken. Connecting a repository to a board could drop you into a blank Code view with no way to tell "this repo has nothing open" from "it didn't work." Three changes close that gap. Linking now pulls the repo's open PRs and issues immediately (no waiting for the first webhook) and the toast reports the result - “synced 4 issues, 2 PRs” or “no open issues or PRs to pull yet.” The board you're on updates live the instant you link - the Code view and git surfaces appear without a refresh. And the Code view's empty state now tells a synced-but-empty repo (“nothing open right now; new activity shows up here automatically”) apart from one that's not synced yet (with a Sync button), so an empty repo never masquerades as a broken integration. Re-linking an already-connected repo is idempotent too - it re-syncs instead of erroring on a duplicate.
- The Code view's docked side panels share one header. The unlinked rail, the card frame, and the Stats panel now use an identical docked header - the same height and the same
bg-mutedbackground in both light and dark modes - so the three line up cleanly instead of the rail's header sitting shorter and lighter than its neighbors. - Docked side panels float as inset cards. The docked side panels - the Stats panel, the docked card/task view, and the unlinked rail - used to sit flush against the screen edges with a hard divider line, which read as heavy and, since these panels don't reach the top of the screen, looked slightly off. They're now inset floating cards: rounded on all corners and outlined with the same hairline ring + soft shadow as the task frame and the app's other floating dialogs (the hard
border-l/border-ris gone), held off the screen edges by a small gap - with the same gap kept between panels when more than one is docked. The space around a panel reads as the board canvas, not a muted tint, and each panel's drag-to-resize handle now lines up with the card's rounded edge and sits flush against it instead of running full-height past the corner. A single--dock-gaptoken controls both the edge inset and the inter-panel gap, so the whole set retunes from one place. The full-height git review/issue drawers are intentionally excluded. - A docked panel's resize handle hugs its card edge instead of floating in the gutter. Between two docked panels the drag-to-resize line sits centered in the gap - clearly the divider between them - and that read fine. But a panel docked against the board itself (a single panel, or the one nearest the board in a multi-panel dock) put its handle a full gutter away from the panel's border, hard against the board content, so the line looked detached and arbitrary. Each panel now decides where its handle goes by what it borders: against the gutter-less board content it hugs its own card edge (flush with the rounded border, matching the unlinked rail), and against another docked panel it stays centered in the shared gap exactly as before. Applies to the docked card/task panel and the Stats panel on either side.
- The docked Stats panel slides in instead of popping. Toggling the board Stats panel while it's docked now eases it in and out with the same width-slide as the unlinked rail - sliding from whichever edge it's docked to (left or right) and pushing the board across as it goes, rather than snapping into place. A floating Stats panel is unchanged: it still appears instantly, with no slide.
- The Stats toolbar button's active state matches the unlinked-rail button. When the Stats panel is open, its toolbar button now uses the same active treatment as the rail toggle (a steady
bg-mutedhighlight) instead of thesecondarybutton style, whose hover lightened the button in a way that read as off for an always-on toggle. - Workspace settings, reorganized - Identity folded in. Settings → Workspace now groups its options under clear headings - Identity (the workspace name and logo, which used to be its own nav entry), Localization (week start, date and time formats), and Time tracking (time rounding, notes-required, and the new Timelog-suggestions switch) - laid out as tidy divided sections under a single Save, so the workspace's name, look, and preferences all live in one place and the separate Identity page is gone.
- The Settings sidebar is calmer. The left-hand navigation in Settings now sits on a subtle muted background that sets it apart from the content pane, and its scrollbar stays hidden until you hover or scroll - and never reserves a gutter that shifts the items - the same stealth-scroll behavior used in My Tasks and the Timelogs views.
- The Plan view shed its card. Settings → Plan was the only settings page wrapped in a bordered, shaded card; it now uses the same flat, full-width layout as the rest of Settings - no outer border, rounded corners, shadow, or shaded
bg-mutedpanels, and content runs edge-to-edge so it lines up with the page title and description. The plan summary, the at-a-glance limits, and the included-features list are separated by plain dividers, matching the Workspace settings' section style. - The My Tasks header matches every other view. The "My Tasks" title icon was the only top-bar identity wrapped in a tinted
bg-primary/10rounded square; it's now a plain icon and label like the Board, Timesheets, and Overseer headers. - The Reviews view gets a proper top-bar header. Reviews was the only view that set no global toolbar title, so the search, timer, notifications, and profile controls bunched up on the left instead of sitting right-aligned. It now renders the standard title (icon + label) in the top bar - consistent with My Tasks, Timesheets, and Overseer - moves its refresh into the view-toolbar row, and drops the now-duplicate in-content heading.
- The sidebar tightened up and aligns to a single column. The personal/workspace nav icons (My Tasks, Reviews, Timesheets, Overseer) were 20px while the folder icons were 16px, which threw their labels out of line; every sidebar icon is now 16px. And boards - which carry no icon of their own - gained a leading spacer so their names line up with the icon-bearing rows above instead of sitting flush against the icon column. Every row's label now starts at the same x.
- Folders expand and collapse smoothly. Toggling a sidebar folder no longer pops its contents in and out - the children animate their height so the rows below get pushed down (or pulled up) through normal flow, with a quick opacity lead-in so they reveal softly and the folder's connector line draws in with them. It's deliberately fast (180ms, ease-out) since it's used constantly, the caret rotation is synced to the same timing, and it respects
prefers-reduced-motion. Nested folders animate only the one you toggled, not the whole subtree. The active-board marker dot scales in alongside the collapse - with a subtle overshoot (back-ease) as it appears and a quick clean shrink as the folder reopens. The Personal, Workspace, and Boards section groups are all collapsible now and expand/collapse with the exact same height-slide (shared transition), so the whole sidebar behaves consistently. The Boards header gained a caret toggle (its collapsed state is remembered per device), and it auto-expands if you start adding a board while it's collapsed. - Sidebar section headers are no longer shouted in all-caps. Personal, Workspace, and Boards now read as normal title case (the all-caps was a CSS treatment, not the translations - those were already title case in every locale), for a calmer, more Linear-like sidebar.
- Active boards match the rest of the sidebar. Opening a board used to slam its row to a heavy solid-black highlight; it now uses the same calm treatment as My Tasks / Timesheets / Overseer - a subtle accent background with the board's icon switching to duotone while active. The board-row "⋯" menu adapts its color to the lighter highlight so it stays legible.
- The Boards "+" reads as a real action. The add-board control next to the Boards header was a faint ghost icon with almost no presence; it's now a defined button (border and surface fill, with a subtle hover state) so creating a board feels like a deliberate call-to-action rather than an afterthought.
- Inter is the new app typeface. Truetask now renders in Inter - the variable font Linear uses - instead of Roboto Light, for a cleaner, more legible UI. It's fully self-hosted from
/static/fonts/inter(latin + latin-ext, normal + italic; no CDN) and set as the primary family on thebody, the Tailwindsansstack, the--font-sanstoken, and the notes/description editor. The base weight moved from 300 (Roboto Light) to 400 (Inter Regular) to match Linear's solidity. Roboto stays bundled as the fallback for now. - Any file type can now be uploaded. File uploads previously enforced a fixed MIME allow-list and rejected anything unrecognized - a
.movscreen recording, a.heicphoto, an arbitrary binary - at upload time. That restriction is gone: the Files view, card attachments, and Trello import now accept any file type, so a workspace can store whatever it needs. The stored MIME type still drives in-app preview - images, video, audio, PDF, and text play inline, and everything else offers a clean download/open-in-tab fallback - and the per-file 500 MB ceiling plus the workspace's configured upload-size limit still apply, so an oversized file is still turned away on size (with a clear message). - Opening a task from Timesheets stays in Timesheets. The "open task" affordance across the report (table cell popovers, the week calendar, and the chart drill-down) used to launch a new browser tab on the task's board. It now opens the task in a floating card frame right over the Timesheets view - on its Time tab, loading cross-board on its own - so you can read and edit a task's context without losing your place in the report.
- The estimate budget pill got a real tooltip, and over-budget shows up when you open a task's entries. The pill's hover explanation is now a proper styled tooltip (instead of the browser's plain title bubble), mounted lazily on hover so a table full of rows stays light. And the over-budget warning - already on the pill and summary card - now also appears at the top of a cell's entry popover, so a task that's over its lifetime estimate is flagged even while you're looking at the day's entries.
- The Approve button always sits in the same place in the Approvals queue. It's now the rightmost action on every row - immediately left of the view-entries eye - so it lines up whether a row also offers Request changes (a week with time) or just Approve (an empty "No time" week). Supervisors click one consistent spot down the column instead of chasing it left and right.
- Locking is now visible and explained, not just enforced. The Approved status pill wears a padlock on both sides of the loop; approving shows "Approve - locks these entries against edits" on hover and confirms with "Approved - entries are now locked". In the worker's Timelogs, locked days look different at a glance - a soft green wash over the whole column, a lock marker on the day header, and add/drag affordances that visibly refuse - so nobody discovers the lock through a failed save.
- The Approvals filter tabs no longer nudge their neighbors when the active tab's label turns bold (the bold width is reserved up front).
- Approval status moved into a status bar at the bottom of the Timelogs popup. The title bar was getting dense, so the approval conversation now lives in a slim bar under the calendar: the status pill and the manager's message sit on the left, and the one action that fits the state - "Respond" (with an attention ping), "Request changes" on a locked period, or "View request" while a reopen request awaits - sits flush right. Status is a label and the action is a button; the pill no longer secretly doubles as a click target. The bar is always present so the calendar height never jumps between weeks.
- The Approvals queue got a real design. Status filter tabs with counts (All / Pending / Changes requested / Approved), uniform rows - avatar, week, total, status pill, and actions in a fixed layout - with the request-and-reply conversation threaded under each row. New affordances: "Edit request" to amend the message without restarting the round, and a quick jump from any row straight to that person's week in the Table view.
- Weekend columns are striped in the Timesheets table and week calendar, matching the personal Timelogs popup.
- The Timesheets summary strip keeps an even grid. Always exactly six cards (total, active users, tasks worked, daily average, estimates vs tracked, top contributor) laid out in two, three, or six columns - rows always fill completely instead of staircasing. The single-task "Top task" card is gone; idle selected users now surface as a warning line inside the Active users card; every card gained an informative second line (date window, board count, active days); and the estimates card shows a quiet em-dash state when nothing in view carries an estimate.
- The week calendar opens where the data is. It now snaps to the week at the end of the selected range (usually the current week) instead of the start, and merely looking at the calendar no longer silently widens your date range - only deliberately paging to a week outside the range grows it.
- The date-range popover stays open while trying presets. Clicking This Week / Last Month / etc. updates the range, highlights it on the calendar (which jumps to the right month), and refreshes the report behind - without dismissing the popover, so presets can be compared in place. Picking a custom range on the calendar still closes it once both ends are chosen.
- Timesheets is easier to read and drive. Switching between Table, Chart, and Week calendar is now a labeled control with a one-line description on hover - no more guessing from tiny icons. The report window is one clear control: a single popover pairing the preset list with a range calendar, whose button reads back the active window ("This week · Jun 8-12"). This replaces the two separate start/end date pickers and the preset menu that confusingly shared the Filters icon. Toolbar and chart controls also keep their labels on mid-size screens instead of collapsing to icon-only variants.
- The stats panel now steps aside on Files, Notes, and Forms - and comes back on its own. Board statistics describe the board's cards, so the panel no longer lingers over surfaces it has nothing to say about: switching to the Files, Notes, or Forms view - whether by clicking the view tab, following a note link, or opening a board that starts on one of those views - now hides the stats panel instead of leaving it docked or floating over the content. It isn't closed, though: return to a card view (Kanban, List, Calendar, or Timeline) and the panel reappears exactly as you left it. Closing it explicitly still keeps it closed, and since stats don't apply to Files, Notes, or Forms, the stats button now only shows on card views.
- MCP no longer has an enable/disable toggle - access is governed entirely by your API token. The old Settings → MCP switch (and the Health page's MCP "disabled" state) was misleading: the same token that authenticates an MCP client also works against the REST API, so an MCP-only off switch couldn't actually revoke access - and because the flag lived in two places (the workspace setting and the MCP server's own config), an instance could show MCP "disabled" while it kept serving every tool. The toggle is gone; MCP is always available, and you grant or revoke access by issuing or rotating the MCP token. The Health card now reports the MCP server's real reachability instead of an enabled/disabled flag.
- Connecting or disconnecting a repository now requires membership of the target board. Previously any site OWNER/ADMIN could wire a repo to (or unlink it from) a board they weren't a member of; since linking configures that board's integration, it now also checks board membership.
- The List view's table header is quieter. Tidying up under the Rhea theme. The heavy vertical rules between column headers are toned right down - each column's drag-to-resize handle is now a quiet, subtle gray that brightens only when you hover or grab it, so the header reads as clean labels instead of a grid. The stray divider to the left of the select-all checkbox is removed, and the hairline under the header now matches the line between rows exactly (it was a step darker before). And the + New task button is pulled out of the header entirely - Asana-style: instead of crowding the Title column header, it now sits in its own slim row above the table, left-aligned and always present (even on an empty board), staying put while the table scrolls. With the button gone from the header, the whole Title header is clickable to sort again like every other column; clicking + New task opens the same inline draft row as before.
- List view cell hover and selection are calmer - Asana-style. Hovering a cell used to draw a stark blue (Google-Sheets-like) box around it; it's now a soft, subtle gray outline. Clicking a cell still selects the whole row, but the row's own quiet background is the only feedback - the extra thick outline the clicked cell used to get is gone. Keyboard users lose nothing: arrow-key navigation reveals the focused cell with the exact same subtle outline as hover (no separate, heavier focus ring), and because that outline only appears for keyboard interaction, a plain mouse click no longer leaves a lingering box behind.
- The List view's views menu got the same calm, compact pass. The popover behind the No view button was busy and uneven: every saved-view row carried five always-on action icons whose hover never showed (their fill matched the row's, so they read as dead), hard rules split the sections, padding and row heights drifted between the main list and its Group by / Columns sub-panels, and the column toggle had a stray horizontal scrollbar with an odd top margin. It's now one cohesive, borderless menu. A saved view shows just its name at rest - rename, pin, share, set-default, and delete reveal on row hover - while an active state (pinned for you, shared, or the board default) stays lit as a quiet at-a-glance indicator, and every icon button finally has a real, visible hover. The hard divider lines between My views, Configure view, and the actions are gone, replaced by the uppercase muted section labels and spacing used across the app; all rows share one height and one inset rounded-pill hover through the menu and both sub-panels; and the Columns list lost its phantom bottom scrollbar (now a hover-only stealth scrollbar) and its nonsensical top padding.
- The Time Tracker popover lines up on one column. The task list and the See all timelogs footer were inset less than the header and search field above them (a 6px gutter vs. the header's 16px), so the task rows bled wider than the search box and sat a hair to its left - the whole popover looked slightly off-grid. The list and footer now share the same 16px inset as the header and search field, so a task row's hover/selected background lines up exactly with the search box's edges; the gaps between header, search, and the first row are evened out to a consistent rhythm; and the list picks up the app-standard hover-only stealth scrollbar (no reserved gutter shifting the rows).
- The Automation Library's empty state is calmer. With no automations, the panel stacked a boxed lightning badge, a heading, a hint line, and a pair of Install from template / New buttons in the middle of a large empty dialog - a lot of furniture for an empty room, and redundant with the New, Import, and Templates controls already sitting in the toolbar. It now matches the quiet, Linear-style empty states used elsewhere (the card comments feed): a single thin lightning-slash glyph over one muted "No automations" line, centered in the body. The actions stay exactly where they always are - in the toolbar.
- Divider lines are visible in dark mode everywhere - fixed at the token, not per-component. Separators drawn with the app's default border color (the
border-bunder a dialog header, the rules inside dropdowns and popovers, card and panel outlines) were nearly invisible in dark mode: the dark border token sat at level 40 while the most common dark surfaces - popover, muted, and secondary - are all level 38, a two-step difference that read as no line at all. (Light mode was always fine: a 229 line on a 255 surface.) The surfacing example was the Automation Library header, whose underline simply vanished on the dark dialog. Rather than hand-patch that one rule, the dark border token was raised to a level that clears those 38-level surfaces, so every default divider - in every dialog, dropdown, card, and panel - now shows as a subtle hairline in both themes, while staying perceptually quiet on the near-black app background (dark needs a larger numeric step for the same apparent contrast). Light mode is untouched; nothing that set an explicit border color changed. - The Notes browser now reads as a sibling of the sidebar's board tree. The notes browser had drifted from the navigation it sits beside: the open note filled with a lighter accent than a selected board and wore a bold title, inactive rows used a different text tone and font size, expanded folders just nudged their children a few pixels right with no guide, and the per-row overflow menu was a horizontal
⋯where the sidebar uses a vertical⋮. It's been matched one-to-one to the sidebar. The active note now uses the exact selected-board fill (sidebar-accent) - the same shade in both themes, no longer a paler, mismatched grey - and drops the bold, so selection reads by background like the sidebar, not by weight; inactive and folder rows adopt the sidebar's text tones and0.825remsize, and open folders switch to the duotone folder glyph. Expanding a folder now draws the same hairline vertical guide descending from the parent's icon, with children indented to match the sidebar's nesting (so two levels deep looks like the Boards → Cloud → Development tree, not a flat list). The row menu is the vertical⋮. And the note's icon button is now an overlay - its own hover state, click to swap the icon - positioned and behaved exactly like the sidebar board icon, so hovering the icon no longer lights up the whole row (the row's hover/selected fill moved onto the inner label button, with the icon and the menu floating above it). Both trees also pick up a small 2px gap between rows - the same rhythm the sidebar's Personal/Workspace nav sections already used - so the board tree (which had been flush) now breathes like the rest of the sidebar, and the notes tree matches it; the expanded-folder guide line stays one continuous stroke straight through the gaps. - The Forms view and its New-form dialog caught up with the rest of the app - fewer lines, a proper tab control, and a broken footer fixed. Forms still wore the pre-Rhea look the other views have been shedding, and the New-form dialog had real bugs. The view sat on a muted canvas; it now sits on the plain
backgroundlike every other view, with each form rendered as a soft floating card (rounded, a hairline ring, a gentle shadow) instead of a hard-bordered slab - and box-free inside: the share URL reads as plain monospace text with quiet ghost copy/launch icons (no boxed chip, nosecondarybuttons), and the action row is one uniform icon cluster - the active toggle (a small switch) plus insights / edit / duplicate / delete, where Edit dropped its odd standalone text label and the toggle its redundant "Active" caption so everything lines up. The empty state is fully borderless now - a centred icon medallion, heading, and button floating on the page with no surrounding card at all (it had been a big outlined box for no reason). The view's heading is also clearer: "Intake forms" rather than a bare "Forms" (the redundant "intake" drops out of the subtitle in turn), while the board tab stays the concise "Forms" to line up with the other single-word view tabs. Inside the New-form dialog, the General / Fields / Sharing switch was a hand-rolled pill cluster with a JS-driven sliding indicator - it's now the app-wide segmented tab control (the same one the board view switcher uses), which also retired ~50 lines of brittle indicator code. The dialog's footer was escaping its own rounded corners - the shared footer assumes the dialog's default padding, but this dialog (like the Insights and Preview dialogs) renders edge-to-edge, so the footer's negative margins pushed it past the dialog edge; all three now pin the footer flush so the actions sit on a cleanpaneltray with rounded bottom corners. The header underline, the tab-bar underline, and a mid-form divider are gone - content is grouped by tone and spacing now, leaving only the one intentional line above the footer. The Fields tab's contrast mess - cards nested inside cards inside the dialog, each with an inner header strip in a fill that's invisible on a dark surface - is rebuilt as single soft tiles: one accent-filled card per field, no inner strips, no boxes-in-boxes. The "Add a field" bar is pinned to the top of the Fields tab while only the tiles scroll beneath it - so the field-type chips stay reachable however long the list grows - with a hairline that fades in under the bar only once the tiles are scrolled (line-free at rest). Every input across all three tabs now shares one fill - a softcardwell - so they read identically on the plain dialog body and inside the accent field tiles; an earlier pass had made the in-tile inputs pure black to fight the fill, which left them inconsistent with the General tab's softer inputs. The "Submissions land in" picker now shows each list's colour dot (and tints a Done-category list green), mirroring the List view's status dropdown, instead of a bare name. And adding or removing a field is now animated: a new field's tile expands open (height + fade) as the chip you tapped scales out of the "Add a field" row, and removing one collapses its tile shut so the fields below glide up to fill the gap while its chip scales back in - the two ends of the same gesture, kept in sync, snappy (~200ms), and honoring "reduce motion". (The collapse is a self-sizing transition, deliberately notanimate:flip, so it never fights SortableJS's drag-reorder.) Dragging a field to reorder it is fixed and polished: the lifted tile is appended to the page(fallbackOnBody) so it tracks the cursor and floats above the dialog uncut - previously, the dialog's centringtransformmade theposition:fixedclone resolve offset from the grab point, and the fields'overflowscroll clipped it at the dialog edge - and it now reads as a raised card (hairline ring + drop-shadow) like the app's other floating panels, gliding displaced tiles aside at the shared 200ms with edge auto-scroll for long lists. The Sharing tab's password field reveals on that same motion - flipping Require a password now expands or collapses its input on the height-and-fade transition instead of snapping in. The Sharing tab's mismatched radii (the URL prefix, the URL input, and the password box each rounded differently) are unified - the URL is one bordered control with a single radius, the sameh-8height as every other input (it had been noticeably shorter), and the password block is a soft accent panel that matches - and the two heavy "scope note" callouts shrink to one quiet helper line, since each field's own help text already explains it. The two boolean settings - Close-only mode and Require a password - are now switches in the app's standard setting-row layout (label on the left, switch on the right, vertically centred) rather than top-aligned checkboxes. The dialog is also narrower (it had stretched its inputs across ~1100px of sparse width) so the form reads at a comfortable measure. The Insights dialog gets the same treatment: soft stat tiles, a borderless recent-submissions list, no dashed empty state. - The List view's list column is now "Status", not "State". This release gives every list an explicit flow state (Idle / In Progress / Done / Cancelled), so calling the column that shows which list a card sits in "State" collided with the new meaning. That column, the filter, group-by, and export label it shares, and the My Tasks list grouping ("No State" becomes "No Status") now read Status - what the column has always meant: the card's place in the workflow. English and French were updated (
Etat/ÉtattoStatut); Spanish, German, and Portuguese already used the right word (Estado/Status), so they are unchanged. The flow state itself keeps its name in the Board Flow dialog and the automation pickers.
Removed
- The redundant Automations bolt button left the view toolbar. A standalone lightning button sat beside the view tabs as a shortcut into the Automations view - but that view now has its own first-class Automations tab, so the button only duplicated the tab right next to it. It's gone; the tab is the one way in (the board's contextual Automate this... surfaces are untouched).
- "Hide done tasks" is gone - and the preferences popover drops its lone tab. The board-preferences popover (the toggle-switch button in the board toolbar) carried a Hide done tasks switch that, on Kanban, simply hid completed cards from view. It was a blunt client-side filter - the cards were still loaded, just hidden with
display:none- overlapping with the real filters and saved views, and almost nobody reached for it, so it's removed: the toggle, the kanban-card hiding logic, and thepreferences.board_hide_done_tasksfield itself (dropped by a schema migration; any stored value is discarded when it runs) all go. With it gone, the Behaviour section was the only thing the popover had to show outside Kanban - where the Display tab (card styling, board layout) doesn't apply - so the now-pointless single Behaviour tab is dropped too: off Kanban the popover shows the behaviour settings directly with no tab bar, while on Kanban the Display / Behaviour tabs are unchanged. - Shaking a floating frame no longer flashes it. Dragging a card frame (or any floating panel) back and forth used to trigger a shake detector that flashed the frame's outline - a leftover easter egg that mostly fired by accident during quick repositioning and read as a glitch. The shake detection and its flash are removed; dragging is now just dragging.
- List descriptions are gone - the per-column "info" popover. Each kanban list carried an optional rich-text description: a small info icon in the column header opened a full Milkdown editor for "what goes in this list, what doesn't." In practice it went almost entirely unused (even on our own boards), was easy to miss, and overlapped with the board's own context and Notes - so it's removed rather than carried forward through the Carta→Milkdown editor migration. Gone with it: the popover, the boilerplate list guidance seeded onto new boards (To Do / In Progress / Done), and the column's
descriptionfield itself (dropped by a schema migration). Cloning a board, importing one, and saving one as a template no longer copy list descriptions, and thedescriptionargument is removed from thelists_create/lists_updateREST and MCP tools. Existing list-description text is discarded when the migration runs.
v1.3.071
New
- Updatinng stale version file VERSION file got stale, fixed deployment
v1.3.070
New
- Cleanup deployment repo Trying again
v1.3.069
New
- Cleanup deployment repo I had a lot of old tags, removing now
v1.3.068
New
- Time estimates over the REST API and MCP. A task's time estimate - the planned-effort budget already on cards in the app - can now be read, set, and cleared through the REST API and the MCP server, so agents and integrations can manage estimates the same way people do in the UI. Each card has a dedicated estimate endpoint (get / set / clear) that returns the estimate next to the tracked total, so budget-vs-actual comes back in a single call, and the estimate can also be set inline when creating or updating a card. Estimates are whole seconds (0 means no estimate), and changes show up in the card's activity feed exactly like edits made in the app.
Changed
- Upgrade prompts now name the exact plan a feature needs. When you open a feature that isn't in your current plan, the prompt now tells you precisely which plan unlocks it - e.g. "Active Directory sync is available on the Enterprise plan" - instead of a vague "available on a paid plan." The required plan is read from the live plan catalog, so each feature points to its real tier (Pro, Team, or Enterprise) and stays correct if a feature ever moves between plans.
- New Truetask Cloud workspaces start with AI switched on. A freshly provisioned cloud workspace now enables AI and all of its assist features out of the box - card-description, tag, inline-title and checklist suggestions, comment-thread summaries, and starter AI automations on new boards - all routed through the included Truetask AI model. Tool use (agent) stays off, since it's a paid capability. Owners can still turn any of it off under Settings → AI. Self-hosted installs are unchanged: AI stays off until you connect a model.
- Clearer tabs in the Automation Library. The Automations and Templates tabs now read as a proper segmented control - the selected tab sits in a raised, outlined pill with a bolder label and icon, so it's obvious at a glance which view you're on.
- Snappier board and folder creation in the sidebar. Pressing Enter to add a board or folder now hides the input field right away and creates the item in the background, instead of waiting on the server and revealing the change in visible steps. On higher-latency connections this no longer feels sluggish - the new board or folder simply appears (and for a board, you're taken straight to it). If creation fails, the input reappears with your text intact so you can try again.
- Faster repeat loads - the app caches its own code properly now. Truetask's interface is built from content-hashed files (a file's name changes whenever its contents do), which makes them safe to cache permanently - but they were being served with only a 4-hour cache, so returning to the app re-downloaded the whole interface several times a day. Those build assets are now sent with a one-year immutable cache, so after your first visit the browser reuses them until the next update - meaningfully quicker reloads, especially on slower connections, with no extra network traffic. The service worker is explicitly kept non-cached so updates still roll out immediately.
- The sidebar is now resizable. Drag the right edge of the sidebar to make it wider or narrower; your chosen width is remembered on this device, and double-clicking the edge snaps it back to the default. The width is kept within a sensible range so navigation labels and board names always stay readable.
- Right-clicking the boards area opens one fuller menu. The menu you get when right-clicking empty space in the sidebar's boards section now gathers everything in one place - New Board and New Folder, New from Template and Import, a Visibility submenu to show or hide the top navigation items (My Tasks, Timesheets, Overseer), and a shortcut to Customize sidebar - with separators grouping each set. The "+" button keeps its focused, add-only menu.
- A customize control is always within reach in the sidebar. The sidebar header now carries a small customize button next to the workspace name that opens the Customize sidebar dialog. This guarantees a way back to hidden items: previously, hiding "My Tasks" could remove the only entry point for turning it back on.
- Tidier sidebar section headings. The personal group now has its own collapsible "Personal" heading to match "Workspace", and the divider line between the navigation and Boards has been removed so the groups read as one consistent list. A heading now also disappears together with its items when you hide them all - no more empty section labels - and the header's customize button brings everything back.
- A cleaner, more focused comment composer on cards. The comment box at the bottom of a card has been redesigned. The typing area now sits on its own line, with the attach and send controls moved to a dedicated row beneath it, so the actions are clearly exposed instead of crowded in beside the text. The whole box reads as a single, slightly raised panel that lights up when you focus it, the text is a touch smaller and tighter, and the send button fills in once you've written something. Posted comments in the thread now render at that same smaller size, so the message bubbles and the box you type in finally match and the whole conversation reads consistently. Everything the composer could do before still works: it grows as you type, supports full Markdown (including the slash menu, @mentions, and note links), accepts file attachments, and sends on Enter.
- The card header's time controls are now one tidy button. The time estimate and the start/stop timer have merged into a single stopwatch button in the card header - matching the workspace timer button in the top bar - and the inline "1h 30m / 2h" readout no longer lives in the toolbar, so the row of header icons stays put instead of shifting sideways whenever an estimate is added or changes. Clicking the stopwatch opens a compact Time panel with a prominent Start timer button, the tracked-vs-estimate budget bar, and the estimate editor: a field with a leading hourglass for free-form input like "2h 30m", quick chips beneath it (including a "0m" that clears the estimate), and a compact Save button that appears inside the field only once you actually change the value. The stopwatch glows green while a timer is running, and the full timer still lives in the card's Time tab too.
- Plan changes show up faster on Truetask Cloud. When you reload the app, it now quietly re-checks your workspace's plan with the billing service in the background and updates in place if anything changed - so an upgrade, downgrade, or trial change is reflected without waiting for the periodic sync. It never blocks the page, and it's rate-limited so reloads and extra tabs can't hammer the service. And right after you complete a purchase, the Plan view now shows a "Finalizing your purchase…" indicator and watches for the new plan to land (rather than briefly showing your old plan), so there's no moment where it looks like the payment didn't go through. If your plan changes while the app is already open - say a teammate upgrades, or a renewal goes through - the change now applies live for everyone in the workspace, and owners/admins get a toast with a "See plan" shortcut.
Fixed
- Fixed a crash in the sidebar's Visibility menu. Opening the Visibility submenu inside a sidebar item's right-click menu threw an error and could fail to render because its heading wasn't wrapped in a menu group; the heading is now grouped correctly and the menu opens cleanly.
- Finishing the welcome setup now sticks on every device. Completing the first-run setup wizard is remembered on your account instead of only in the browser you happened to use, so signing in from another browser or computer no longer replays the welcome steps. Previously the "done" marker was written to the browser first and the account record only as a best-effort afterthought, so a different device - or a cleared browser - could show onboarding again even though you'd already finished it. The wizard now also stays open and lets you retry if saving that completion ever fails, rather than closing as if it had saved.
v1.3.067
Changed
- The welcome board's first task now points you to My Tasks. Because new sign-ins land directly on the Welcome board, the starter task assigned to you - now titled "Open me in My Tasks" - explains that everything assigned to you across every board collects under My Tasks and how to get there, instead of telling you to open the board you're already looking at.
Fixed
- Truetask Cloud workspaces apply trial and plan changes immediately again. Starting the no-card free trial on a hosted workspace appeared to do nothing - and a second attempt said the trial was already active - yet no features unlocked. The Portal was recording the trial correctly, but the workspace couldn't read the result back: every plan/trial/managed-AI sync authenticated with an admin login that hosted stacks intentionally don't have, so the local entitlement snapshot never updated. Hosted workspaces now pull their authoritative plan from the Portal over the internal service channel, so the trial (and any Stripe upgrade, downgrade, or cancellation) takes effect right away, and the managed-AI key syncs too. Self-hosted installs are unaffected.
- Your avatar updates everywhere the moment you change it. Changing your profile picture or colour (for example in the first-run setup wizard) now refreshes your avatar instantly on the cards you're assigned to - not just in the top corner. Previously a card kept showing your old initial and colour until the page was reloaded or the card's members were edited, because each card held a snapshot of its members taken when it first loaded. The signed-in user's avatar is now read live wherever it appears.
v1.3.066
New
- Time estimates on cards. A card can now carry a time estimate, set from a small hourglass control next to the timer in the card header (and from the Time tab). The popover takes natural input - type
2h 30m,1d 4h, or90m, or tap a quick chip (15m, 30m, 1h, 2h, 4h, 1d) - using working-time units (1d = 8h, 1w = 5d). Estimates are stored in seconds so they line up exactly with tracked time. - Budget vs. actual. When a card has an estimate, the Time tab shows a budget bar comparing tracked time against the estimate (turning red once you go over), and the header shows an at-a-glance
tracked / estimatereadout. Estimates and this per-card comparison are part of time tracking (the Pro plan on Truetask Cloud); self-hosted installs get everything. Estimate changes are recorded in the card's activity feed.
Changed
- Smoother sign-in mode switch. Switching between password and one-time-code sign-in on the login page is now animated instead of jumping: the email field stays put, the password field gently expands and collapses (fading and scaling rather than popping in and out), and the button label, helper text, and headings crossfade as the mode changes. The whole interaction is quick and subtle, and honours the system "reduce motion" setting.
- Faster startup for self-hosted instances. Container initialization no longer launches a throwaway database server before configuring the instance, authenticates to the local database once instead of for each setting, and applies instance settings (backups, batch requests, rate limits, SMTP, app URL) in-process as the database boots rather than through a series of follow-up requests. The database reaches its ready state with less work on every boot - and noticeably faster on a new workspace's first start - so the rest of the stack, which waits on the database, comes up sooner. No change to configuration or behaviour.
Fixed
- New Truetask Cloud workspaces can always create their owner. Provisioning a hosted workspace could fail to create the owner account - and so leave the customer unable to sign in at all - when the workspace's plan limits hadn't yet synced from the Portal: the seat limit resolved to zero and refused even the very first user. A workspace can now always seed its first user, and an unsynced free workspace falls back to its standard 10-seat limit instead of zero. Self-hosted installs are unaffected (seats are unlimited there).
v1.3.065
Changed
- Cloud workspaces report their first sign-in to the Portal. On Truetask Cloud, a workspace now tells the Portal once when a user first signs in, so newly provisioned-but-unused workspaces aren't reaped. Best-effort and cloud-only - self-hosted installs never contact the Portal, and a Portal outage never blocks or slows sign-in.
v1.3.064
New
- Passwordless email sign-in (one-time code). The login page now offers an 8-digit one-time code sent to your email as an alternative to your password. Enter your email to receive a code, then type or paste it - pasting validates and signs you in automatically. Codes expire after 10 minutes, and you can switch between code and password sign-in at any time. Accounts are still created by an administrator; there is no self-registration.
Fixed
- Uploading many files at once no longer trips the server's rate limit. Bulk file uploads now pace their record creation to stay within the create-rate limit (and retry automatically if they hit it), instead of bursting past it and failing partway through with a "Too Many Requests" error.
v1.3.063
Changed
- Deployment test Testing deployment integration with the Portal
v1.3.062
Changed
- Deployment test Yay
v1.3.061
Changed
- Self-hosting is now Docker Compose only, from pre-built images. Truetask no longer builds images on your server. Each release publishes versioned container images to the registry; you install by cloning the deploy repo, running
./build_env.sh(which logs Docker into the registry and writes your.env), thendocker compose up -d- images are pulled, not built. Update withgit pull && docker compose pull && docker compose up -d. The native macOS/Windows desktop installers have been retired in favour of this lower-friction path (and hosted Cloud instances).
v1.3.060
Fixed
- Notes collaboration starts correctly in production installs. The packaged server now includes the self-hosted Yjs service and allows the editor's embedded font/WebSocket resources through the CSP, preventing the
/yjs/healthz502 and blockeddata:font console errors when opening Notes. - Notes edited by MCP/API no longer get hidden by stale collaboration state. The Notes editor now treats the PocketBase note snapshot as the durable source when joining a Yjs room, refreshes the active editor when realtime note updates arrive, and disconnects collaboration cleanly during teardown.
- Notes collaboration no longer trips Svelte's unsafe state mutation guard. Milkdown/Yjs lifecycle callbacks are bridged safely into Svelte, stale editor callbacks are ignored after note switches, and collaboration status is reset by the Notes view instead of editor teardown.
- Notes inline creation no longer visually pops. New note and folder draft fields now disappear immediately after validation, then reopen with the original text and an error toast if creation fails.
v1.3.056
New
- Board Files. Added a new Files board view after Timeline with a Windows-style explorer layout: All Files, task attachment folders, nested free folders, thumbnail/list views, search/filter/sort, uploads, previews, downloads, rename/move/delete actions, and a live details panel.
Updated
- Board Files drag-and-drop, previews, and folder creation are more complete. Files can be dropped onto folders, task attachment folders, the main file area, or the tree; aggregate drops prompt for a destination, files can move between tasks and folders, task folders open their task on double-click from the left tree,
.txt/.mdfiles preview through Milkdown, folders are created inline from the tree, and the details panel has a remembered toggle. - Forms view tabs now behave like the other board views. Forms is visible by default on new boards and no longer appears as a dismissible dashed nudge; users can still hide it from View Preferences.
- Markdown selection toolbars now wait for mouse selection to settle. The formatting toolbar hides while you drag-select text and reappears after release, avoiding the jumpy repositioning during selection.
v1.3.054
New
- Board Notes. Added a new Notes board view: a board-scoped Markdown vault with folders, search, note comments, version history, ZIP export, MCP/agent read tools, and self-hosted Yjs collaboration using Milkdown Crepe.
- Notes wikilinks. Notes now support Obsidian-style
[[Note]]and[[Note|Alias]]links with autocomplete, clickable unresolved-link creation, stable link indexing, and backlinks. - Obsidian vault import. Notes can import a local Obsidian-style folder tree, recreating folders and Markdown notes in the board vault.
- Public Notes links. Publish a live, read-only Notes link for a note, folder tree, selected notes/folders, or the full notes section, with optional shared-password protection and custom URL slugs.
Updated
- Dark theme. Tweaked some colors around the dark theme, specifically for the Kanban board.
v1.3.053
New
- API and MCP clients can upload task cover images directly. Agents and integrations can now send PNG, JPEG, WebP, or GIF bytes to set a task's cover image without relying on the website metadata auto-cover flow or the external-fetch setting.
v1.3.052
Fixed
- Saved List views now preserve resized column widths. Saving a view captures the current table column widths, loading a view applies those saved widths the first time, and any later resizing is remembered locally per view so subsequent loads keep the user's adjusted layout. Reverting or saving the view clears that local override and returns to the saved layout.
v1.3.051
New
- The command palette (Cmd/Ctrl + K) does much more. Jump straight to My Tasks, Timesheets, or Overseer; run a board's manual automations; create an API token or webhook; open any settings section; and switch between light and dark themes. Everything shown is filtered to your role, so you only see destinations you can actually open.
Improved
- Redesigned the command palette. The search box is larger and clearly set apart, and it stays pinned near the top so it no longer shifts as results change while you type. Opening and closing it is now a soft fade instead of a slide, and the placeholder reminds you that you can search tasks and boards too.
- New accounts get a clearer first step. A brand-new account now opens onto an "Open the board" task that points you to your board, where the getting-started cards live.
- Tidied up the task panel in My Tasks. Removed the redundant close button - selecting another task or opening the board already moves you along.
Fixed
- Editing a tag's name from a task no longer breaks the tag picker. Renaming a tag inline could throw an error; it now works correctly.
v1.3.050
Fixed
- AI-output automation fields no longer come pre-filled with a literal
{ai.output}. Set Description, Set Title, Add Comment, and Apply Tags nodes now start empty with{ai.output}shown as a faint placeholder hint instead of as actual text in the box; leaving the field empty still uses the upstream AI node's output exactly as before. - "Set Description" and "Set Custom Field" automations now have a "Clear" toggle. Turn it on to deliberately empty a card's description or custom field value (e.g. a "clear all descriptions in this list" workflow). Previously a blank Set Description field meant "use the upstream AI output", so there was no unambiguous way to wipe a value - an automation built to do so just errored. The toggle disables the value input and clears the field directly; a cleared custom field matches how clearing it in the card view behaves. The safeguard that stops an AI step from wiping a description when it produces no text is unchanged.
v1.3.049
Fixed
- Setting a card's custom field value through a connected AI assistant (MCP) works again. Asking an MCP client to create or update a custom attribute silently failed - the value never reached the server. These writes now go through correctly.
- The automation editor no longer prints debug output to the browser console. Dragging nodes in and out of grouping sections used to log a line on every move; that noise is gone.
v1.3.048
Fixed
- Automations that use visual grouping sections now run. Wrapping nodes in a labelled group container in the automation editor caused "Run now" (and triggered runs) to fail with an "unsupported node type" error, because the group container itself was treated as an executable step. Group containers are now recognized as visual-only and ignored at run time.
- Automations no longer log duplicate runs under heavy bursts. When many cards were created or changed at once, the same event could be picked up twice, producing a duplicate entry in an automation's run history (the action itself only ever ran once). Event pickup is now serialized so each event is handled a single time, and the noisy server-log errors that came with it are gone.
- Multiple automations on the same event no longer block each other. When two automations fired on one event - say an AI hydrate that generates a description and tags, plus a quick "set title" - the fast one used to wait behind the slow AI one, so the title only appeared once the AI call returned. Automations triggered by the same event now run independently of one another, so a quick automation takes effect immediately no matter how long an AI automation on the same event takes.
- List view keeps the checkbox, priority, and title columns locked at the front. Dragging a column in the table header could slip it ahead of priority or into the gap between priority and title. Those three leading columns are now fixed in that order - they can't be dragged and nothing can be dropped onto them - and any saved layout where a column had previously slipped in between is corrected automatically.
- Condition / Filter automations match multi-value selections correctly. Comparing against several values at once (a multi-select custom field) silently never matched before. A selection now matches with "any of" semantics on positive operators (equals / contains) and "none of" on negative ones (not equals / not contains).
- Automation nodes after "Duplicate Card" or "Create Card" now act on the new card. A chain like "Duplicate Card → Assign Member" (or set priority, add comment, tag, etc.) used to apply to the original trigger card, leaving the freshly made copy untouched - so the duplicate never got assigned. Steps after a duplicate or create now operate on the card that was just made. If you specifically need a later step to act on a different card, add a "Target Card" node to switch focus.
Improved
- Condition / Filter automations show the right value picker for the field. Comparing a card's Priority or Tags now gives you a multi-select dropdown of the board's actual priorities / tags - styled like priorities and tags everywhere else - instead of a free-text box where names had to be typed exactly. You can pick several to mean "is any of". Custom-field comparisons continue to adapt their input and operators to the field type (checkbox toggle, date picker, number, single/multi-select).
- Settings → AI: adding a model no longer asks which capabilities it has. You used to pick a model's capabilities when adding it, then separately choose a model for each capability under Routing - declaring the same thing twice. Every enabled model is now treated as capable of everything, and Routing is the one place that decides which model handles generate, suggest, summarize, and tool use. Existing routes keep working unchanged.
- Removed the minimize button from floating task windows. It collapsed a floating card to an unlabeled bar that wasn't collected anywhere, so it added clutter more than convenience. Floating cards now simply open and close.
v1.3.047
Fixed
- Webhooks reject dashboard URLs up front with a clear error. Pasting
https://webhook.site/#!/view/…(the in-browser dashboard URL) instead of the receiver endpoint used to save silently and then fail every test with a confusing 404 - browsers strip the#…fragment before sending, so deliveries actually went to the host root. The webhook form now refuses any URL containing a fragment and explains why, so the mistake is caught at save time instead of after the first failed delivery. - Webhook board scoping actually scopes now. The "fire only for these boards" picker has never worked - every active webhook fired for every board regardless of selection, because the boards array was being written to a field the collection didn't have. The schema is corrected and the selection is now honoured; existing webhooks remain wide (empty selection = all boards) so nothing stops firing unexpectedly.
card.movedandcard.deletedwebhooks fire now. Both events have been silently dropped since launch -card.movedwatched the wrong source (list-membership arrays that aren't updated on moves), andcard.deletedonly fired on hard purges, missing every normal user delete (which the trash workflow handles as a soft delete). Both now fire correctly off the card record's own state change; existing receivers don't need to change anything.- "Duplicate Card" automation with target list = "First open list" now actually skips Done lanes. The Python port of this action filtered against a non-existent
closedfield on the lists collection (the schema's field iscategory, a select with valuesopen/done). The filter always matched zero rows and fell through to "first list regardless of category" - so a duplicate could end up in a Done lane if Done happened to sit at the leftmost index. Filter now matchescategory="open"and picks the lowest-index open lane, exactly like the docs and the editor's tooltip imply. If every lane is Done, the action fails loudly instead of writing into one. - Automations with a "Move to Board" action no longer silently destroy state when configured to move to the same board. Cross-board moves clear tags / members / priority by design (those are board-scoped relations). If the editor's destination board resolves to the same board the card is already on - a likely misconfiguration - the action now refuses with a clear pointer to use "Move to List" instead, rather than wiping state.
- HTTP Request automation header values now resolve placeholders. Body and URL already substituted
{actor.token}/{card.id}etc., but headers were passed through literally - so{"Authorization": "Bearer {actor.token}"}would send the placeholder text to the remote API. Header values now run through the same substitutor as body and URL. - "Mark Completed" / "Mark Uncompleted" automation handles MCP-imported and hand-edited configs that send
"true"/"false"as strings. The editor coerces its select values to Python booleans on save, but JSON imports and SDK callers can send strings. Naive coercion (bool("false")= True in Python) would silently flip cards the wrong way; the handler now treats strings explicitly. - "If a card has priority X" automation conditions actually work now. Same root cause as the tags / members fix below:
_resolve_lhsreturned the priority record ID when users typed"high","medium"etc., so the comparison silently never matched. Resolves the priority ID to its display name before comparing. - "If a card has the X tag" / "If a card is assigned to person Y" automation conditions actually work now. The Condition / Filter nodes'
tagsandmembersfields were comparing against the underlying record IDs (e.g.t_bug_id,u_alice_id), not the human-readable names the editor shows. Sotags contains "bug"ormembers contains "alice"silently never matched - automations like "duplicate the card if it's tagged 'bug' on completion" would log as triggered but the action would never fire because the filter dropped the walk. Both fields are now resolved to lowercased, comma-joined names before the comparison, so the value the user typed in the editor is the value being compared. Missing tag / user records are skipped silently; the comparison continues with whatever resolved. Member name resolution falls back to email when the user record has no name set (LDAP-only accounts). - Workflow / Agent automations no longer open their final reply with a transition sentence. The anti-fluff rules in the agent system prompt forbade openers like "Here's…", "Done!", "Let me…" but didn't explicitly cover the tool-use → final-output transition pattern ("I now have the data I need. … Here is the synthesized report:") that some models still emitted before getting to the deliverable. The rule is tightened to require the first character of the reply to be the first character of the deliverable itself - examples listed include "I now have…", "Based on what I found…", "Here is the report:", etc. Existing admin edits in the AI Prompts dialog are honored; fresh installs pick up the tightened rule from the migration. The inline fallback used when the prompts collection is briefly unreachable was updated to match. As a defence-in-depth safety net (some models ignore the rule no matter how loudly we phrase it), the agent's final text is also scrubbed on the server side before it reaches downstream nodes: if it opens with one of the known transition shapes AND a clear deliverable boundary (markdown heading, horizontal rule, code fence, etc.) follows, the preamble is stripped. The raw text is preserved in the run transcript so admins can still see what the model emitted vs. what landed in the comment / description.
- "Parse JSON" automation node returns boolean values as
true/falseinstead of Python-flavouredTrue/False. When you extracted a boolean leaf via{parsed., the value used to come back capitalised, so a downstream Condition node comparing. } {parsed.x.flag} == truewould silently never match (it was actually"True"). Booleans now match the JSON convention (and the rest of the placeholder system), so conditions work the way the editor implies. - "Assign Member" / "Unassign Member" automation actions now correctly assign the triggering user when configured to do so. The editor's member picker has a "Triggering user" option that saves the placeholder
{triggering_user}- meant to resolve to whoever fired the automation - but the backend was treating that placeholder as a literal username and silently failing the lookup ("User not found"). It now reads the actor from the event payload and assigns/unassigns that user. Picking a specific board member by name continues to work the same way.
Improved
- "Duplicate Card" automation now drops the copy at the bottom of the target list, and running a manual automation scrolls you to the new card. Previously the duplicate landed at
source.position + 1, so a Clone triggered from a mid-list card placed the copy next to the source - easy to miss. The new card now lands strictly past the current last card. When you run a manual automation from the toolbar or card frame, the originating session also auto-scrolls the destination list to bring the new card into view (other sessions watching the same board don't scroll). - Forms now have an Active/Inactive switch on each card. Inactive forms stay in the list so you can flip them back on later; their public URL returns 404 while off. Replaces the old Archive / Restore flow.
- Form insights moved into their own dialog. Click the chart icon on a form card to see views, submissions, conversion, and recent submissions - no longer buried inside the form editor.
- Public form headers are centered. Logo, title, and intro now sit centered at the top of the form page (and the in-editor preview).
Fixed
- AI-driven automations no longer time out the originating request, and now respect the full board context regardless of how they were triggered. Form submissions, in-app card creates, card updates, scheduled / milestone / due-date crons, manual editor "Run now" - every path that fires an automation used to block on the agent's full execution time (often 20+ seconds), and the originating HTTP request would 500 before the agent finished. The entire automation engine was rewritten as an async pipeline: any event that triggers an automation now returns immediately while the agent runs out-of-band, with per-trigger retry on delivery failure and stale-claim recovery if the engine restarts mid-run. Retries that come back after an interrupted run no longer double-fire writes (comments / xattrs / card updates); a per-node idempotency log dedupes them. Automation activity now exposes a queue-depth metric for operators, so a backed-up engine becomes visible before users notice.
- Realtime updates from fast-firing automations now reach the tab that created the card. Creating a card in tab A and watching it from tab B always worked - tab B saw the automation's description / tag updates land within a second. Tab A didn't, because the optimistic-create code path was suppressing "the next realtime event for this card" to silence its own create echo, and a fast automation's subsequent UPDATE was getting eaten instead. The echo is now handled by separate guards that don't race with downstream updates, so tab A sees the same live updates everyone else does.
- Board imports preserve the source board's view configuration. Exporting a board has always carried the
preferred_view(admin-pinned default view) andvisible_views(which tabs the toolbar shows) inside the JSON - but the importer never read them, so re-importing always landed on the schema defaults (Kanban default, all views visible) regardless of what the exporter intended. The importer now reads both fields with the same validation the Clone path already uses, so a board that shipped as "List view by default, Forms hidden" imports the same way. Older exports that predate these fields fall through to schema defaults exactly like before. - "Generate Description" / "Set Title" automations no longer wipe the card the moment they finish. The graph editor's Description and Title nodes advertise
{ai.output}as the default value - meaning "use whatever the upstream AI node produced" - but the field only persists to the saved automation if the user types it, and the backend wasn't honouring the displayed-but-unsaved default. Result: a "Generate Description → Set Description" chain would write the AI text, then the Set Description node would resolve its (empty) configured value and overwrite the same field with a blank, so users saw the description flash in for a second and then vanish. The backend now treats an empty Set Description / Set Title config as if the user typed{ai.output}(matching the editor), and refuses to write a blank value at all when there's no upstream AI text to inherit - so the worst case is "automation does nothing", never "automation deletes your content". - "Apply Tags" automation actually applies the tags now. The editor saves the tag source to
config.tags_input, but the Python backend was readingconfig.tags(a different name that the editor never writes), so every editor-saved Apply Tags node silently no-op'd. The handler now reads the right field, understands theEXISTING:/NEW:/NONEgrammar the editor documents (creating missing tags on the fly whenNEW:foois used), merges into the card's existing tags instead of replacing them, and defaults to{ai.output}so a Suggest Tags → Apply Tags chain works without extra configuration. - "Set Dates" automation actually sets dates now. The editor's Set Dates node persists a structured shape (
target= end / start / both,mode= offset / absolute / clear, plus the relevant numeric or date fields), but the Python backend was reading literalconfig.start/config.endISO strings that the editor never writes. Every editor-saved Set Dates node returned "No dates configured" and did nothing. The handler now interprets the editor's full grammar (including the Clear mode that explicitly blanks out the target field). - "Delay" automation respects the editor's default unit again. The editor's Delay node displays "Hours" as the default unit, but only persists
config.unitif the user opens the dropdown - so a delay configured as5with the displayed "Hours" default would silently run as 5 minutes against the Python executor (which had defaulted to minutes). Default is now "hours" on both sides, so accepted-default delays behave the way the editor says they will. - "Duplicate Card" automation handles the "First open list" target and the per-field xattr whitelist correctly. Picking "First open list" as the target now actually finds the first non-closed list on the board (it used to be treated as a literal list name lookup, which always failed). The "Copy custom fields" option's per-field selector also works now - the editor stores field NAMES in the whitelist, but the handler was comparing them to xattr value field IDs, so every xattr was always skipped. Names get resolved to IDs before the membership check.
- Workflow (multi-tool agent) automation can actually write again. The editor's Workflow node lets you check write tools (Add comment, Update card, etc.) directly in the capability list - no separate "permissions" section like the simple Agent node has. The Python executor had a second permission gate inherited from the simple-agent path that required
write_permsto be populated, so every write tool the user enabled on a Workflow node was silently filtered out at runtime and the agent ran as if it were read-only. The gate now infers the right permissions from the Workflow node's tool selection, matching the editor's "the toggle IS the permission" contract. - AI capability routing falls back to the configured backup model and to the legacy resolver. Settings → AI lets admins configure both a primary and a fallback model per capability, but the backend resolver ignored the
fallbackslot entirely - a workspace whose primary Anthropic key expired silently lost tool-use even with an OpenAI fallback configured. The resolver now tries the configured fallback when the primary is missing/disabled/unsupported, and falls all the way back to the legacy first-enabled-with-capability matcher if neither slot is usable, so a workspace with at least one valid AI model never loses AI on a routes misconfiguration. - AI palette nodes (Generate Description / Suggest Tags / Improve Title / Summarize) no longer write to the card on their own. The editor's help text for every Quick AI node says the same thing: "Produces … as
{ai.output}. Connect to a Set … / Apply … node to write it to the card." The Python port was auto-applying the output anyway - Generate Description appended todescription, the others posted comments - so a chain like "Generate Description → Add Comment" wrote the AI's text BOTH to the description (the auto-apply) AND to the comment (the downstream node). The variants now produce text only, leaving the card untouched, and a downstream Set Description / Apply Tags / Set Title / Add Comment node reads{ai.output}to apply it once. Also: the Suggest Tags / Improve Title / Summarize palette items were registered in the backend under different names (ai_generate_tagsetc.) than the editor emits (ai_suggest_tagsetc.), so those nodes silently failed to dispatch at all - both naming sets are now accepted. - "Add Comment" automation now defaults to posting the upstream AI output. Matching the Set Description / Set Title / Apply Tags pattern, an Add Comment node with no explicit message now reads
{ai.output}so a "Generate Description → Add Comment" (or any AI-node → Add Comment) chain works without typing the placeholder by hand. When there's no upstream AI to inherit, the node fails fast as before rather than posting a blank comment. - AI Prompts dialog edits actually take effect on every automation surface now. Five of the rows the dialog let admins edit -
agent_loop.context.triggering_card,agent_loop.context.no_card,agent_loop.persona.header,agent_loop.system.recommendation, plus the four Quick-AI palette user prompts (Generate Description / Suggest Tags / Improve Title / Summarize) - weren't reaching the model at runtime. The automation agent loop was hand-building its own user message and never loading those rows; the Quick-AI prompts didn't even have rows seeded for the dialog to surface. The Python executor now assembles its system prompt from intro + persona header (when a persona is set) + recommendation rule (when the recommend_action tool is enabled), and its user message from triggering_card / no_card context + the variant or workflow task - every piece sourced from the AI Prompts collection so admin edits flow through, with inline fallbacks for a fresh install. Tuning a prompt in the dialog now does what the dialog implies it does. - AI-generated content drops the stray meta-commentary. Users reported a Generate Description run ending with "Note: this card is currently blocked by another card - check and resolve that dependency before proceeding." - an observation about card state that's not what a description is for. Root cause was twofold: (1) the shared anti-fluff system prompt (
agent_loop.system.introin the AI prompts table - which spells out "no preamble, no narration, no meta-commentary, deliverable only") was never loaded into the system slot of the Python automation agent loop; the executor was passing only the variant prompt directly. (2) The output rules block was inconsistent across surfaces (sparkle, hydrate, agent_loop) - each one had a subset, so a model running one path would behave differently than another. The shared rules are now wired into every automation AI call, normalised across all three surfaces (with the appropriate adaptations for tool-use vs one-shot), and the individual Generate / Suggest Tags / Improve Title / Summarize variant prompts also restate them inline so the rules survive an admin overriding the shared base. - Card-scoped manual triggers run when a Target Card node supplies the focus card. Clicking Run on a "Run on demand → Target Card → …" automation used to error out with "This automation requires a card_id (its trigger is card-scoped)" even though the Target Card node downstream picks a specific card by itself - the validator only looked at the trigger's scope, not at whether the graph already provided a card. The check now walks the graph from the trigger and skips the requirement when a properly-configured Target Card is reachable. Same
action_target_cardnode was also broken on the engine side: the editor stores the chosen card undertarget_card_id, but the Python port was reading the legacy field namecard_idonly - so even when the user picked a card, the node failed at runtime with "No card_id configured". Both names are accepted now.
Improved
- Agent personas own their capabilities; the Agent automation node becomes a dropdown. The Agent node used to have its own "Allow changes" toggle and per-category permission overrides, which competed with the persona's own defaults and meant the same persona could behave differently across automations depending on which checkboxes someone left on. That's gone - the persona is now the single source of truth. The persona edit dialog (Settings → Members & Teams → Agents) is split into two tabs - Details (name / avatar / description / personality) and Capabilities (four read categories and eight write categories using the same switch-with-description UI as the automation nodes). Both tabs reserve the same vertical space so flipping between them doesn't reflow the dialog, the Personality textarea is roomier so writing a real voice no longer feels cramped, and the avatar field is now a small emoji-picker popover with a curated set of agent-flavoured glyphs (or type your own). The Agent node itself strips down to just a persona dropdown + extra instructions - open it, pick a persona, optionally add per-automation context, done. If you need a one-off permission set that diverges from the persona, use the Workflow node instead (next bullet).
- Workflow automation node: persona-aware capability pre-fill with deviation warnings. When you pick a persona on a Workflow node, every capability switch (reads + changes) snaps to whatever the persona declared as its defaults. Switching personas resets the switches to the new persona's expectations - no stale overrides hiding under the hood. If you then toggle off a switch that the persona expects ("Triage Agent" needs
Update cardbut you uncheck it), the row shows a small amber warning beneath the description: "Triage Agent expects this - disabling may cause it to misbehave." Toggling on a switch the persona doesn't declare doesn't warn - widening capabilities is a deliberate choice, not a contradiction. - Workflow + Agent automation nodes: unified capability UI. The Workflow node's capability list collapsed from 18 checkboxes to 9 - Reads went from listing every internal tool ("Get card" / "List tags" / "List priorities" / "List comments" / "List dependencies" / etc.) to four user-facing categories: Read card details (default on), Read comments (default on), Read board context (default on), Read time logs (default off, billing-sensitive). The five Changes toggles (Add comment / Add checklist item / Update card / Create card / Suggest a one-click action) are unchanged in scope, but the capabilities panel is no longer collapsible - it's always visible like the Agent node, so the two configs read the same way. Every toggle (reads and changes, in both nodes) is now a small switch instead of a checkbox, with a one-line description under the label so what each one does is legible at a glance. The amber "watch out, this writes" tint on Change labels is gone - the description is enough to convey it. Persisted config shape is unchanged too - existing automations keep working without migration; the new categories just reflect whatever underlying tools the old node had enabled.
- Automation "Update card" tool is now the universal card-write capability. It already covered title, description, tags, priority, assignees, dates, list, and completion - it now also covers watchers and custom attributes (xattrs). The Workflow node's checkbox is just labelled "Update card" (the old "(assign / move / dates)" qualifier was misleading because the tool already did more than that, and now does even more). The simple Agent node gains a new "Set custom attributes" permission category alongside the existing tags / members / dates / move toggles so per-persona permissions stay granular if you want them. For the canonical triage use case - form creates a bug, agent reads title + description + reporter-entered fields, then fills missing xattrs and adds a triage comment - one Agent node with
add_comment+update_cardchecked is enough. Each xattr write produces its own audit entry so history queries don't have to special-case agent-loop changes.
v1.3.045
Improved
- Edit Profile dialog: AI tab and its per-user "Enable AI features" toggle are gone. The workspace-level Enable-AI switch in Settings → AI is the only authoritative kill-switch now - having a second per-user toggle layered on top was confusing (admins disabled AI workspace-wide and were surprised some users still saw it, or vice versa), and every check in the app already AND'ed both flags together. All AI feature gates now read the workspace flag (plus the relevant per-feature toggle where one exists, e.g. title suggestions or timelog suggestions). Backend endpoints (FastAPI + the route-AI hooks) no longer block on the per-user
settings_aifield either; users who had it disabled in the past will now see AI according to the workspace switch like everyone else. - User profile menu: reorganized into a quieter, label-free flat list. What used to be three labelled groups (AI / Integrations / Settings) is now a single set of separator-divided entries: Profile, Appearance, MCP, then (when you have access) Agents, Prompts, Settings, then Help. The standalone Settings entry that used to float at the bottom now lives next to Agents and Prompts, and the previously-separate AI header is gone - the items themselves are the only label you see. Visibility rules are unchanged: Agents/Prompts only show for admins with AI enabled, Settings only shows for users with view-settings permission, and that whole block hides if you have access to none of them.
- Settings → AI: clearer, more consistent layout. All three sections (Features, Routing, Models) now use the same bordered-card-with-divided-rows treatment, with matching row heights and small switches everywhere - so the page reads as one rhythmic list instead of three differently-spaced blocks. On desktop widths Routing and Models stack in a left column (2/3 width) while Features sits beside them on the right (1/3 width); below that breakpoint everything stacks as before, so narrow windows aren't squished. Section descriptions and per-row descriptions now live in info-icon tooltips next to each label instead of as inline subtitles, cutting vertical clutter without losing the explanatory copy. "Allowed capabilities" is renamed to "Features", and the "Install starter automations" opt-in lives inside that card as its last row instead of floating in a separate box. The model edit dialog's capability picker is now a switch list (cleaner activation pattern than the old chip toggles).
- Settings → AI: removed the per-model "Thinking mode" toggles. The Add/Edit model dialog no longer asks you to opt each capability into extended reasoning. Different models handle thinking differently, and the few that expose it (e.g. local runtimes like LM Studio) already let you toggle it from the host tool itself, so the per-capability switches in Truetask were noise. The dialog now stops at Capabilities - one less thing to configure.
Added
- AI capability routing - pick which model serves which capability. Settings → AI now has a dedicated "Routing" section that decouples which models you have from which model serves each capability. Pick the model that handles each of Generate / Suggest / Summarize / Tool use independently. Capabilities are no longer mutually exclusive across models - multiple models can declare the same one, and the route decides which actually runs. Each capability label has an info-icon tooltip explaining what it's used for and what kind of model is best suited (frontier vs. fast-and-cheap vs. tool-call-capable), so admins can pick routes without leaving the page. Existing workspaces are auto-migrated so today's behavior is preserved on upgrade.
Fixed
- Realtime updates no longer go silent after the browser tab has been backgrounded. Two root causes addressed: (1) Caddy was buffering the PocketBase realtime SSE stream because the proxy route didn't disable response buffering - events were piling up in Caddy and not reaching the browser until the connection cycled. The realtime endpoint now has a dedicated
/api/realtimehandler withflush_interval -1, so server-sent events flush to the client as soon as PB emits them. (2) Browsers silently kill SSE connections on backgrounded tabs, and the SDK often still reports "connected" after the tab wakes while no events are being delivered - this is the canonical "I clicked the Done checkbox, the card didn't move, refresh fixed it" bug. Avisibilitychangehandler now force-re-subscribes everything when the tab returns to visible after being idle for >5s (after a quick health check, so we don't tear down a working connection if the server itself is unreachable). - Board view tabs: the sliding active-tab indicator now repositions correctly when you toggle views on/off. Previously the indicator only re-measured when the active tab changed; toggling another view in or out of the visibility set reflowed the tab strip but left the indicator pointing at the old pixel coordinates, so it could end up overlapping the wrong tab or floating in empty space until the next interaction. The indicator now re-runs whenever the visible-views set changes too, after a frame so the DOM has settled.
- New users now get
Bas the default sidebar-toggle andQas the "show only my tasks" filter. Previously both actions claimedQ, so pressing Q on a board toggled the sidebar instead of filtering to your assigned tasks. The Welcome board's "Try keyboard shortcuts" card has been updated to match - the dead "+ Add card" bullet is replaced with the My-tasks filter shortcut. Existing users keep whatever combos they have today; only fresh signups pick up the new defaults. - List view no longer auto-tags and auto-describes new tasks behind your back. Adding a task in List view was hitting AI to generate a description and pick tags on every create, regardless of whether the board had a Hydrate automation installed - Kanban view didn't. List view now matches Kanban: card creation creates the card, nothing more. Auto-fill is opt-in per board via the Hydrate new cards automation.
- "Hydrate new cards" is now available as an automation template. Install it from the Automation Library → Templates on any board to get the same one-call description + tag fill that the workspace-level "Install starter AI automations on new boards" setting auto-installs. Lets you turn off the workspace auto-install and still add hydration to specific boards on demand. Requires AI enabled and an Enterprise license.
- Onboarding wizard now opens directly on the Welcome board instead of My Tasks. New users are routed straight to the seeded board the moment the wizard fires, so the "Drag me to Done!" hero card and the To Do / In Progress / Done lists are visible behind the wizard from the very first step - the tutorial instructions are now actually followable.
- Onboarding wizard can no longer be skipped or dismissed. The Skip link, the X close button, the Escape key, and clicking outside the dialog are all disabled - the only way out is to walk through the three short steps. Since the wizard is what lands the user on the Welcome board, allowing dismissal would strand brand-new users on My Tasks with no obvious next step.
- Welcome board cards no longer say "double-click" to open. Cards open on a single click; the seeded tutorial copy was telling new users to do something that doesn't work. Only affects new signups (existing welcome boards keep their original copy).
v1.3.043
Fixed
- Custom attributes are writable and definable again through the Claude / MCP integration. Setting or updating attribute values (text, URL, select, multi-select, checkbox, date) and defining new select / multi-select fields through MCP tools was silently producing empty requests and erroring out; only plain numbers were getting through. All paths work now.
v1.3.042
Fixed
- Custom attributes are writable and definable again through the Claude / MCP integration. Setting or updating attribute values (text, URL, select, multi-select, checkbox, date) and defining new select / multi-select fields through MCP tools was silently producing empty requests and erroring out; only plain numbers were getting through. All paths work now.
- License activation no longer fails with a server error on fresh installs. The bootstrap hook was treating an empty collection as a failure instead of as the signal to seed defaults, so the initial
settingsrecord was never created and any downstream call that reads it (license activate, license details, MCP gate) returned 500/404. Activation works end-to-end now. - macOS desktop app no longer enters crash-restart loops. PocketBase's JS-hooks hot-reload was being tripped by routine macOS file-system events on the app bundle (Gatekeeper re-verification, Spotlight, Time Machine, anti-virus scans), causing PocketBase to exit and the watchdog to restart it every few minutes. Hot-reload is a dev-only convenience; disabled now in all production builds (macOS, Windows, Docker dist). Local Docker dev still has it on.
- List view: URL custom attributes are now editable inline. Previously they rendered as read-only cells. Click to edit, type a URL, blur or press Enter to save. Schemeless input like
example.comis auto-normalized tohttps://example.com/; unparseable input still saves the raw text but surfaces a warning. - List view: adding a new task no longer pops the sidebar. The new row stays inline and gets focused so you can keep adding without breaking your typing flow. Click the row if you want the detail view.
- List view: opening the side panel from a row no longer nudges the table 1-2px left. The auto-scroll that brings the focused row into view was using
scrollIntoView, whose default horizontal-alignment can driftscrollLeftby a subpixel in scroll containers wider than their viewport. Replaced with an explicit vertical-only scroll. - List view: with no sort active, the table is now ordered newest-first so a freshly added task always lands at the top instead of somewhere in the middle. Previously the unsorted order was kanban-shaped (by list, then by position), which made newly added tasks appear in unpredictable spots depending on which list they were assigned to.
- List view: typing into the new-task draft while sorted by title no longer accidentally commits the half-typed text as a real task. Sorting moves the draft row mid-keystroke, which in some browsers drops focus on the input as a DOM side-effect; the blur handler then treated that as "user clicked away" and committed. Now disambiguates a "real" blur from a "focus dropped" blur and refocuses the input in the latter case. Escape still dismisses.
- Kanban: inline AI title suggestions popover now flips below the input when there's no room above (visible when you're adding a card near the top of the viewport). Replaced the custom Portal positioning with bits-ui Popover, which gets collision-detection for free.
- View Preferences: the default view's checkbox is now locked as checked + disabled in Visible views, so you can't accidentally end up with a default you can't see. Applies to both the "Your view" and "Board default" tabs (locked against the user's effective default and the admin's choice respectively). The last remaining visible-view checkbox is also disabled so you can't reduce the set to zero. Picking a currently-hidden view as the default is still blocked with a toast.
- Forms suggestion pill: the dismiss × now sits inside the dashed outline and is always visible at ~40% opacity (instead of only appearing on hover, outside the pill).
- Forms suggestion pill is now dismissed globally instead of per-board. Closing it once stops the nudge everywhere. Previously each new board re-prompted, which felt naggy.
Improved
- List view: "Add task" now spawns an inline draft row instead of a separate input pinned to the header. The new row sits inside the table with the same column layout as real rows - the title input is in the title column, not floating above it. Press Enter to save, Esc to cancel; Enter keeps you in rapid-entry mode so you can add several in a row without re-clicking the button. The draft slides live as you type if the table is sorted by title (so you can see where the task will land alphabetically); for any other sort or no sort, it stays pinned at the top so it doesn't bounce around based on fields you haven't filled in yet. New tasks land in the lowest-index list that isn't a Done list, grouping correctly when grouping is active. The "+ Add task" button itself is a secondary-styled CTA that stays visible during entry - clicking it while a draft is open just re-focuses the input.
v1.3.041
Added
- "Try Forms" nudge on the view bar. Boards without Forms now show a subtle dashed "+ Forms" affordance at the end of the view-switcher tabs. Click to enable Forms on the board (admins write to the board default; non-admins get a per-user override) and switch straight to the new view. A small × dismisses the nudge per-board. Viewers don't see it.
- Milestones in the Calendar view. Milestones now appear as colored dashed pills inside the day cells where they fall (month + week views) and as a list block at the top of the day view. Click a milestone to edit, right-click for edit / delete, right-click an empty day cell for "Add milestone here" - same flow the Timeline view already had.
- Milestone triggers for automations. Two new triggers in the automation builder: Milestone Approaching (fires N days before a milestone's date - useful for reminders, pre-release checklists) and Milestone Reached (fires on the date - useful for retros, archiving, post-launch notifications). Available in the Triggers → Time group. New
{milestone.name},{milestone.date}, and{milestone.id}placeholders work in Send Email, HTTP Request, and Create Card bodies. - Automation palette is sorted into subgroups. The Triggers, Actions, Logic, and AI sections now show category labels (Card events, Card lifecycle, Card content, Tags, People, Time, Communication, Integrations, Flow control, Agents, Quick AI). The flat alphabetical-soup is gone.
- Tool-using AI automations now work with OpenAI, Ollama, and Google Gemini. The
agent_loopautomation node - the AI step that reads and acts on board data through Truetask tools - used to be Anthropic-only. Any tool-capable OpenAI model (gpt-3.5-turbo, gpt-4o, gpt-5, etc.), Ollama model with a tools-aware tag (gemma4, llama3.1+, qwen2.5+, mistral-nemo), or Gemini 2.5+ model now drives the same loop. LM Studio and other OpenAI-compatible providers also work. - Inline AI title suggestions in the Kanban add-card flow. As you type a new task title, three alternative phrasings appear in a popover above the input. Arrow keys to navigate, Enter or click to accept, refresh button to re-roll. Works both at the bottom of a list and when adding between cards.
- Board Context dialog rebuilt. Resizable textareas, larger workspace, five starter templates (Marketing, Product/Engineering, Operations, Design, Blank), a "Suggest from board" button that drafts a context from the board name and recent task titles, per-section help with examples, and a live preview showing the exact text the AI receives.
Fixed
- Timeline no longer adds empty scrollable space past the end date. When today fell after the visible range (most common in Data range mode on boards with only past work), the today marker was rendered outside the canvas and extended the scrollable area into dead space. The marker now only renders when today is inside the visible range; the canvas ends flush with the range end.
- End-of-sequence tokens (
,<|im_end|>,<|eot_id|>, etc.) no longer leak into AI output. Small or aggressively-quantized local models occasionally bleed their stop tokens into the final response. Now stripped across all AI surfaces (card actions, Pulse, automations).
Improved
- Forms tab is opt-in on new boards. New boards open with Kanban / List / Calendar / Timeline only - the Forms tab is hidden by default. Owners turn it on per board from View Preferences when they want public intake. Existing boards keep their current view set.
- AI errors are now actionable. Instead of a generic "Something went wrong" toast, AI failures surface what to do: "OpenAI account is out of quota - check your billing", "Invalid API key for Anthropic - update it in Settings → AI → Models", "Couldn't reach Ollama - check the API URL", etc. Applies across card AI actions, the Overseer Pulse rail, and
agent_loopautomations. - AI failures on cards now toast instead of failing silently. Suggest title, summarize comments, auto-tag, and generate checklists previously logged the error to the console only - they now show the same actionable message in the toast.
- OpenAI reasoning-class models (gpt-5, o1, o3, o4 family) work as drop-in choices. Previously they 400-errored because Truetask was sending standard chat-completion parameters those models reject. Now usable across Pulse summaries, card AI actions, and
agent_loopautomations. - Per-model "thinking" toggles are now actually enforced. Turning thinking off for a capability (Settings → AI → Models) used to only nudge the model via prompt-engineering - the model would still burn thinking tokens. Truetask now passes the provider-level disable parameter (Gemini
thinkingBudget=0, Ollamathink:false, OpenAI reasoningreasoning_effort:low) so the setting actually saves tokens and latency. - Overseer Pulse waits long enough for slow AI models to finish. Summaries no longer 502 mid-generation when the model is slow - applies to cloud reasoning models (gpt-5, o-series) on heavy payloads as well as local Ollama models on consumer hardware.
v1.3.040
Added
- Forms. Public intake forms on any board. Build the form (title, description, drag-to-reorder fields including custom attributes), pick a target list, share the link. Submissions land as real cards and trigger your automations. Public or password-protected. Anonymous file uploads up to 25MB. Honeypot + per-IP rate limit for bots. Available as a new board view next to Kanban / List / Calendar / Timeline.
- Tasks submitted via a form are tagged with the originating form. Filter by it on any board with the new "Source form" option in the filter menu - match any form, no form, or a specific one. Tasks survive form deletion.
- Forms manager: archive / restore to pause intake without deleting, duplicate to clone a form, and an Insights tab showing views, submissions, conversion %, and recent submitted tasks.
- Set Dates automation action replaces Set Due Date. Set start, end, or both - by offset, fixed date, or clear. Existing Set Due Date nodes keep working.
Improved
- Card frame opens faster on cards without checklists.
- Imports (Trello, TrueTask, Linear, Asana, GitHub, Jira, Todoist, Notion) no longer trigger automations on every imported card.
- Save as Template, Clone Board: include context / automations / views are on by default, and the new board opens in the source's default view.
- Build from Template: each template card shows its default view icon.
Fixed
- Board export and TrueTask import now round-trip checklists. Re-export / re-import any board that had blank checklist counts to recover the data.
- Card mentions are consistent across comments, descriptions, and the activity feed. Mentions to inaccessible cards show a clear toast; mentions on My Tasks no longer pop a floating window over the panel.
- Archiving or navigating to an archived board redirects to My Tasks.
- Building a board from a template that included views now exposes those views in the selector.
- Form submissions fall back to the first list on the board if the original target list was deleted (or surface a clear error if the board has none).
- Links inside your own message bubbles are readable again (were rendering near-invisible on dark backgrounds).
v1.3.036
Fixed
- Re-cut of v1.3.035 to fix release-pipeline issue. No user-facing changes.
v1.3.035
Improved
- License screen now communicates the perpetual model correctly (grillme §3, voice.md): renamed "Upgrade Expires" → "Updates included until" since the date is the update window, not a tier upgrade. Date now turns amber with "ends in N days" inside 30 days and red with "ended N days ago" once past. Added a perpetual reassurance line ("Your software keeps running at this version forever. Renew to receive new versions and security updates.") below the details card so admins don't misread the amber/red expiry as the software bricking. Added a "Renew Updates" CTA (visible only when the update window is ≤30 days or past) that opens a dialog showing the prefilled email body in a textarea with a Copy button, plus an "Open in mail app" mailto fallback - manual renewal path until the self-serve flow ships in Q3/Q4 2026 (grillme §6.4). The dialog approach (instead of a bare
mailto:) sidesteps Gmail web / some Chrome → Apple Mail handlers that silently strip%0D%0Afrom mailto bodies, collapsing the message into one line. Dates in the email are sliced toYYYY-MM-DDso timestamps don't clutter. Renamed "Remove License" → "Detach License" with aLinkBreakicon since the action is non-destructive (license unbinds, grace period starts). The "License active" badge stays green regardless of expiry - only updates lapse, the license itself never bricks. New translation keys added across en/es/fr/de/pt:updates_until,updates_ended_relative,updates_ending_relative,perpetual_reassurance,renewal_cost_note,renew_button,renew_description,renew_modal_title,renew_modal_intro,renew_modal_recipient,renew_modal_subject,renew_modal_body,renew_modal_copy,renew_modal_copied,renew_modal_open_mail,detach_title,detach_button,detach_confirm.
Fixed
- Settings opens at first accessible section per role: LEADs were dropped on the Health page when opening Settings, even though Health is OWNER/ADMIN-only.
open_settings()now resolves an empty section argument by picking the first item fromget_settings_groups(role), so LEADs land onmembersinstead. - Health → MCP server status: PB's MCP probe was hitting
http://localhost:8811from inside the PB container (which is PB itself), so the check always reported "unreachable".TRUETASK_MCP_URL=http://truetask-mcp:8811now set in bothdocker-compose.ymlanddocker-compose.dist.ymlso PB resolves the MCP service via the docker network. - Health page version display: was reading from
svelte/static/VERSIONanddb/pb_public/VERSION(both stuck at the old1.2.002format), which only got updated bybuild-server.sh:149at deploy time and drifted in dev. Roottruetask-source/VERSIONis now the single source of truth: a newsyncRootVersionVite plugin (svelte/vite.config.js) mirrors it intosvelte/static/VERSIONon every dev start and build, so the Health/Updates pages display the version the user actually has. Stale dev copies brought in line. - License Activate button no longer flickers on click: the button used to disable itself + swap both icon AND text (
Activate→Validating…) for the brief moment validation runs, which on a fast happy path read as a layout glitch. Now the button text stays constant and only the leading icon swapsKey→CircleNotch(bothsize={14}, no width change). Added a re-entrancy guard inhandle_activateso a fast double-click can't race itself through the POST. - Webhook event labels now translated: the Add/Edit Webhook dialog showed raw keys (
settings.webhooks.event.card.created) for all 21 event toggles because the matching translation entries were never added. Addedsettings.webhooks.event.*to all 5 locales (en/es/fr/de/pt) covering every event listed inroute_webhooks.pb.js:VALID_EVENTS. - Settings → AI starter description matches the actual starter: the "Install starter AI automations on new boards" description still referenced the legacy "Auto-fill description" + "Auto-tag new cards" pair, which
util_ai_starters.jsmerged into a singleai_hydrate(Smart Hydrate) automation called "Hydrate new cards". Updatedsettings.ai.policy.install_starters_descin all 5 locales (en/es/fr/de/pt) to describe the current behavior, and translated theinstall_starterslabel too - the non-EN locales had been left as untranslated English. Inline fallback copy insettings-integrations-ai.svelteupdated to match. - Board sharing dialog now describes what each role can do when you pick one, and the documentation link sits inline with the description.
- Leaving a board is blocked when you're the only admin - a message asks you to promote another member to Admin first instead of orphaning the board.
- Board sharing dialog: Add Member is now the prominent action above the list, and the search field stays pinned to the top of the member list as you scroll.
- Timesheets week calendar: day headers no longer shift height when a scrollbar appears underneath.
- Board preferences panel: removed the empty AI tab and now only shows the Kanban tab while you're on the Kanban view.
- New "My tasks" filter on every board, available to every user, triggered by pressing Q (configurable). Sidebar toggle moved from Q to B.
- Saved-filter row menu's "Update with current filters" renamed to "Save changes" with a clearer save icon.
- Audit Log now attributes activity from automations and AI agents by name instead of showing "Unknown".
- Default Truetask logo on the Identity settings preview now matches the active theme (black on light mode, white on dark).
- Board export / import now round-trips custom attributes:
route_export.pb.jswas emitting board, lists, cards, tags, members, and (optionally) automations - but noxattr_fielddefinitions and no per-cardxattr_values. Custom-attribute data was silently dropped on export and unrecoverable on the receiving end. The export now collects both (one query per collection, ID-OR-chain on values to avoid walking each card) and includes them underxattr_fields+xattr_values. The TrueTask import path (route_import.pb.js) now creates the field definitions before cards, builds anold_field_id → new_field_idmap, and after each card save materializes the correspondingxattr_valuesrows pointing at the new field + new card IDs. Export schema bumped toversion: 2; v1 exports without xattr arrays still import cleanly (treated as empty). Audit log + import stats now includexattr_fieldsandxattr_valuescounts. - List view CSV / Excel export now matches the on-screen view (WYSIWYG): the export used to dump every card with a fixed column set (title/list/priority/members/tags/start/end/completed) regardless of what the user had configured in the table - hidden columns came back, filters and search were ignored, sort and grouping were dropped. Now it respects all of them. Mechanism:
view-list.sveltepublishes a lazystate_site.list_view_export_fnthat snapshots the table's resolved visible columns (in their effective order, excluding the chromeselect/completedIDs) and the filtered + sorted leaf rows from TanStack's row models.list-view-export.sveltecalls it on click and projects each row through per-column-id formatters (title,priority,members,progress,list,start,end,modified,tags,blocked_by,blocks,completed, plusxattr_). Falls back to the old behavior if the table isn't mounted (defensive - shouldn't happen in practice). - List view toolbar consolidated into the view selector popover: the Group, Columns, and Add field buttons (plus the toolbar
ColumnsPlusRightfrom the previous turn) are gone from the toolbar. The view selector - which already looks like a select and showed saved views - now also hosts a "Configure view" section with three navigable rows: Group (with active-count summary), Columns (with hidden-count summary), and Add field. Tapping a row swaps the popover content to the corresponding panel with a back-arrow header; the popover trigger keeps its select-like appearance so users still see which view is active. Each panel was extracted into a presentational sibling (list-view-group-panel.svelte,list-view-columns-panel.svelte,list-view-add-field-panel.svelte) shared between the standalone wrappers and the unified selector - no logic duplication. Standalone wrappers (list-view-group.svelte,list-view-columns-dropdown.svelte,list-view-add-field.svelte) stay around because the timeline view still uses Group as a free-standing dropdown and the in-table+cell still uses Add field. Added 4 translation keys per locale:board_view.configure,board_view.back,board_view.n_grouped_by,board_view.n_hidden.
Removed
- Settings → Updates section: out-of-date screen with a single "run the update script" instruction. Users now have multiple install/update paths (CLI, Tauri menubar updater, manual), so the in-app instruction is misleading more often than not. Removed the nav item from
state.svelte.js, the conditional branch fromsettings_frame.svelte, and deleted the orphansettings-app-updates.svelteview. Thesettings.updates.*translation keys are left in place across all 5 locales - pruning them is 45 edits with no user-visible benefit; safe to clean later if needed.
Improved
scripts/README.mdrestructured: top of the doc is now purely a quick-reference for running thetruetaskCLI (install + commands + env overrides). Everything else - repos, mental model, credentials, deploy stages, recovery, dist-zip contents, layout, gotchas catalogue - moved below a divider as a Reference section you only consult when you need to.
v1.3.034
Improved
scripts/reorganization: root now holds only the three mission-critical entry points (deploy.sh,status.sh,truetask.sh) plusREADME.md. Everything else has moved into purpose-named subfolders:
-
scripts/utils/- dev tooling (minify.mjs,test_migration.sh, thepackage.json+pnpm-lock.yaml+node_modulesbacking them)-
scripts/scratch/- non-mission-critical one-offs (seed-timesheets.py)-
scripts/deploy/- release-pipeline internals (already there)-
scripts/management/,scripts/setup/- end-user runtime scripts shipped in the dist zip (already there)- CLI suffix: renamed
scripts/truetask→scripts/truetask.shfor consistency with the other shell scripts; symlink target updated.ln -s scripts/truetask.sh /usr/local/bin/truetaskstill gives the sametruetaskuser command. - References updated:
scripts/deploy/build-server.shnow invokesscripts/utils/minify.mjs;scripts/README.mdreflects the new layout;db/MIGRATIONS.mdtest-migration path updated.
Removed
scripts/flatten_migrations.sh- refusal stub; flattening migrations is incompatible with deployed clients (seedb/MIGRATIONS.mdrule 3, which now states the rule directly without referencing the dead script)scripts/obfuscate.mjs- orphan;build-server.shno longer obfuscatespb_hooks(just copies them), so the script and itsjavascript-obfuscatordependency are gone
v1.3.033
Improved
- Release tooling: new
truetaskCLI wrapper (scripts/truetask) - single entry point fordev,dmg,upload,deploy,status. Pure delegation to existing scripts; install withln -s scripts/truetask /usr/local/bin/truetask - Pipeline status: new
scripts/status.sh(also available astruetask status) prints local repo state (clean / dirty / ahead-behind for bothtruetask-sourceandtruetask-installer) and remote state (latest portal release with per-platform artifact presence; latest Gitea release tag) in one shot - Release docs: rewrote
scripts/README.mdto cover the full multi-repo flow (commands, credentials, whatdeploy.shdoes, recovery paths, things-that-bit-us list) instead of just deploy-script internals
v1.3.032
Improved
- Updater post-install UX: helper now refreshes LaunchServices (
lsregister -f -R) before relaunch so the new bundle's menubar icon registers immediately (previously the swapped-in app could run headless until the next manual launch). New app detects a fresh install via ajust-installedmarker file (or bundle mtime fallback) and auto-opens Settings → Updates so the user sees confirmation of the new version - Settings → Network → Reachable at: URL is now a proper clickable link (opens in default browser) - removed the separate launch icon that didn't size-match the copy icon
v1.3.031
New
- Automation logic nodes: four new nodes in the automation builder -
Parse JSONandParse XMLextract fields from HTTP/webhook payload bodies,For Eachiterates over arrays,Target Cardswitches the active card context mid-flow
Fixed
- Login screen default logo: now picks the correct light/dark variant based on the active theme
- Trial process on new installs: trial flow runs cleanly against brand-new installations
v1.3.017
Fixed
- MCP Server workign
v1.3.016
Improved
- PocketBase migrations flattened:
scripts/flatten_migrations.shconsolidated 35+ accumulated migration files into a singlecollections_snapshot.jsrepresenting the current schema state. Fresh installs now skip the entire replay history - no more collisions from staleupdated_*.jsmigrations colliding with regenerated snapshots (this had been causing theavatarduplicate,deleted_byrelation-constraint, andValue must be uniquesuperuser errors on brand-new installs). Existing installs unaffected - PB tracks applied migrations in_migrations - Build warnings cleanup - final
pnpm buildnow runs with zero warnings:
-
btn-notifications.sveltebackdrop: replaced barewith a(removesa11y_click_events_have_key_eventswarning and the accompanyingsvelte-ignorecomment; newaria.close_notificationslocale key across all 5 languages)-
chart-container.svelte:setContext('chart-config', config)only captured the initial prop value (Svelte 5state_referenced_locally). Now stores a{ get current() { return config } }accessor; the single consumer (chart-tooltip.svelte) readsconfig_accessor.current[p.key], so config changes reach the tooltip live-
view-timeline.svelte: swapped threeduration-[120ms]classes (Tailwind 3 can't disambiguate transition-duration vs animation-duration) for explicit[transition-duration:120ms]arbitrary properties-
card-view.svelte: promoted the dynamicimport('fractional-index')call to a static import - the module was already statically pulled in by 8 other files, so lazy-loading here saved nothing and triggered Rollup's mixed-import warning-
vite.config.js: raisedchunkSizeWarningLimitfrom 1000 → 1500 kB with an explanatory comment. Matches the observed top chunk (~900 kB minified - translations bundle + shadcn-svelte/bits-ui surface + icon set) without hiding future regressions- Auto-memory: saved a
feedback_schema_flatten.mdnote so future sessions flag accumulatedupdated_*.jsmigrations as a liability and reach forscripts/flatten_migrations.shbefore trying to edit individual files into idempotency
v1.3.015
Improved
- Deploy script (
scripts/deploy.sh): newPORTAL_ONLY=1flag re-runs only the client-portal upload step. Skips tests, frontend build, dist-repo commit/push, and Gitea release publish - useful when a prior deploy succeeded end-to-end on the Gitea side but the portal auth/upload printed a warning and was never retried (previously recoverable only by bumping the CHANGELOG version). Also gates theGITEA_TOKENpre-flight prompt whenPORTAL_ONLY=1so the rerun doesn't ask for a credential it won't use
v1.3.014
New
- Timesheets: AI note suggestions on timer stop and Add Entry - new
timelog_suggestAI action (inroute_ai.pb.js) reads the card's title, description, open checklist items, and last 10 comments to produce 2-3 one-sentence suggestion chips. Click to fill the note field. Fails silent (AI off, offline, rate-limited → the dialog behaves like before). Per-usersettings_ai_timelogspreference, on by default; toggle in tweaks and inline "Turn off" link in the dialog - Timesheets: shared timer-stop prompt dialog - replaces the silent
stop_timer()call everywhere (global timer dropdown, card toolbar, task Time tab). Shows task title + live elapsed, note textarea with Cmd/Ctrl+Enter to submit, primary button label toggles between "Save note & stop" and "Stop without note" based on content. "Keep running" sits at the left edge, "Stop" at the right - Timesheets: unified table view - single
timesheets-table.sveltereplaces the old Users/Boards mode pair. Group-by selector (User / Board / Task), Excel-style grid with border-separated columns, right-aligned numeric cells, row expand for task/user breakdown, full-cell click targets, per-cell popover listing entries with full note text + "Open task" (plus right-click context menu). Export button moved from the global toolbar into the table wrapper's right edge - Timesheets: collapsible table search - icon-only trigger that expands to a full input; filters both primary rows and their secondary breakdowns by label. Same pattern as the board quick-search
- Timesheets chart: Bars / Stacked Area toggle - segmented tab set with an icon per group-by option; responsive tabs+dropdown at narrow widths; x-axis auto-strides labels to ~10 visible regardless of range length
- Timesheets calendar: overlap tracks - overlapping entries split the day column side-by-side instead of z-stacking. Auto-expanding visible hours with a primary-colored dot on the gear when data falls outside the preferred window. "This week" button gets a
CalendarDotglyph. Right-click entry → "Open task in new tab". User picker converted to shadcn-svelte combobox with search (Popover + Command). Block popover replaces the old side-panel drawer - Approvals tracking card (
5dmmpioi48mbuqqin the backlog board): captures scope and rediscovery pointers for when we bring the Approvals view back
Improved
- Timesheets calendar blocks: note indicator icon when an entry carries a note
- Timesheets table cell indicator: inverted - the dot now flags missing notes rather than their presence, so writing notes reads as the silent norm
- AI suggestion panels: reserve three skeleton rows at fixed
min-h-[44px] items-centerthe moment the dialog opens, so chip render is a pure swap (no layout shift) - Card delete attribution (
hook_cards.pb.js):deleted_byis only set when the actor resolves to ausersrecord. Superuser / cron / MCP-initiated deletes skip attribution silently instead of crashing the soft-delete with a relation-constraint 500 - Deploy script (
scripts/deploy.sh): picks a Python ≥3.10 interpreter from PATH (clear install hints if none found), manages a dedicatedapi/.venv, and only reinstalls requirements when the hash ofrequirements.txtchanges - Vite build: pre-transform plugin unwraps Tailwind-reserved
@layer base|components|utilities { … }blocks from third-party (node_modules) CSS so LayerChart 2.x scoped styles no longer crash PostCSS
Fixed
- Timesheets chart: stacked area rendering - areas were drawn as floating disconnected bands because
chart_dataomitted series keys for days with zero value, causing d3.stack to emit[NaN, NaN]for those points and the area path'sdefinedaccessor to go false. Now every row defines all series keys with explicit zeros; stacked bands share edges cleanly - Timesheets chart: near-invisible render with many series - LayerChart's
getAreaPropssets opacity to 0.1 when >1 series is visible and none are hovered; with ≥10 task series the whole chart faded to a single ghost. Overridden viaprops.area.opacity: 1andline.opacity: 1 - AI timelog suggestions firing in a loop - the fetch effect transitively tracked
elapsed_seconds(updated every second by the clock interval), firing an AI request per tick until the provider 502'd. Wrapped the body inuntrack()so onlyopenis reactive - Timer stop dialog task-title overflow - long titles pushed past the dialog's
max-w-mdbecause Dialog.Content is a CSS grid and children default tomin-width: auto. Addedmin-w-0to direct children sotruncatetakes effect - Timesheets table popover reactive shifts - vertical scroll of the table now closes any open cell popover (horizontal scroll leaves it attached since the anchor stays in the same row). Sticky first/last columns use opaque
bg-mutedon hover so content from underneath doesn't bleed through. Open cell getsz-20+ ring so neighbour hover tints don't paint over the selection - PocketBase snapshot duplicate
avatarfield - two update migrations (1776383511_updated_users.js,1776384993_updated_users.js) re-added theavatarfield that was already present in the regenerated initial snapshot, breaking fresh installs with "Duplicated field name avatar". Merged their end-state (maxSize: 10 MB,thumbs: ["100x100"]) into the snapshot and deleted the redundant migrations. Existing installs are unaffected - PB tracks applied migrations in_migrations
Removed
- Timesheets Notes view - its jobs fold into the table's cell popovers and the calendar block note indicator.
notes_entriesderivation,view_mode === 'notes'branches,timesheets-notes-feed.svelte, and alltimesheets.notes.*/timesheets.view.noteslocale keys deleted - Timesheets Approvals view tab - hidden behind an
{#if false && ts.is_manager}guard. Schema (timesheet_approvals), state (fetch_approvals,is_entry_locked,set_approval_status,weekly_approvals,pending_approval_count), and thetimesheets-approvals.sveltecomponent are preserved so re-enablement is a single-line change. Hidden because the feature shipped half-looped (manager-only; no user-facing status, submit flow, change-request round-trip, or lock affordances). Backlog card tracks the scope timesheets-pivot-table.svelteandtimesheets-boards-table.svelte- superseded by the unified table
v1.3.013
Improved
- Timesheets: removed the SMTP setup step. Admins who haven't configured SMTP now get a toast reminder with a "Set up now" action at the end of onboarding. Non-admins and admins with SMTP already set up never see the reminder.
onboarding.smtp.remindertranslation added to en, pt, de, fr, and es locales
v1.3.012
New
- Timeline single-date scheduling: tasks with only a start date or only a due date can now be extended into a full date range by dragging a resize handle. The original date becomes one endpoint, the drop position becomes the other - Truetask orders them so the earlier becomes start and the later becomes due.
Improved
- Onboarding wizard: removed the SMTP setup step. Admins who haven't configured SMTP now get a toast reminder with a "Set up now" action at the end of onboarding. Non-admins and admins with SMTP already set up never see the reminder.
onboarding.smtp.remindertranslation added to en, pt, de, fr, and es locales
Fixed
- License warning dialog and onboarding wizard no longer open simultaneously on first sign-in - the license dialog is skipped when the onboarding wizard will show, and reappears the following session (the persistent header banner still communicates license state)
Removed
step-smtp.svelteonboarding component (no longer used)
v1.3.011
Fixed
DEMO_MODE,DEMO_EMAIL, andDEMO_PASSWORDenv vars missing fromdocker-compose.dist.yml- demo mode was not passed to PocketBase container in deployed instances
v1.3.010
New
- AI sparkle icon (
icon-ai-sparkle.svelte): custom 3-star SVG icon replaces PhosphorRobotfor all AI actions - usescurrentColorfor theme-aware rendering, with animated twinkle effect during AI requests - Delete button on AI-generated comment summaries - appears on hover for the user who generated them
Improved
- AI icon replaced across all card frame actions: Generate Title, Auto-tag, Generate Description, Generate Checklists, and Generate Summary
- AI loading state now uses animated sparkle icon instead of generic spinner - visually communicates "AI is working" rather than "something is loading"
- AI sparkle animation: staggered pop/rotate effect across 3 stars for a professional, distinctive look
v1.3.009
Improved
- Card context menu: members submenu now uses
CheckboxItemwithcloseOnSelect={false}- stays open for multi-select, matching tags submenu behavior - Card detail cover image overlay: semi-transparent wash (
bg-black/40for dark images,bg-white/30for light) improves title readability over cover photos - Color picker popover z-index raised to
z-[250]- renders above tag popovers, dialogs, and all other nested UI - Main content area background changed to
bg-muted/30
Fixed
- Color picker rendering behind tag popover in card detail view - tag popover is
z-[200], color picker nowz-[250] - Backend graph sanitization function was defined at file scope but PocketBase route handlers have isolated contexts - moved to
util_sanitize_graph.jsloaded viarequire()pattern - Automation import returning 400 due to sanitize function crash - now fails open (logs error, preserves original graph)
v1.3.008 (skipped - merged into v1.3.009)
v1.3.006
Improved
- Automation clone sanitization: cloning an automation to another board now scans the graph against the target board's lists, tags, members, priorities, and xattr fields - auto-fixes case mismatches and strips unresolved references
- Backend graph sanitization: server-side
sanitize_graph_for_board()validates all automation config references on both create and import endpoints - two-layer defense against stale references - Select dropdown base z-index raised from
z-50toz-[100]globally, fixing dropdowns rendering behind dialogs across the entire application
Fixed
- Automation clone carrying stale list/tag/member references from the source board to the target board - references that don't exist on the target are now stripped
- Automation import scanner flags
{triggering_user}as unresolved reference - now whitelisted as a special value - Automation import review dialog: member mapping dropdown renders behind the dialog - Select z-index set to
z-[250] - Automation clone dialog: board picker popover renders behind the dialog - Popover z-index set to
z-[250] - List conversion dialog: Select dropdown renders behind the AlertDialog - z-index raised to
z-[250]
v1.3.005 (skipped - merged into v1.3.006)
v1.3.004
New
- Automation actor context: automation engine now captures the user who triggered the event, enabling "assign to triggering user" and
{actor.name}comment placeholders - "Triggering user" option in automation member select - assigns/unassigns the person who performed the action (moved card, completed task, etc.)
{actor.name}placeholder for automation comment actions alongside existing{card.title}and{card.id}- Actor capture hook (
hook_actor_capture.pb.js) stores auth context via$app.store()for cross-hook access - Available placeholders hint displayed below comment message textarea in automation builder
Improved
- Completed cards no longer show overdue (red) styling on start/due dates in list view - reduces visual noise for finished work
- Kanban cards only display member avatars for users who are current board members - removed members no longer show stale avatars
- Markdown editor unescapes literal
\nsequences on load - descriptions with escaped newlines from API/MCP now display correctly in edit mode - Vite build chunk size warning threshold raised to 1MB to suppress noise for expected large bundles
Fixed
- Auto-assigned list index query using wrong SDK method (
get_list→get_full_list) causing 500 errors on list creation without explicit index
v1.3.003
New
- Board role locking: site ADMIN/OWNER members show a locked "Admin" badge with shield icon and tooltip in the share dialog - role dropdown is hidden since site admins always have board admin access
- Last admin guard: prevents removing or demoting the last admin on a board (blocks in role change, member removal, and leave board flows)
- Shield icon indicator next to admin usernames in the "Add member" picker for at-a-glance identification
Improved
- API auto-assigns list
index(max + 1) when not provided, preventing duplicate index collisions - API auto-assigns card
position(max + 1000) when not provided, ensuring consistent ordering - Frontend sort uses
idas tiebreaker when list indices or card positions collide, ensuring deterministic order - Initialize script enables PocketBase batch requests by default (required for list reordering)
- Non-admin list color indicator now matches admin ColorPicker appearance (same size and border radius)
Fixed
- List reordering not persisting on demo instance - PocketBase batch requests were disabled by default
- Lists with duplicate indices rendering in non-deterministic order after refresh
- Command palette
$effectcausedeffect_update_depth_exceedederror - writingonboarding_signalinside a reactive effect created an infinite loop. Fixed withuntrack()wrapper Tooltip.Providercontext error in board share dialog - tooltip rendered in portal outside layout's provider scope- Deploy script auto-removes stale
.git/index.lockin dist repo before commit step
v1.3.002 (skipped - merged into v1.3.003)
v1.3.001
New
- User onboarding wizard: role-aware first-login dialog (Welcome → Profile → SMTP for admins → Explore) with step indicator, profile editing, and skip option
- Enhanced welcome board: new users get "Welcome to TrueTask" board with 5 interactive cards, 2 tags, and a checklist teaching core features by doing
- Getting-started checklist: collapsible sidebar widget with auto-detection of completed items (profile, board creation, card creation, quick search, SMTP setup for admins)
- Integration test suite: 119 frontend tests (Vitest) covering fractional indexing, string/validation/misc utilities, and realtime tracker; 35 backend tests (Pytest + httpx) covering auth, card/board/list CRUD, bulk operations, and PocketBase hook side-effects
- App version displayed on Settings → Health page, fetched from
/VERSIONat runtime onboarding_completedfield onpreferencescollection for cross-browser onboarding persistence- Tooltip on sidebar "Add board or folder" button
Improved
- Settings dialog now defaults to Health page instead of Identity
- Welcome board upgraded from 1 card to 5 cards with checklists, 2 tags (
getting-started,tutorial), and richer descriptions - Frontend tests run automatically before every build (
pnpm buildruns vitest first) - Deploy script runs both backend (pytest) and frontend (vitest) tests before building
- Documentation link added to Git integration settings page
- Onboarding checklist items update reactively via
onboarding_signalcounter instead of stalelocalStoragereads
Fixed
- Onboarding checklist not updating in real-time when creating a card or using quick search (localStorage reads are not reactive - added signal-based re-read)
- Profile completion check was too strict (required avatar upload) - now checks name + profile color instead
v1.3.0
New
- Demo mode: full public sandbox experience - blocks destructive operations (settings updates, user/token CRUD, email/HTTP/AI automation nodes) while preserving core product UX
GET /api/demo/statusendpoint returns demo state and guest credentials- Demo guard hook (
hook_demo_guard.pb.js) blocks sensitive PocketBase operations server-side is_demo()andis_demo_error()helpers for consistent demo detection across frontend- Global fetch interceptor shows
toast.infofor demo-blocked requests without breaking PB SDK responses - Dismissible demo banner with light/dark mode support
- Feature tier gating: Teams ($500) < Pro ($1,500) < Enterprise ($5,000) with proper feature locks across UI
is_pro_or_above()andis_enterprise_or_above()helpers instate.svelte.jsandutil_license_tier.js- Enterprise gate component supports
tier="pro"prop for pro-level gating - API token authentication checks
is_pro_or_above()before allowing access - Settings navigation items display tier badges (pro, enterprise) with tooltip gates
- Checklist progress hook (
hook_checklist_counts.pb.js): auto-updateschecklist_countandchecklist_completedon card when checklists are created, updated, or deleted - fixes progress bar not showing for cards created via API/MCP - Documentation links added to all settings views (retention, sessions, templates, webhooks, etc.) pointing to docs.truetask.io and setup.truetask.io
Improved
- Demo mode automation guards:
action_send_email,action_http_request, andai_generatenodes return{ ok: false }in the automation engine when demo mode is active - Automation builder shows toast when loading an automation containing demo-disabled nodes (Email, HTTP, AI)
- Automation node palette shows toast when clicking or dragging a demo-disabled node
- Automation import shows toast when imported automation contains demo-disabled nodes
- Demo banner renders inside the viewport flex column instead of above it, preventing sidebar/content from being pushed past screen height
- Demo banner uses darker amber shades in light mode (
text-amber-700/text-amber-800) for better readability - All settings views import
is_demo_errorfor proper demo error handling in catch blocks - All settings views import
is_demo()to guard destructive actions with demo toast before execution - Data retention, sessions, templates, webhooks, and other settings components consistently handle demo mode
Fixed
- Tags not appearing on kanban cards in realtime: race condition where card update arrived before tag create event -
apply_card_updatenow checks for missing tag IDs and fetches them - Demo mode double toasts: removed demo toast from PB SDK
afterSendhook, kept only in global fetch interceptor - Demo mode fetch interceptor no longer throws (which broke PB SDK body parsing with
status: 0, data: {}), instead returns original response so SDK reads the 403 body correctly - Duplicate
is_demo()guard removed fromconfirm_deletein workflow templates settings
v1.2.006
Improved
- Install scripts wait for health check before showing access URL
- Install scripts use
post_startflow: health check → bind installation → display URL - Dev mode automigrate:
DEV_MODE=trueenables PocketBase automigrate for development instances - Update script uses
--force-recreateto ensure hooks reload on update - Added
flatten_migrations.shscript for flattening PocketBase migrations - Flattened migrations to include
portal_user_idfield on settings collection
Fixed
- Schema migration now includes
portal_user_idfield (was missing on fresh installs)
v1.2.005
Fixed
- License binding now correctly persists and enforces
portal_user_idacross activations - Added debug logging for binding check to aid troubleshooting
v1.2.004
New
- Two-tier license key system: separate trial and production signing keys
- License binding: installations are permanently bound to the portal account that installed them, preventing license sharing and trial cycling
- Install scripts bind the installation to the portal user account automatically after setup
POST /api/license/bindendpoint for installation-to-account bindinguser_idfield baked into license payloads for cryptographic account binding- Windows installer:
irm https://portal.truetask.dev/install.ps1 | iex(PowerShell)
Improved
- License types updated: trial, teams, pro, enterprise (replaces trial/standard/enterprise)
- Removed seat-based licensing - all plans now include unlimited users
- Removed
hardware_idfrom license payloads - replaced byuser_idbinding - Removed seat enforcement cron job
- License settings UI updated to reflect new tier names and removed seats/hardware ID fields
- Setup wizard: URLs auto-detect protocol (localhost → http, domains → https), bare hostnames accepted
- Setup wizard: admin credential prompts clarify they are for signing into the Truetask instance
- Setup wizard: localhost always displays with port, domains show reverse proxy reminder
- Updated all 5 locale files with new license type translations (teams, pro)
Fixed
- License activation rejects mismatched
user_idwith clear error message - License deactivation preserves account binding (prevents deactivate-reactivate abuse)
v1.2.003
Improved
- Versioned documentation deployment (docs.truetask.io, setup.truetask.io)
- CI/CD pipeline with Gitea Actions for auto-building docs on push
- Lean service worker (push notifications only, no Workbox precaching)
- Docker healthcheck for PocketBase container
- Fixed double-dash in API/MCP container names
- Setup wizard displays current directory on separate line
- Default workspace name changed to truetask-prod
v1.0.089
Fixed
- Fixed imports
- Fixed copying context
Improved
- Setup wizard shows current directory and resolved absolute path for data directory prompt
- Default data directory changed from ../truetask-data to ../data
- Management scripts included in release zip (start, stop, status, update, backup)
- Installer support email: [email protected]
v1.0.053
New
- Board templates: create new boards from pre-built templates (Scrum, Kanban, Bug Tracker)
- Keyboard shortcuts: navigate boards, create tasks, and switch views without touching the mouse
- CSV export for list view with configurable columns
Improved
- Card drag-and-drop is now smoother on large boards with 500+ tasks
- Board loading time reduced by 40% through optimized query batching
- Search results now highlight matched terms in card titles and descriptions
Fixed
- Cards occasionally duplicating when moved between lists during slow connections
- Notification badge not clearing after marking all as read
- Date picker closing unexpectedly when selecting a start date in Safari
- Automation triggers firing twice on boards with multiple webhook listeners
v1.0.052
- Initial public release
- The List view's status dropdown pins its selected check to the right edge. Opening a card's status (list) picker from a List-view cell, the checkmark on the current list sat right after the list name instead of out at the right edge, so it read as part of the label rather than a right-aligned marker. The row already grew the name with