Superset Updates & Release Notes
153 updates curated from 157 sources by the Releasebot Team. Last updated: Sep 8, 2026
- Sep 6, 2026
- Date parsed from source:Sep 6, 2026
- First seen by Releasebot:Sep 8, 2026
feat(cli): list, edit, and delete terminal scripts; add --upsert
Superset adds CLI commands to list, edit, and delete terminal scripts, plus `--upsert` to replace same-named scripts instead of duplicating them. The desktop import bridge now keeps v2 presets in sync when scripts are edited or removed.
Adds
superset scripts list,scripts edit <id>, andscripts delete <id>, plusscripts add --upsertto replace a same-named script instead of adding a duplicate.Extends the desktop's CLI import bridge so edited rows update their v2 preset in place and deleted rows remove the v2 copy.
Why / Context
superset scriptsonly supportedadd, so every revision of a script from the CLI piled up another pinned copy in the Scripts bar, and the only way to clean up was the desktop app. Reported on 1.26.0: five "Open in GitHub" presets after tweaking one command.How It Works
The CLI can only write the legacy
terminalPresetscolumn in local.db; v2 scripts live in renderer localStorage per organization. Every CLI change is therefore a marker on the legacy row that the desktop'suseCliTerminalScriptImporthook settles on the next refetch (focus, or the existing/settings-changednudge when the app is running):- add / edit / upsert set
cliImportPendingas before. The hook now updates an existing v2 row in place (bar position,createdAt, and any agent link are kept) instead of skipping it. - delete removes a row the desktop never imported immediately. Otherwise it leaves a new
cliDeletePendingtombstone; the hook deletes the v2 copy and the acknowledgement drops the row from the shared store. - list reads the shared store and replaces the markers with one
statuscolumn:ready,importing, ordeleting. --upsertlooks up the exact name among live rows and refuses when the name is already duplicated, listing the ids to delete.
No v2 → legacy write-through was added: the legacy store is still read by v1, so desktop-side edits stay out of it.
Manual QA Checklist
Run against the built binary (
bun run buildinpackages/cli) withSUPERSET_HOME_DIRpointed at a scratch local.db:-
scripts addtwice with the same name, thenscripts listshows both with statusimporting -
scripts add --upserton a duplicated name fails and lists both ids -
scripts delete <id>on a never-imported script removes the row immediately -
scripts add --hidden --upsertreplaces the remaining script in place (same id,pinnedToBar: false) -
scripts edit <id> --no-hidden --description "Opens the PR" --execution-mode split-panepatches only those fields -
scripts edit <id>with no flags, an unknown id, and--project+--all-projectstogether each fail with a hint - After simulating the desktop acknowledgement (markers stripped),
scripts delete <id>tombstones the row:listshowsdeleting, andediton it is refused -
scripts list --no-jsonrenders the table;--jsonreturns the public rows -
scripts --helpandscripts edit --helplist the new commands and flags - Desktop hook, driven live over CDP against the dev desktop app (signed-in dev profile, CLI pointed at its local.db and notifications port):
scripts add→ v2 row appeared inv2-terminal-presets-<org>within 500 ms, "CLI Drive Test" visible in the Scripts bar, legacy row back toreadyscripts edit(rename + new command) → same v2 row updated in place (same id,tabOrder,createdAt; no duplicate), and clicking it in the bar ran the new command (echo edited from cliprinted in the launched terminal)scripts delete→ v2 row removed, Scripts bar back to its four original entries, legacy row dropped,listback to the profile's original scripts
Testing
bunx tsc --noEmitinpackages/cli,packages/local-db, andapps/desktopbunx biome checkon changed filesbun testinpackages/cli(216 pass) and the touched desktop suites (cli-terminal-script-import,applyCliTerminalScriptEdit)
Known Limitations
scripts listcannot see scripts created in the desktop's Settings: they live only in the app profile.- Edits made in the desktop do not flow back to the CLI. A CLI edit replaces the app copy with what
listshows plus the requested changes. Documented in the CLI reference. - Presets migrated from v1 carry different ids in v2, so deleting one of those from the CLI only drops the shared row.
- An older desktop build ignores
cliDeletePending; the row then stays listed asdeletinguntil the app updates.
Compatibility
- The desktop change ships with the CLI change. A new CLI against an older desktop degrades as described above; an older CLI against the new desktop is unaffected.
Summary by cubic
Adds
superset scripts list,scripts edit <id>, andscripts delete <id>, plus--upsertonscripts add, so revising a script from the CLI replaces it instead of stacking duplicate pinned copies in the Scripts bar. The desktop import bridge now updates or removes the matching v2 preset when the CLI edits or deletes a script; changes reach the app on next open or refocus, or immediately if it's already running.Compatibility
scripts listonly shows scripts in the shared local store, not ones created in the desktop app's Settings.- A CLI edit overwrites the desktop's copy with what
listshows plus the requested changes; desktop-side edits do not flow back to the CLI. scripts deletealways leaves a tombstone, and the app drops the row only after removing its v2 copy; an older desktop build ignores the tombstone, so the script stays listed asdeletinguntil the app updates.- An older CLI against the new desktop is unaffected.
Summary by CodeRabbit
New Features
- Added CLI commands to list, edit, and delete terminal scripts.
- Added
--upsertsupport to replace scripts by name without creating duplicates. - Terminal script changes now synchronize with the desktop app, including additions, edits, and deletions.
- Added status reporting for synchronization and script availability.
Bug Fixes
- Improved retry handling for failed synchronization attempts.
- Prevented ambiguous duplicate-name updates.
Documentation
- Documented terminal script commands, options, statuses, and synchronization behavior.
- Sep 6, 2026
- Date parsed from source:Sep 6, 2026
- First seen by Releasebot:Sep 8, 2026
feat(billing): tell annual subscribers before we charge them
Superset adds annual subscription renewal reminder emails before Stripe invoice.upcoming charges, closing the gap between signup and yearly billing. The notice goes to billing roles only, skips monthly plans and seat changes, and includes tailored owner and admin payment instructions.
Annual only, on purpose
A yearly subscriber hears from us at signup and then nothing for twelve months, until a charge an order of magnitude larger than a monthly one lands. Stripe fires invoice.upcoming 7.0 days ahead (measured across the last 30 days, not assumed) and we were ignoring it — 413 a month, none handled.
Not monthly. 363 of those 413 events are flat $20 monthlies. A weekly heads-up before a charge people already expect mostly reminds them to cancel.
Not seat changes, even though that was the original motivation. MemberAddedBillingEmail and MemberRemovedBillingEmail already fire the moment seats change, to the same billing recipients, quoting seat count, new total, proration, and the exact next invoice via previewNextInvoice — whose own comment names the failure this would have duplicated:
"A seat-change email stating a total the customer will not be charged is how a card limit gets set too low, which is the whole reason this exists."
That leaves the genuine gap: 141 live annual subscriptions with no signal between signup and renewal.
Details worth reviewing
- No CTA. Nothing is payable yet — it's a renewal notice, not an invoice. Also sidesteps the missing web billing route.
- Subscription matched on the Stripe id, not the organization: an organization that resubscribed has several subscriptions rows and the wrong one can win. Same reasoning as the guard in fix(billing): stop dunning people who already cancelled #7217.
- Seats take the max quantity across lines, not the sum — a proration line carries its own quantity, and summing reports more seats than exist.
- Interval comes from our billingInterval column, because on the current API version invoice lines carry only a price id (pricing.price_details.price), with no expanded recurring.interval to read.
- Goes to BILLING_ROLES (owners + admins), not the whole team.
Verification
- Rendered the email and read the output; preview sent to Satya for copy review before this ships.
- lint.sh clean across 7,214 files. typecheck clean on auth, email, trpc, api, web. @superset/auth tests 8/8.
- Payload shape confirmed against a real invoice.upcoming event rather than assumed.
Summary by cubic
Sends annual subscribers a renewal notice before we charge them by handling Stripe's invoice.upcoming events, which we previously ignored. Only yearly plans get the email; monthly plans and seat changes are deliberately excluded because they already receive timely notifications or the charge is expected.
Details
- Subscriptions are matched on the Stripe subscription id, not the organization, to avoid hitting the wrong row for resubscribed organizations.
- Seat count uses the max quantity across invoice lines instead of the sum, because proration lines double-count.
- The email goes to billing roles (owners and admins) and contains no call to action since nothing is due yet.
- Owners are told to update the card in Settings → Billing; admins are told to ask an owner, since payment methods are owner-only.
Summary by CodeRabbit
- New Features
- Added renewal reminder emails for annual subscriptions before the upcoming renewal date.
- Reminders include the organization, plan, renewal amount, renewal date, and seat count.
- Payment-method instructions are tailored for account owners and administrators.
Fixed — valid catch. The notice goes to owners and admins (BILLING_ROLES), but requireOwnerWithCustomer refuses billing changes for admins, so the Settings → Billing instruction was unfollowable for half the recipients. Admins now get "ask an owner to update it", matching usePaymentFailedCard's existing owner/member split. Worth distinguishing from #7217, which removed an owners-only gate: that one was on a hosted invoice link, payable by anyone holding it. Our billing settings genuinely are owner-only, so this gate stays.
Original source All of your release notes in one feed
Join Releasebot and get updates from Apache and hundreds of other software products.
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
Commit, push, and open PRs from the Changes pane, image diffs, and a device-first Workspaces page
Superset adds a broader release with Changes pane workflows for commit, push, and PR creation, richer diffs for images, video, and PDF files, a rebuilt Workspaces page, new model and reasoning options, plus updates to sessions, billing, downloads, iOS, and many fixes.
Commit, Push, and Create a PR From the Changes Pane #7102 #7139 #7166 #7196
Commit, Push, and Create a PR From the Changes Pane
The Changes pane is now one surface for the whole branch: the diff, the changed-file list, and every step to a pull request. A pill in the top bar shows the diff stats, and the control next to it walks the branch from Commit to Push to Create PR, then becomes the PR badge once the pull request exists.
- Commit opens a message popover with a generated fallback, and Create PR prefills the title from your latest commit and pushes an unpublished branch for you
- Reply to PR review threads inline in the diff, without leaving for GitHub
- Search the changed-file list by path, and renames match their old path too
Open it with ⌘⇧L or the diff pill in the top bar.
Image, Video, and PDF Diffs #7035 #7182
Image, Video, and PDF Diffs
Binary files in the Changes pane render with the same viewers the file pane uses. A modified image shows Before and After side by side, at the version the diff compares (staged, against base, or a commit), not only the working tree. Videos and PDFs wait behind a Preview button so a large changeset stays light.
@theblondealex contributed the image previews.
Workspaces Page Rebuilt Around Devices #6901 #7150
Workspaces Page Rebuilt Around Devices
The page title is now the device you are looking at, with your other hosts a click away, and every row shows which machine it lives on, dimmed when that device is offline.
- Filter by project and by who created the workspace, next to the search box
- Board cards drop the repeated chrome: a muted project line, a state glyph beside the title, and a footer of PR, churn, and activity age
- Search and filters respond instantly, even with hundreds of workspaces
- Main checkouts with a finished agent show in Needs review, like every other surface
New Models and Reasoning Levels #7099 #7137 #7045 #7178 #6805
New Models and Reasoning Levels
Claude Fable 5.1 and GPT-6 Astra are in the model pickers and the usage pricing table. Codex offers its max and ultra reasoning levels on the models that accept them, and Cursor Agent gets a reasoning effort picker of its own. You can also pick a model per launch from the CLI, the SDK, and MCP, contributed by @Shravankb301:
superset agents create --workspace W --agent claude --model claude-fable-5-1 superset ws create --agent codex --model gpt-6-astraImprovements
- Session folders - sessions in the sidebar group into tag folders like projects do, with rename, colour, and bulk move from the context menu
- Sort and filter projects - order the sidebar's projects by last active or date created, and filter by name from the magnifier in the Projects header
- Hide projects - Hide from Sidebar keeps a project's groups and pins for when you bring it back, and owners get Delete Project in the same menu
- Leaderboard rank card - Settings → Usage shows your rank, tier, and the token gap to the row above you; opt in with Reveal my rank
- API-billed usage profiles - Add account offers Subscription or API key, and API profiles show Billed per token with a link to the provider's usage page, based on @iamgadmarconi's original PR
- ⌘= and ⌘- follow focus - a terminal steps its font size, a browser pane steps its zoom, anything else zooms the app; ⌘0 resets
- Open in - right-click a link, path, or folder in a terminal and pick where it opens, with the same destinations as Settings → Links
- Terminal scripts from the CLI - superset scripts list, edit, and delete, plus add --upsert to replace a same-named script instead of adding a duplicate
- Automations - new Review requested and Assigned pull request triggers, with a people chip for whoever landed on the PR
- Darker theme - a near-black theme with Superset's ember accent in the marketplace, contributed by @0x962
- Remote worktrees follow you - a worktree you created on another machine gets a sidebar row here as soon as its host is online
- Pages up to 16 MB - page documents upload straight to storage, so a page with a dozen screenshots no longer hits the old 3 MB limit
- Downloads page - lists every release with per-OS assets, and Linux auto-downloads like macOS
- iOS - session tabs sit at the bottom by your thumb, the PR link moves beside the quick keys, and Copy ID confirms with a notice
- Billing - annual subscribers get an email a week before the renewal charge
Bug fixes
- Desktop - the app no longer freezes after closing a dialog opened from a context menu
- Desktop - pressing Enter on Delete in a workspace context menu shows the confirmation instead of deleting outright, and bulk delete runs behind a progress toast instead of a blocking dialog
- Sidebar - dropped rows land where the drag preview showed them, and dragging costs about 3x less per move
- Sidebar - the sidebar no longer holds a live git watch on every workspace row, which kept large repos busy
- Terminal - a resize during an image decode can no longer kill the terminal, and "Auto-run on workspace creation" scripts run again
- Terminal - Superset now reaps the wedged host-service children an auto-update leaves behind, so terminals stop freezing after a relaunch
- Browser - Sign in with Google works from the in-app browser, and the overflow menu closes on a click into the page
- Usage - a Claude login with a lapsed access token no longer reads as expired, and Keychain logins resolve by account
- Agents - switching accounts restarts idle agents too, and a swept terminal's agent session stays resumable, contributed by @owieschon
- Pull requests - merges take GitHub's merge time instead of the time Superset first saw them, contributed by @owieschon
- Workspaces - delete re-checks the disk after git unregisters the worktree, contributed by @sahiljagtap08, and tags stay with the user who applied them on shared hosts
- Settings - Settings → Agents loads against host services older than 1.24
- Editor - Dockerfiles and Makefiles get syntax highlighting, contributed by @mjspeck, and Download as PNG works on mermaid diagrams
- Themes - standalone red text uses each theme's own red instead of the default theme's pink
- Accounts - the app no longer moves you into the organization you joined most recently
- iOS - diffs no longer render black on black for unsupported languages
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): device-first Workspaces page — device on rows and title, creator filter, menu/typing perf - #6901
Superset reworks the Workspaces page around device-first controls, adds Created by filtering, and speeds up filter and search interactions. It also restores device details in rows, refines the toolbar, and remembers the last List or Board view.
Reworks the v2 Workspaces page around devices and fixes the interaction lag on its header controls.
- Device on every list row: restores the device item removed with the Host column in feat(desktop): rework Workspaces page into a status-grouped triage list #6506 — laptop/monitor icon + host name before the timestamp, dimmed with a grey dot when a remote device is offline (matches the board card's vocabulary).
- Device-first header: the page title is now the device filter dropdown (real machine name, other hosts with online dots), with a primary Create workspace button opposite; the title row doubles as the window-drag surface. Second row: bare borderless search on the left; first-class project filter (selected project's icon in the trigger) plus compact Filter / Display / List–Board controls on the right. The archived-window control moved back under Display.
- Created-by filter: new "Created by" submenu in the Filter menu (avatars, "(you)" marker), wired through the filter store, row filtering, and the URL as ?creators=.
- Perf, measured over CDP against the running app:
- Filter-checkbox toggles painted in 300–515ms (all 200+ rows re-rendered synchronously behind the open menu). memo() on rows/cards + useDeferredValue on the list data + modal={false} on the header menus → checkbox paints ~143ms with the list catching up off the critical path; menus no longer scroll-lock the page.
- Typing in search cost 76–197ms per keystroke, ~40% of it the dashboard sidebar re-rendering because the URL synced (navigate()) on every key. Debounced the URL sync (300ms) + deferred the search query into the filter hook → 5–12ms per keystroke.
Test plan
- Typecheck (tsc --noEmit) passes
- CDP end-to-end in the dev app: device dropdown opens/lists hosts; Created-by toggle filters rows (238→175) and round-trips the URL; project icon renders in the trigger; search focus shows no ring/background
- Latency re-measured after each fix (menu open 41ms; checkbox paint 515→143ms; keystroke processing 197→12ms)
- Sanity-check board view drag/menus after the memo() /non-modal changes
Summary by cubic
Reworks the Workspaces page around devices, adds a Created-by filter, and fixes the lag in filter menus and search typing. All new header strings are localized across all 16 locales, the sidebar pin filter is relabeled "Sidebar", and the last chosen List/Board view is remembered across sessions (filters and search still reset, and a ?view= deep link overrides).
New Features
- List rows show the host device again: laptop icon for the local machine, monitor for remote, dimmed with a grey dot when a remote device is offline.
- The page title is now a device filter dropdown showing the actual machine name, with a "Create workspace" button opposite it.
- Added a "Created by" submenu to the Filter menu with avatars and a "(you)" marker, synced to the URL as ?creators=. It lists organization members rather than just visible-row creators, so teammates whose workspaces live on unreachable devices stay filterable.
- The project filter is a first-class trigger showing the selected project's icon; the archived-window control moved back under Display.
- Search is now a bare borderless input with no focus ring.
- Container-query variants compact the toolbar and rows for narrow panes: Filter/Display/List/Board go icon-only, the device item shrinks to its glyph, and diff stats hide.
Bug Fixes
- Filter checkbox toggles took 300–515ms because every row re-rendered synchronously; memoized rows/cards, deferred list updates, and non-modal menus cut checkbox paint to ~143ms.
- Each search keystroke cost 76–197ms because URL sync re-rendered the whole app; debounced sync (300ms) and deferred search cut it to 5–12ms.
- A creator filter with zero matches now shows "No workspaces match your filters" with a Clear filters button instead of the empty-account message.
- isReady is deferred with the rows so a settling host query can't flash the empty state while the first rows render.
- When the device item shrinks to its glyph, the host name stays readable to screen readers via an sr-only label; the offline dot has its own sr-only "Offline" label.
- Board view drag and menus still need a sanity check after the memoization and non-modal changes.
Summary by CodeRabbit
New Features
- Added creator-based workspace filtering with creator names and workspace counts.
- Added prominent device and project filters, plus a “Create workspace” action.
- Moved search to the top toolbar.
- Workspace rows now show device details and offline status.
- Creator filter selections sync with the URL.
Performance
- Improved responsiveness during workspace filtering and searching.
UI Improvements
- Updated filter counts, clearing, dropdown alignment, and view controls.
- Improved layouts for narrower panels.
- Added translated labels for the updated workspace controls.
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): hide projects from the sidebar and delete them from the context menu - #7176
Superset replaces the old Remove from Sidebar action with a reversible Hide from Sidebar that preserves project data, and adds Delete Project… for organization owners with clearer deletion details and a hidden-projects list that survives reloads.
Why
Discord feedback (fluxchamber, gislol in #feature-requests): "Remove from Sidebar" on a project reads like a removal but only hides the project, and it wipes the project's groups and pins on the way out. Deleting for real lives only in project settings, and an agency user asked for an "archive" for dormant customer repos. Project folders (#4018) are out of scope here.
What
- Hide from Sidebar replaces Remove from Sidebar. It flips a new isHidden flag on the local placement row and touches nothing else, so unhiding brings the project back with its groups, pins and order intact. Hiding shows an undo toast. Hiding the project you are currently inside lands you on the workspaces list.
- Hidden projects row at the foot of the project list ("N hidden projects") lists what is hidden and restores one per click. Survives reload.
- Any path that would add the project to the sidebar (setting it up on this device, opening one of its workspaces, an agent creating a worktree in it) reveals it, matching what re-adding a removed project used to do.
- Hidden projects leave the visible-workspace set, so their workspaces stop raising notifications until shown again.
- Delete Project… in the context menu for organization owners, sharing one DeleteProjectDialog with project settings. The copy states how many worktrees are removed from disk, that the repository folder is kept, that worktrees with uncommitted changes stay on disk, and how many offline devices keep their copy.
- The tombstoning removeProjectFromSidebarState path and its tests are deleted. New tests cover the hide flag and the ensure-reveals-hidden rule.
- Eight new strings translated into all 16 locales.
Verification
Driven over CDP in the dev desktop app (worktree scandalous-tulip, signed in as the dev account), using trusted mouse events on the real context menu:
- Context menu shows Hide from Sidebar and Delete Project… for an owner.
- Hide: row gone, undo toast, "1 hidden project" row, isHidden: true in local storage; Undo restores.
- Hidden state persists across reload; the hidden-projects dropdown restores the project with its group still attached.
- Hiding from inside the project's own workspace navigates to /v2-workspaces and stays hidden.
- Delete dialog on a real project with 9 worktrees shows the plural copy; Cancel leaves it untouched. Deleting a throwaway project removes it from the host, shows the toast, and leaves its folder on disk.
- No console.error during the whole journey. Typecheck, biome, check:i18n clean; sidebarMutations.test.ts passes.
Summary by cubic
Replaces the old "Remove from Sidebar" action, which hid a project but wiped its groups, pins, and order, with a reversible "Hide from Sidebar" that preserves them, and adds "Delete Project…" to the context menu for organization owners.
Changes
- "Hide from Sidebar" flips a local isHidden flag and leaves placement data untouched.
- Hidden projects appear in an "N hidden projects" row at the bottom of the project list and can be restored one at a time; hidden state survives reload.
- Opening a hidden project or creating a worktree in it reveals it again.
- Hidden projects' workspaces stop raising notifications and pull-request polling until shown again; hidden ids come from persisted placement rows so this holds even when the host is offline.
- "Delete Project…" reuses the same confirmation dialog as project settings; the dialog counts only worktrees on hosts the delete will reach, using each workspace's host-reachable flag.
- Removes the old tombstoning removal path and its tests, and adds tests for hiding and re-revealing.
Side effects
- Deleting a project removes its worktrees from reachable hosts but keeps the repository folder; dirty worktrees and offline hosts keep their copies.
- Hiding the project you are currently inside navigates to the workspaces list.
Summary by CodeRabbit
- New Features
- Projects can be hidden from the sidebar and restored from a dedicated hidden-projects list while preserving their sidebar placement.
- Added project deletion with confirmation details for devices, worktrees, offline copies, and repository folders.
- Project deletion is available to organization owners.
- Bug Fixes
- Hidden projects no longer appear as visible workspaces or trigger related sidebar notifications.
- Localization
- Added and updated translations for hidden-project and deletion workflows across supported languages.
Additional notes from reviews:
- Worktree count now covers only hosts the delete will reach.
- Hidden projects no longer feed pull-request polling, and their workspaces are skipped by the post-removal navigation list.
- Czech wording uses the git term for uncommitted changes; ja/zh/ko/vi/id/tr plurals carry both branches; Turkish has a singular possessive for one worktree.
- Reachability via relay URL for offline remote hosts is the same logic the settings delete used before this PR.
- Legacy placement rows without isHidden treat missing flag as false.
This PR was merged 3 days ago by Kitenite with 3 commits, 1153 additions & 734 deletions.
Original source Similar to Superset with recent updates:
- Qlik Sense updates22 release notes · Latest May 1, 2026
- Qlik Cloud updates293 release notes · Latest Sep 9, 2026
- Tableau updates23 release notes · Latest Jul 1, 2026
- ThoughtSpot Cloud updates19 release notes · Latest Jul 1, 2026
- Power BI updates54 release notes · Latest Aug 1, 2026
- Tableau Server updates36 release notes · Latest Aug 27, 2026
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): add API-billed usage profiles - #7175
Superset adds API-key billing support for Claude Code and Codex profiles, with billing status, provider usage links, and secure sign-in flows. The Usage page now shows accounts sooner, keeps login detection running in the background, and preserves billing type when switching sign-in.
Supersedes #6967 (thanks @iamgadmarconi) — that branch was 141 commits behind main and on the retired explicit-ID i18n scheme, so this re-applies it on main and reworks the UI. Fixes #6966.
The Usage page can already discover several Claude Code and Codex subscription profiles and switch the default with one click. API-billed profiles (Anthropic Console,
codex login --with-api-key) could not take part. Now:- Add account gets a Billing row: Subscription or API key. The generated command runs the provider's own API login and then writes a marker file into the profile dir; the key never passes through Superset.
- API-billed profiles get an API badge and, instead of quota bars, a "Billed per token" line with a View usage link to the provider's usage page.
- Switch sign-in on an API profile stays on API billing (re-runs the API login, rewrites the marker); Remove works as for any profile.
- Sections render before the first quota read lands, so Add account is reachable immediately.
Changes vs #6967
- Marker is agent-tagged. The marker now holds
claudeorcodex. A presence-only marker made every marked~/.codex-*home also show up as a Claude API profile, because Claude discovery scans all~dot-dirs (reproduced in the running app). - Codex command is one line with
read -rsinstead of thestty/trapsubshell, and the marker step precedesunsetso it follows the login's exit status. A multi-line paste would feed the next line toreadas the key, so it stays single-line on purpose. - Login poll survives an unfocused window.
useHostUsageLoginssetsrefetchIntervalInBackground: true. The app ties react-query's focusManager to window focus, so the poll paused exactly while the user was off in a terminal signing in, and the dialog never noticed the new profile. - Inline
RadioGroupinstead ofTabs; dialog copy trimmed; catalogs for all 17 locales.
How I tested it
bun testonpackages/host-service/src/trpc/router/usage(97 pass) and the desktop usage folder (39 pass): agent-tagged marker classification, fingerprint changes on re-login, other agent's marker ignored, unmarked APIauth.jsonignored, generated commands for both agents and both billing kinds.typecheckfor desktop and host-service, biome clean,bun run check:i18nclean.- Real dev app over CDP, window unfocused:
- Ran the generated Codex command verbatim with a throwaway key:
codex login --with-api-keyaccepted it from stdin and the marker was written; the profile appeared under Codex only. - Claude add flow with API billing: simulated the Console login finishing by writing the marker; the dialog detected it in ~1.5s.
- Switch sign-in on an API profile shows the API login command; Remove deleted both test dirs.
- Ran the generated Codex command verbatim with a throwaway key:
- Not exercised: a real Anthropic Console OAuth login.
Screenshots
Cards under Claude Code and Codex, the dialog in API mode for both providers, the detected state, and Switch sign-in are in the session link below.
https://claude.ai/code/session_01Qy1bWiGW9qq8V3zZ64v2r3
Summary by CodeRabbit
- New Features
- Added support for API-key billing profiles for Claude and Codex.
- API-billed accounts now show billing status and a link to provider usage pages instead of quota windows.
- Added terminal-based sign-in guidance, including secure API-key entry for Codex.
- Account switching preserves billing type.
- Improvements
- Usage sections now appear immediately with per-agent “Reading usage…” states.
- Login discovery continues while the app is unfocused.
- Updated translations across supported languages for billing, sign-in, usage, and zoom controls.
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): scope Cmd +/-/0 to the focused terminal or browser pane - #7174
Superset adds context-aware zoom shortcuts that act on the focused surface, stepping terminal font size, browser pane zoom, or the whole app as needed. The shortcuts are now registry hotkeys and can be customized in Settings > Keyboard.
Summary
- Cmd/Ctrl =, -, 0 now act on what has keyboard focus: a terminal steps its font size (Cmd+0 resets to the default), a browser pane steps its page zoom (Cmd+0 = 100%), anything else zooms the whole app as before (Cmd+0 = 100%).
- Implemented as three registry hotkeys (ZOOM_IN/ZOOM_OUT/ZOOM_RESET, customizable in Settings > Keyboard) instead of Electron's menu roles owning the keys.
Why / Context
The View menu's zoomIn/zoomOut/resetZoom roles registered the accelerators, so Cmd+= always zoomed the entire window, even while typing in a terminal or browsing in a pane. VS Code, iTerm, Windows Terminal and Chrome all scope these keys to the focused surface.
How It Works
- useZoomHotkeys (mounted with the other global hotkeys in the dashboard layout) resolves a target from document.activeElement: xterm's helper textarea = terminal, a = that browser pane (looked up through browserRuntimeRegistry), else app.
- Terminal: steps the persisted terminalFontSize by 1 within FONT_SIZE_LIMITS via the shared useFontSettingsMutation (optimistic cache + live xterm sync, extracted from the settings page so both callers use it). Reset clears the override. Applies to all terminals, like VS Code's terminal font zoom.
- Browser: new browserRuntimeRegistry.stepZoom (10% steps, rounded so repeated steps don't drift); the overflow-menu buttons use the same method. The three chords join the pane's forwardable set, so a focused guest page forwards them to the host like tab switching already does.
- App: new window.zoom mutation steps the sender window's zoom level by 0.5, matching the old roles.
- Menu: the roles stay, with registerAccelerator: false, so the shortcuts remain visible and the items still zoom the page on click, but the renderer sees the key first. The terminal key handler already lets any registered hotkey chord bubble, so nothing leaks into the PTY on Windows/Linux.
Manual QA Checklist
Verified in the dev app over CDP with real OS keystrokes (AppleScript key codes), instance confirmed by pid path and Vite port:
- Terminal focused: Cmd+= 14 → 15, Cmd+- ×3 → 12, Cmd+0 → default (setting cleared); app zoom untouched
- Nothing focused: Cmd+= / Cmd+⇧= / Cmd+- / Cmd+0 step the app zoom 1.10 → 1.20 → back to 1
- Browser tab active, webview focused: Cmd+= 0.9 → 1.0 → 1.1, Cmd+0 → 1, Cmd+- → 0.9; app zoom untouched (forwarded through before-input-event)
- xterm emits no data to the PTY on Cmd+- / Cmd+0 (checked via terminal.onData)
- Windows/Linux: Ctrl+= / Ctrl+- / Ctrl+0 in a terminal (not tested here; relies on the existing registry-chord bubbling in terminal-key-event-handler)
Testing
- bun run typecheck
- bunx biome check on touched files
- bun test for renderer/hotkeys, useZoomHotkeys, BrowserPane
- bun run check:i18n (new strings translated in all 16 locales)
Known Limitations
- Numpad + / - are not bound (the old roles didn't bind them either).
- If a user rebinds the zoom hotkeys, the View menu still displays the default shortcut labels (display-only accelerators).
Summary by cubic
Scopes Cmd/Ctrl +, -, and 0 to the focused surface — a terminal steps its font size, a browser pane steps its page zoom, and anything else zooms the whole app — instead of always zooming the entire window. The shortcuts are now registry hotkeys, rebindable in Settings > Keyboard.
Zoom behavior
- Terminal font size steps by 1 within the existing limits; reset clears the override, and rapid key repeats keep stepping correctly.
- The terminal step math lives in a unit-tested helper covering limit clamps, half-point sizes, and reset.
- Browser pane zoom steps by 10% from the page's live factor, with the same bounds as the overflow menu, and focused guest pages forward the keys to the host.
- App zoom steps through a new window.zoom mutation, clamped to Chromium's 0.25–5 range.
- The View menu keeps its zoom items and shortcut labels, but the renderer handles the keys first. The hotkeys work across all authenticated routes, including settings.
Summary by CodeRabbit
New Features
- Added keyboard shortcuts for zooming in, zooming out, and resetting zoom.
- Zoom shortcuts now apply contextually to terminal font size, browser pane zoom, or the overall app.
- Added consistent zoom limits, step sizes, and localized guidance across supported languages.
Bug Fixes
- Prevented menu shortcuts from applying page zoom before focused content is handled.
- Terminal font-size changes now update immediately and recover safely if saving fails.
- Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): add an "Open in" submenu to terminal link right-clicks - #7179
Superset adds an Open in submenu to terminal right-click menus, making link actions easier to discover for URLs, files, and folders. It also keeps context menus accurate under the pointer and adds localized labels for browser, editor, Finder, and tab actions.
Summary
• Right-clicking a link in a terminal now offers Open in ▸ at the top of the context menu, with the same three destinations that link kind already has in Settings → Links.
• The entry is hidden entirely when the right-click did not land on a link, so the menu is unchanged everywhere else.Screenshots
Right-clicking a linkified URL, file path, and folder in a terminal. Hosted on the
pr-7179-screenshots branch (same pattern as pr-6787-screenshots ) and pinned by commit SHA,
so they never enter main's tree.Why / Context
Terminal links were reachable only by modifier-click, and the bindings are invisible unless you go and read Settings → Links (or hover long enough for the hint). Defaults are plain: null, ⇧ → new browser tab, ⌘ → in-app browser pane, ⌘⇧ → default browser — so a plain click on a URL does nothing at all, which is a confusing first experience. The right-click menu is the discoverable place for "where should this open?", and it had no link items at all.
How It Works
Each link kind gets its own trio, named the way Settings → Links already names them:
right-clicked submenu
URL In-App Browser · New Browser Tab · Default Browser
file path Tab · New Tab · Editor
folder Sidebar · Editor · Finder
The pane context menu is built in usePaneRegistry, which can see neither the hovered link nor the hooks that open files, folders and URLs. TerminalPane therefore publishes both into a small store on contextmenu — capture phase, before Radix opens the menu, while the pointer is still over the link. Recording on the event rather than reading live hover state is what keeps the two in step: a right-click on blank terminal records null, so a stale link from an earlier hover can never leak into the menu.
Three supporting changes:
• packages/panes: ContextMenuActionConfig gains hidden?: boolean | ((ctx) => boolean), evaluated when the menu opens rather than when the action array is memoized. Without it an entry cannot depend on state that changes between opens — resolvedContextMenuActions is a useMemo on [context, contextMenuActions, definition], and subscribing the whole registry to hover state would rebuild every pane definition on every mouse move.
• LinkHoverInfo now carries the URL (it previously only said kind: "url" ) and the file's row/col, threaded through all three link providers (LinkDetectorAdapter, UrlLinkProvider + its OSC 8 handler, WordLinkDetector).
• runTerminalLinkAction is now shared by the modifier-click handlers and the menu, so the two paths cannot drift apart.Manual QA
Driven over CDP against the dev app (v2 workspace, real terminal, real host service):
• Right-click a URL → Open in ▸ shows In-App Browser / New Browser Tab / Default Browser
• Right-click an absolute file path → Tab / New Tab / Editor
• Right-click a directory path → Sidebar / Editor / Finder
• Right-click on non-link terminal output → no Open in , no stray separator; menu byte-for-byte as before
• Right-click a word that looks like a path but does not resolve (AGENTS.md in an empty cwd) → no Open in , since no link is detected
• Open in → In-App Browser on https://example.com/abc opens a browser pane at exactly that URL
• Open in → New Browser Tab opens a new tab with a browser pane
• Windows/Linux (macOS only here — nothing platform-specific in the change, but the Finder entry is macOS-shaped and matches the existing folder policy)Testing
• bun run typecheck — @superset/desktop and @superset/panes clean
• bun run lint — clean
• bun run check:i18n — clean; 5 new ids (In-App Browser, New Browser Tab, Default Browser, Editor, Finder) translated across all 16 locales. "Open in", "Tab", "New Tab" and "Sidebar" reuse existing entries — each verified to be the same referent at its existing call sites, so no context split was needed.
• bunx sherif — no issues
• bun run --filter=@superset/panes test — 110 pass
• bun run --filter=@superset/desktop test — 3469 pass, 1 pre-existing env failure (LeaderboardRank asserts https://superset.sh/... while this worktree's .env sets NEXT_PUBLIC_MARKETING_URL=http://localhost:8202 ; untouched by this diff)
• bun turbo run build --filter=@superset/desktop
• Updated one assertion in terminal-link-manager.test.ts that pinned the old { kind: "url" } hover shape.Design Decisions
• hidden on the action config instead of rebuilding the registry. Making the menu link-aware by subscribing usePaneRegistry to hover state would re-create every pane definition on every mouse move over a link. A predicate evaluated at open time costs nothing and keeps the hot path untouched.
• Snapshot on contextmenu , not live hover state. Radix opens the menu under the cursor, which can make xterm fire leave between the click and the menu render. Capturing in the capture-phase handler removes that race.
• Terminal-specific modules stay under TerminalPane/ even though usePaneRegistry imports them. That follows the existing arrangement in this folder — usePaneRegistry.tsx already reaches into TerminalPane/components/ for TerminalPaneHeaderExtras , TerminalPaneIcon , and TerminalSessionDropdown .
• No "Copy Link Address". The existing Copy already covers the selection, and pairing a copy action with an "Open in" group read oddly.Known Limitations
• UrlLinkProvider 's hard-wrap joining over-captures when a URL sits at the very end of a line immediately above the prompt: https://superset.sh/docs becomes https://superset.sh/docsrelay-v1-decommission-2 . Pre-existing and not introduced here — xterm hands activate and hover the same link.text and both forward it unchanged, so the menu opens exactly what a modifier-click would open. Worth its own fix.
• Only the v2 terminal pane. v1 (screens/main) is being deleted, so it was deliberately left alone.Summary by CodeRabbit
• New Features
Original source
◦ Added an “Open in” submenu for terminal links, including browsers, editors, Finder, workspace tabs, and in-app navigation.
◦ File links preserve row and column positions when opened.
◦ Folder links can be opened, revealed, or shown in the sidebar where applicable.
• Bug Fixes
◦ Improved URL and file-link hover information and right-click handling.
◦ Context menus now accurately reflect the link under the pointer.
• Localization
◦ Added translations for browser, editor, Finder, and tab labels across supported languages. - Sep 5, 2026
- Date parsed from source:Sep 5, 2026
- First seen by Releasebot:Sep 8, 2026
feat(marketplace): add Darker theme
Superset adds the Darker near-black dark theme to the marketplace, with cool grey tones, ember accents, terminal color mappings, and editor comment styling. It also ships a downloadable theme package with marketplace metadata and tags.
How I tested it
Darker is a near-black dark theme. The greys are cool and step up in small increments from #08090a, so the app reads as one dark sheet. The accent is Superset's own ember #e07850, on highlight, sidebarPrimary, ring, chart1, and the terminal cursor. The ANSI palette is Superset's Ember set. This adds the downloadable theme JSON and the catalog listing.
The theme pins editor.syntax.comment to #8a8f98 instead of letting the diff view inherit terminal.brightBlack. That inheritance is the contrast problem fixed for Tokyo Night. For the same reason I lifted ANSI brightBlack to #7d7875, because Ember's #5c5856 only reaches 2.83:1 on this background. Every text color meets WCAG AA. The lowest pair is mutedForeground on accent at 5.19:1.
I ran the marketing app and loaded both marketplace pages. The card and the detail page render the palette correctly, and the download link returns the JSON with a 200.
I also parsed the file with the desktop importer, parseThemeConfigFile in packages/shared/src/themes/import.ts. It returns zero issues and one theme, with 38 UI keys and 21 terminal keys. I then imported it into my own desktop app with superset settings theme import and ran it as the active theme.
bun run lint, bun run typecheck, and bun run test pass across the monorepo.
Checklist
- PR title follows conventional commits (type(scope): subject)
- bun run lint and bun run typecheck pass (CI fails on lint warnings too)
- "Allow edits from maintainers" is checked on fork PRs
Summary by CodeRabbit
New Features
- Added the Darker theme to the marketplace.
- Introduced near-black backgrounds, cool-grey text, ember accents, terminal color mappings, and editor comment styling.
- Added a downloadable theme package with marketplace metadata and tags.
- Sep 4, 2026
- Date parsed from source:Sep 4, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): sort and filter projects in the dashboard sidebar
Superset adds sidebar Projects sorting and filtering with persisted Manual, Last active, and Date created views, plus inline name search, drag gating, and empty-state handling. It also persists host activity timestamps, improves timestamp safety, and localizes the new UI across all enabled locales.
Adds sort and filter controls to the dashboard sidebar Projects list — previously ordered only by manual drag, it can now be ordered by last activity or creation date and filtered by name. "Last active" runs on a new host-persisted activity timestamp instead of the 10-second polling from #6005, which this supersedes; drag is disabled whenever a non-manual sort or a filter is active.
New Features
- Sort menu in the Projects header offers Manual order (default), Last active, and Date created; the choice persists per user in v2UserPreferences and survives restarts.
- The inline filter matches project, workspace, and folder names case-insensitively, auto-expanding matches and pruning non-matching siblings, with a "No projects match" row for empty results.
- Returning to Manual restores the exact prior drag order; drag is inert in every other sort mode and while filtering.
- "Last active" ranks by a new lastActivityAt column stamped by the host on every agent lifecycle event, throttled to one write per 30 s per workspace.
- All new UI strings are translated across every enabled locale.
- The filter closes when the Projects section collapses, the header keeps its "Projects" accessible name while the input takes the row, and ⌘1–⌘9 skip the persisted collapse toggle while a filter is active.
Migration
- Host service adds nullable last_activity_at; new workspaces stamp creation as first activity, pre-existing rows stay null and fall back to updatedAt until their first agent event.
- Apply drizzle migration 0030_workspace_last_activity_at.
- Timestamps are coerced NaN-safely so cached string dates can't crash the sidebar (the failure mode of the first landing).
- A row's cached lastActivityAt survives an older host's updated event that omits the field.
Summary by cubic
Adds persisted manual, last-active, and creation-date sorting plus inline project filtering to the desktop dashboard sidebar. Persists workspace activity in the host database and streams it through workspace list and change-event contracts. Adds timestamp-safe project, folder, and workspace sorting with deterministic tie-breaking. Adds derived filtering, automatic match expansion, empty-state messaging, and drag gating for transformed views. Extends preference persistence, compatibility normalization, localization catalogs, documentation, and tests.
Confidence Score: 5/5
The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issue identified. The host activity signal, compatibility normalization, derived sorting and filtering, selection handling, and drag gating remain aligned across the changed data and UI paths.
Original source - Sep 4, 2026
- Date parsed from source:Sep 4, 2026
- First seen by Releasebot:Sep 8, 2026
feat(automations): trigger on a pull request being assigned or review-requested - #7163
Superset adds new GitHub automation triggers for Review requested and Assigned, plus a Me filter for PR assignees and reviewers. GitHub PR events now open the checked-out pull request in the workspace, with safe fallbacks when checkout is unavailable.
Two new GitHub automation triggers, Review requested and Assigned, under the Pull request… submenu.
GitHub already delivered both actions on the pull_request webhook we subscribe to. githubEventNames returned nothing for them, so the rows landed in automation_events and stopped there. No GitHub App permission or event-subscription change is needed.
The new people slot
Their sentence carries a third people chip, for whoever was put on the PR:
Review requested from [Me] in [superset] by [Anyone]
That is a different person from the actor, who is whoever did the assigning. Set the chip to "Me" and a run starts when a PR lands on you; it resolves against the automation owner's GitHub identity at delivery, through the existing resolveMeScopes path.
The payload names the person directly — assignee on an assignment, requested_reviewer on a review request — so nothing is synthesised from a before/after diff the way Linear's issue.assigned has to be.
A team review request stays silent. GitHub names the team and nobody in it, so matching "assigned to me" against it would fire for every member of that team. There is a test pinning that.
Workspaces now land on the PR
A run whose event names a pull request creates its workspace with that PR checked out, via the pr input workspaces.create has had since 0.1.0, instead of a fresh timestamped branch. The host reuses the workspace already on that branch, so repeated events on one PR share it.
Three guards:
- Repository must match the project. PR numbers are per-repository, and a trigger watching one repo can dispatch into a project pointed at another, so an unchecked number would check out an unrelated pull request.
- Fork PRs are refused, for the same reason includeForks is a literal false: their head is attacker-controlled content the agent would then run in.
- A failed checkout falls back to a fresh branch. Resolving a PR shells out to gh, which runs on the user's own gh auth login and may be missing or expired on a host. A PR we cannot fetch must not turn a run that would have worked into a failure; the agent still gets the PR url and number in its prompt context.
⚠️ Behaviour change worth a look: the PR checkout applies to every GitHub trigger that names a pull request, not just the two new ones. An existing "comment added" automation will now start on the PR rather than an empty branch. I believe that is what people want and the fallback keeps it safe, but it does change existing automations. Happy to gate it to the new events if you would rather.
Verification
Typecheck passes on shared, trpc, api and desktop. Biome clean. check:i18n compiles with "Review requested" translated into all 16 locales; "Assigned" already existed in the catalogs from Linear's menu and correctly shares the one entry, same meaning and same position.
Summary by cubic
Adds two new GitHub automation triggers, "Review requested" and "Assigned", that fire when someone is put on a pull request. Runs triggered by any PR-naming event now check out that pull request instead of a fresh branch.
New Features
- New triggers fire on pull request assignment and review request, each naming the person added.
- A "Me" filter on that person starts a run when a PR lands on you.
- No new GitHub App permissions or event subscriptions are needed.
Behavior changes
- Existing automations on PR events now start on the PR's checked-out branch instead of an empty one.
- A PR is only checked out when the payload positively proves it is not a fork; a comment event on a fork PR branches fresh instead.
- A checkout refused by the host (e.g., missing gh login) falls back to a fresh branch; timeouts or transport errors rethrow so the retry meets the host's per-PR dedupe.
- Team review requests match an "Anyone" filter but never a named person, since they don't name an individual.
Summary by CodeRabbit
- New Features
- Added GitHub pull request automation triggers for Assigned and Review requested events.
- Automations can target a specific assignee or reviewer, or match anyone.
- Matching distinguishes the assignee from the person who performed the action.
- Supported pull request events can create workspaces directly from the pull request.
- Bug Fixes
- Unsupported, forked, or failed pull request checkouts now fall back to creating a fresh branch.
- Localization
- Added translations for “Review requested” across supported languages.
Security Review
The issue-comment payload path bypasses the new fork refusal because it derives the PR number from payload.issue while checking fork status only on payload.pull_request. This permits comment-triggered automations to run inside a fork-controlled checkout.
How this was verified: The issue-comment event was traced through matching and dispatch to host PR materialization, whose cross-repository path does not reject fork heads.
Important Files Changed
packages/trpc/src/router/automation/dispatch.ts and apps/api/src/app/api/github/webhook/normalizeGithubDelivery.ts
Confidence Score: 2/5
The PR should not merge until fork issue-comment events are prevented from reaching PR checkout and transport-ambiguous checkout failures preserve the intended workspace target.
Issue-form pull-request events can bypass the fork boundary and place an automation agent in a fork-controlled checkout, while a lost successful PR-create response can produce a second workspace and run the automation on the wrong branch.
Ambiguous failures switch workspace targets
If the host successfully creates the PR workspace but its relay response is lost or exceeds the client timeout, this broad catch retries with a different fresh-branch target. That leaves the PR workspace behind, creates another workspace, and runs the automation against the fresh branch instead of the pull request.
Fix is to require a positive "not a fork" instead of refusing only an explicit one, since absence of the field is not evidence of absence of a fork:
if (payload?.pull_request?.head?.repo?.fork !== false) return null;That drops the issue branch entirely, because an issue comment can never prove the PR is safe. Consequence: a comment_added trigger now gets a fresh branch rather than the PR. pr_review_comment and every pull_request.* event carry the head repository and are unaffected, so the two new triggers this PR is about still check out the PR.
Verified against recorded production deliveries
Read-only query over automation_events (newest 40 rows of the two event types). Both events are already arriving in volume — every row below was recorded today, before this PR existed.
Every delivery names exactly one recipient. No row came back with the person field empty: it is always assignee, requested_reviewer, or requested_team. The matcher reads exactly those. One delivery per person — confirmed, not inferred. I had reasoned this from the singular field shape. The data shows it directly: a multi-person request fans out into one delivery each, at the same instant on the same PR. So "review requested from Me" fires on your own delivery and is unaffected by how many other people were added alongside you.
One finding worth knowing: team requests are about half of all review requests
In this sample, roughly half the review_requested rows named a requested_team rather than a person — team:Engineering, team:Platform, team:backend, team:codeowners-fiddler-default, and so on. That is CODEOWNERS doing the requesting.
This PR keeps those silent, which I still think is right: the payload names the team and no members, so firing for "Me" would mean firing for everyone on that team. But it does mean "review requested from Me" will not fire when you are asked via your team, which is a meaningful share of real review requests.
Making that case work needs team-membership resolution through the GitHub API, plus probably a team-shaped scope on the chip rather than a people one. Worth a follow-up ticket rather than stretching this PR — happy to file one.
Individual review requests (requested_reviewer) and all assignments are unaffected and work as described.
Original source - Sep 4, 2026
- Date parsed from source:Sep 4, 2026
- First seen by Releasebot:Sep 8, 2026
fix(desktop): place your worktrees from online remote hosts in the sidebar - #7120
Superset fixes remote worktree and session sidebar placement so items created on another machine now appear automatically when their host is online. It also adds creator tracking via a new x-superset-user-id header and tombstones removed projects to prevent them from reappearing.
Fixes #7100: a worktree or session you created on another machine now gets a sidebar row automatically when its host is online, instead of staying hidden until clicked in Workspaces. Hosts now record the creating user via a new
x-superset-user-idheader, and removing a project now tombstones row-less worktrees so a removed project can't reappear.Bug Fixes
- A remote worktree or session is placed only when its host is online, has answered this session, and you are the creator.
- Teammates' worktrees on shared hosts are not placed; null creators (older hosts) stay opt-in via Pin.
- The local host is always placed regardless of creator, and remote main workspaces are still never auto-included.
- Both relays stamp the creator from the verified JWT and discard any client-supplied id; sign-out clears the stamped user.
- Removal tombstones only the worktrees placement could bring back, so teammates' work on a shared host doesn't pile up rows.
Migration
- Remote auto-placement requires the remote host on this version to stamp creators; older hosts keep today's behavior.
- Both relays must deploy before or with hosts, since an old relay just sends no user header.
- No database migration: the
createdByUserIdcolumn already existed.
Summary
- A worktree or session created on another machine now appears in the sidebar automatically when its host is online.
- Hosts learn who is calling via a new header stamped by the relay from the verified JWT or local callers.
- "Remove project" now tombstones row-less worktrees on every host the reconciler could place from, preventing removed projects from reappearing.
Why / Context
- Sidebar rows are per-device records joined to host data.
- Previously, only local worktrees were placed; remote ones created via CLI or automation were filtered out.
- Clicking a workspace calls ensureWorkspaceInSidebar with no host check, which explains previous behavior.
- Dropping the hostId === machineId filter without creator info would auto-pin every teammate's worktree, which is undesirable.
How It Works
- selectWorktreesToPlace places a remote worktree/session only when the host is online, has answered, and the creator matches the signed-in user.
- Creator identity is propagated from desktop, CLI, and relays via verified JWT headers.
- The local host is always placed; remote main workspaces are never auto-included.
Manual QA Checklist
- Online host whose relay fetch fails: snapshot rows not placed.
- Host answers with a worktree created by me: row appears with remote icon, no click needed.
- Same host, worktree created by a teammate: no row.
- Offline host handed retained rows: no row.
- Hidden remote row, host answers again: not re-placed.
Known Limitations
- Workspace deleted on another device leaves an orphan local row (pre-existing).
- API-key CLI callers to a local host send no user id.
- Reconciler waits for every host's workspace.list query to settle; a flaky host can delay auto-placement.
Compatibility
- Remote auto-placement needs the remote host-service on this version to stamp creators.
- Both relays must deploy before or with hosts; old relays send no header.
Testing
- Typechecks and tests added covering remote workspace placement, sidebar behavior, authentication headers, and JWT handling.
Design Decisions
- Creator, not host owner role, determines placement.
- Null creator means not placed, a safe default.
- Persisted state is bounded to one local row per worktree created by the user on an online host.
This update improves sidebar visibility and management of remote worktrees and sessions by securely tracking creators and automatically placing their worktrees when hosts are online.
Original source - Sep 4, 2026
- Date parsed from source:Sep 4, 2026
- First seen by Releasebot:Sep 8, 2026
feat(trpc,cli,mcp): upload page documents straight to storage; cap pages at 16 MB
Superset adds staged HTML document uploads to page publishing, raising the page limit to 16 MB with server-side verification, upload reuse prevention, and a shared upload flow for assets and documents across CLI and MCP tools.
Why
The page HTML travelled base64-encoded inside the page.publish tRPC body. The API runs on Vercel, whose request body is capped at 4.5 MB, and base64 inflation made 3 MB the practical ceiling for a page. A real page with a dozen inlined screenshots hit File too large. Maximum is 3MB today.
Page assets already avoid the body: page.assets.upload presigns a PUT straight to R2 and publish verifies what landed. The document now takes the same path, and the page cap goes to 16 MB.
What changes
One upload, two kinds of file (packages/trpc)
page.assets.upload grows a kind discriminator instead of gaining a sibling procedure. An asset stages against a page at the path it holds; a document has no page and no path, so it presigns, records a pending files row, and stops. Both go through one recordUpload, so there is a single presign + pending-row implementation. The document's content-type allowlist and 16 MB ceiling are in the schema, next to the asset's own 100 MB one.
The body path is gone, not kept beside the new one
page.publish takes fileId and nothing else. Deleted: the content/contentType input, validatePublishContent, inlineDocument, the "exactly one of" refinement, and lib/upload-bytes.ts, whose last consumer that was. The dead assets input on publishPageSchema went with them — nothing has read it since assets moved to staging.
Pages are internal today, so a client still on the body path just fails the schema rather than getting a deprecation runway. cli-v1.25.x is the only such client. Its asset uploads keep working untouched: kind is optional and defaults to asset.
Publish
loadUploadedDocument matches a row shaped exactly like a document upload — the caller's own, still pending, HTML, and within MAX_PAGE_BYTES — then HEAD-verifies it, copies it server-side (new copyObject in lib/r2.ts) to the unchanged pages//versions//index.html key inside the version transaction, and consumes the row there guarded on pending. Title/slug defaults, version-conflict retry, TargetPageChanged, and the one-page-per-workspace resolution are the same runPublish as before.
The document and every staged asset now share one verifyUploadedObject, which was duplicated between them.
Clients
- CLI superset pages publish: utils/uploadDocument/ is deleted. uploadAssets and uploadDocument live in one utils/upload module over one PUT function, and reuse is now "the server returned no upload URL" rather than a second flag.
- MCP pages_publish: same procedure, same flow. The upload error names the file. Its description still points at the CLI for documents over ~4 MB, because MCP is on the same host with the same body limit.
- plugins/superset/skills/page/SKILL.md: 3 MB → 16 MB in three places.
Size
Against the previous revision of this PR: -133 lines of non-test code, -515 overall. Against main the feature is still +235 non-test, which is copyObject, the document branch and its schema, the loader, and the two client call sites. I did not get that below zero without deleting comments, and did not try.
Bot findings
- cubic, detached pending HTML asset over 16 MB. Fixed by construction: the loader's where clause requires pending, the caller's own, a PAGE_CONTENT_TYPES content type, and sizeBytes <= MAX_PAGE_BYTES, so no asset row can stand in for a document whatever its size. Covered by a new integration case.
- cubic, MCP upload error omits the filename. Fixed.
- cubic, uploadPageSchema is not strict and its test overclaims. The upload schema is z.strictObject on both branches, and assets/schema.test.ts asserts what it actually tests — a document is refused content, refused a path, refused non-HTML, and refused over the cap.
- coderabbit and cubic, verify the uploaded document's sha256. Skipped deliberately. The version row's hash is never read: nothing in this repo compares it, and pull/versions only display it. The page-assets path has had the same shape since it shipped, so verifying here alone would buy nothing and cost a full read of every document on every publish.
Tests
- assets/schema.test.ts (new): the document and asset branches of the upload schema.
- schema.test.ts: the body shape is refused. The other inline-path cases are gone.
- publish-rules.test.ts: the validatePublishContent and validatePageUpload blocks are gone with the functions.
- publish.integration.ts: every publish now goes through an upload, via the helper. Six document cases: published under the version key and consumed, never uploaded, size mismatch, another user's upload, a staged asset is not a document, non-HTML refused — plus the detached-oversized-asset case above.
- CLI uploadDocument.test.ts is deleted; the helper is the shared one.
- bun run lint:fix, typecheck for trpc / cli / mcp, bun test in trpc (118), cli (145), shared (924), and bun run check:i18n all pass.
- publish.integration.ts against the dev Neon branch: 24 pass, 2 fail — the pre-existing workspace access cases whose helper inserts cloud_workspaces without environment_id, which made NOT NULL. Same two fail before this PR.
Notes
- Deleting lib/upload-bytes.ts orphaned serverError.uploadBytes.fileIsEmpty, so that key and its catalog entries are removed. Regenerated with check:i18n; every locale reports zero missing.
- No schema change.
Summary by CodeRabbit
- New Features
- Page publishing now supports staged HTML document uploads before publishing.
- HTML pages can be up to 16 MB, with automatic size and integrity checks.
- CLI publishing supports larger documents, while the MCP tool documents its approximate 4 MB tool-call limit.
- Uploaded documents are validated and consumed during publishing to prevent reuse.
- Bug Fixes
- Invalid, oversized, mismatched, or unsuccessful uploads are rejected before page creation.
- Documentation
- Updated publishing guidance and troubleshooting information for the 16 MB limit.
- Sep 3, 2026
- Date parsed from source:Sep 3, 2026
- First seen by Releasebot:Sep 8, 2026
feat(shared,host-service): add Claude Fable 5.1 to the model pickers and pricing table - #7099
Superset adds Claude Fable 5.1 to the model pickers and chat catalog, updates usage pricing for Fable 5.1 and Mythos 5.1 cache reads, and corrects Sonnet 5 and GPT-5.6 Sol pricing to reflect the latest vendor rates.
Summary
- Claude Fable 5.1 (claude-fable-5-1) is now selectable in the workspace-create picker for the claude preset (Pinned releases), in the opencode and OMP pickers, and in the Superset chat catalog. The claude fable alias already tracked it.
- The usage pricing table learns Fable 5.1's economics: the same $10/$50 per MTok as Fable 5, but cache reads at $0.25/MTok (0.025x input, where every other model is 0.1x). A per-model cacheReadPerM override carries that; Mythos 5.1 shares it.
- Two rows checked against the vendor pages while re-dating the table were corrected: Sonnet 5 is $2/$10 (the $3/$15 increase scheduled for 2026-09-01 was cancelled) and GPT-5.6 Sol is on $4/$20 promotional pricing through at least 2026-11-21.
Why / Context
The model catalogs in packages/shared/src/agent-models.ts are hand-maintained, so Fable 5.1 was not offered anywhere. Usage cost estimates matched claude-fable-5-1 transcripts to the claude-fable-5 prefix, which is right on tokens but 4x too high on cache reads, and long agentic sessions are dominated by cache reads.
How It Works
- AGENT_MODEL_SUPPORT and SUPERSET_CHAT_MODELS gain the new ids. The desktop picker, host-service's validateAgentModelSelection, and buildAgentModelArgs all derive from the catalog, so nothing else changes.
- ModelRate.cacheReadPerM is an optional absolute $/MTok cache-read price. costUsd and cacheSavingsUsd resolve it through one helper that falls back to inputPerM × CACHE_READ_MULTIPLIER. Only the Fable 5.1 and Mythos 5.1 rows set it.
- Ids were verified before being added: claude-fable-5-1 is in the Claude Code 2.1.257 binary, and anthropic/claude-fable-5-1 is in models.dev (opencode) and in the catalog bundled with OMP 18.1.2.
Manual QA Checklist
- matchModelRate resolves claude-fable-5-1, claude-mythos-5-1, and anthropic/claude-fable-5-1 to the $0.25/MTok cache-read rate, while Fable 5 and Mythos 5 stay at $1/MTok (unit tests)
- Fable 5.1 sits under "Pinned releases" in the claude picker, next to Fable 5 (catalog group pinned by test)
- Sonnet 5 and GPT-5.6 Sol rates re-read from the Anthropic and OpenAI pricing pages on 2026-09-02
- Not exercised in the running desktop app: launching a workspace with each new id. The picker is data-driven and covered by tests, but the live launch path was not run.
Testing
- bun run lint (the only diagnostic is a local, git-excluded .github/hooks/superset-notify.json, which is not in this PR)
- bun run typecheck
- bun test packages/shared/src/agent-models.test.ts packages/host-service/src/trpc/router/usage/history/ (95 tests)
- bun test packages/host-service/src/trpc/router/agents/agents.test.ts apps/desktop/src/renderer/components/AgentModelSelect/groupModelOptions.test.ts
Design Decisions
- Absolute cacheReadPerM rather than a multiplier: Anthropic publishes the cache-read price as $0.25/MTok and longContext is already an absolute override, so the table stays in the vendor's units.
- Explicit claude-mythos-5-1 row: the longest-prefix matcher would otherwise price it off the bare claude-mythos row and report the match as exact.
Known Limitations
- gpt-4.1, gpt-4o, and the Grok rows still use the 0.1x cache-read default although their vendors bill 0.25x to 0.5x. Not changed here.
- The chat catalog entry is inert today: chat.getModels has no in-repo consumer.
- The prefix matcher reports prefix-extended ids (a future claude-fable-5-2, say) as exact matches. A test tying picker ids to pricing keys would surface that; deferred.
Follow-ups
- Add Fable 5.1 to the Copilot and cursor-agent pickers once their ids are confirmed against a logged-in CLI. Both list models server-side and reject unknown ids, so they were left out rather than guessed.
- The Slack integration's model picker never offered Fable and is unchanged.
Summary by cubic
Adds Claude Fable 5.1 to the model pickers and usage pricing, and corrects two outdated pricing rows.
Pricing
- Fable 5.1 and Mythos 5.1 cache reads are $0.25/MTok via a new cacheReadPerM override.
- Sonnet 5 drops to $2/$10 (the scheduled increase was cancelled) and GPT-5.6 Sol to $4/$20.
Model pickers
- Adds claude-fable-5-1 to the claude preset, opencode, OMP, and Superset chat catalog.
- Copilot and cursor-agent pickers are left unchanged; their ids are confirmed server-side.
Summary by CodeRabbit
- New Features
- Added Anthropic Claude Fable 5.1 to supported model catalogs and model selection options.
- Added support for Fable 5.1 and Mythos 5.1 cache-read pricing.
- Pricing Updates
- Updated Sonnet 5 pricing to $2 per million input tokens and $15 per million output tokens.
- Updated GPT-5.6 and GPT-5.6 Sol pricing to $4/$20 per million tokens.
- Added model-specific cache-read pricing, including $0.25 per million tokens for Fable 5.1 and Mythos 5.1.
- Improved cached-token cost and savings calculations.
- Sep 3, 2026
- Date parsed from source:Sep 3, 2026
- First seen by Releasebot:Sep 8, 2026
feat(desktop): leaderboard rank card on Settings → Usage - #7118
Superset adds a collapsible leaderboard card to Settings → Usage, showing opted-in users their 30-day rank, tier badge, neighboring ranks and token gaps, while opted-out users see a teased token total and blurred rank slot with a quick path to join.
Settings → Usage gets a leaderboard card
Opted in: your rank as the headline (#83 + your tier badge + "of 864"), a one-line tokens/handle subtitle, and a league slice showing the row above you, you, and the row below with the token gap to pass.
Not opted in: a tease with your real 30-day token total and a blurred rank slot, "Reveal my rank" opens the existing join dialog.
The card is flat (one border, no nested boxes) and collapsible; the trophy doubles as the fold toggle and swaps to a chevron on hover.
Why / Context
The usage page already scans your last 30 days of transcripts. Showing where that puts you on the public board, or how far you are from the next rank, is the strongest reason to opt in, and the strongest reason to come back. Survey of other boards (Duolingo/Mimo leagues, Alan, Tonal, Fi, viberank, WakaTime) informed the league-slice and hidden-rank patterns.
How It Works
- LeaderboardCard owns the data: useLeaderboardOptIn("30d") for membership (the hook now takes a period and invalidates the ["leaderboard","me"] prefix on join/leave so both surfaces refresh), useHostUsageHistory(hostUrl, 30) reused with the same key as the chart below so the tease costs no extra transcript scan, leaderboard.public.stats for the participant count, and leaderboard.public.standings (limit 3, offset rank−2) for the neighbours.
- CardFrame is the single flat surface shared by both states. Collapsed state persists in leaderboard-card-collapsed-v1 (registered in the persisted-key registry; key removed when expanded).
- RankNeighbors never renders other people's handles or names. Neighbours get a stable, obviously fake factory alias by rank (Anonymous Assembler, Mystery Machinist, …). Your own row is synthesised from membership so a CDN-cached standings slice can never drop "You".
- Only your own tier badge renders, next to the headline rank.
- TierBadge is a desktop copy of the marketing tier names/colours (the desktop can't import the marketing app); a comment says to keep them in step.
- The gear button pre-fills the settings search with "leaderboard" and navigates to Account, so the page filters down to the opt-in switch.
Manual QA Checklist
Verified over CDP against this worktree's dev app (Neon branch, real standings data), with real mouse input:
- Not opted in: tease shows local 30-day tokens, blurred rank, "of N", Reveal opens the dialog with the projected rank
- Join from the card: card flips to the rank view without reload
- Rank view: headline rank + own tier badge, neighbours with aliases and gaps, no real names anywhere
- Card's leaderboard.me and the public 30-day standings agree on rank and tokens at the same instant
- Collapse/expand via the trophy: chevron on hover, key written on collapse and removed on expand, survives navigation
- Gear → Account with search prefilled to "leaderboard", switch visible
- Leave from Account → Usage shows the tease again
- No renderer console errors
Testing
- bun run typecheck (apps/desktop)
- bunx biome check on touched paths
- bun test src/renderer/routes/_authenticated/settings/usage/components/LeaderboardCard src/renderer/lib/persisted-keys (apps/desktop)
- bun test (packages/i18n)
- bun turbo run build --filter=@superset/desktop
Known Limitations
- 32 new Lingui strings are untranslated in the 16 non-English catalogs; the Translate Catalogs workflow fills them on this PR. Until then bun run --cwd packages/i18n check fails on the strict compile.
- Your own tier comes from your standings row, which is CDN-cached, so right after a fresh publish the badge can be briefly absent rather than stale.
- The public profile page ranks by all-time tokens; this card and the board's 30D tab rank within the window, so the two numbers legitimately differ.
Follow-ups
- Percentile framing ("top 9%") once previewRank is no longer rate-limited enough to call eagerly.
- Tier progress ("X to Operator") needs leaderboard.me to return tier/progress.
Summary by cubic
Replaces the opt-in prompt on Settings → Usage with a collapsible leaderboard card. Opted in, it shows your 30-day rank, tier badge, and the rows above and below you with the token gap to pass; opted out, it shows your real 30-day token total with a blurred rank slot, and "Reveal my rank" opens the join dialog.
- Neighbor rows show stable factory aliases by rank, never real handles or names.
- The collapsed state persists in a registered localStorage key.
- The opted-in subtitle dropped the privacy line; reassurance belongs in the prompt and join dialog.
- The tier badge sits directly after the rank headline and can be briefly absent right after a fresh publish because it comes from the CDN-cached standings row.
- The card ranks within the 30-day window; the public profile ranks all-time, so the two numbers can legitimately differ.
- New i18n strings are translated across enabled locales; useLeaderboardOptIn takes a period and refreshes both surfaces on join/leave.
- Fixed a missing NeighborRow type export and updated two card tests that predated the collapsible frame props.
Summary by CodeRabbit
- New Features
- Added a collapsible leaderboard card to the Usage settings page.
- Users can opt in and view their 30-day rank, token count, tier, and neighboring ranks.
- Added anonymous aliases and token-gap details to protect participant identities.
- Added options to open the leaderboard and manage participation.
- The card remembers its collapsed or expanded state between visits.
- Added unranked states and loading previews.
- Localization
- Expanded leaderboard translations across supported locales.
Curated by the Releasebot team
Releasebot is an aggregator of official product update announcements from hundreds of software vendors and thousands of sources.
Our editorial process involves the manual review and audit of release notes procured with the help of automated systems.