Skip to content

Sidebar: show every profile at once - #83052

Merged
OutThisLife merged 6 commits into
mainfrom
bb/sidebar-all-profiles
Aug 10, 2026
Merged

Sidebar: show every profile at once#83052
OutThisLife merged 6 commits into
mainfrom
bb/sidebar-all-profiles

Conversation

@OutThisLife

@OutThisLife OutThisLife commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

The desktop sidebar could already flip to all-profiles, but it only listed a flat page of chats: the project tree belonged to the active profile, grouping and filtering had no notion of an owner, and each profile lane paged itself. That makes the multi-agent workflow this exists for — several profiles working at once, the way Discord threads do — unreadable. This makes the owning profile a first-class axis of the sidebar, and fixes a few things that scope touched on the way.

What's new

A cross-profile project tree. projects.tree over JSON-RPC answers for the backend's own profile, so it could only ever describe a slice of this view. GET /api/profiles/projects/tree runs the same authoritative builder once per profile against that profile's state.db and merges the results by folder — one checkout is one group, however many profiles work in it, and __no_project__ is one Home rather than one per profile. Discovery stays off: an empty repo is the same repo in every profile, and the scan is the one part of the builder that writes.

Grouping and filtering by profile. Profile is a grouping option like date or project (picking it turns the scope on, since that's the ask), and profiles are a filter alongside status, project and PR. The all-profiles scope keeps its own persisted grouping, so flipping the rail doesn't reset how you read a single profile.

Profile groups look like project groups, because they do the same job: the shared SidebarGroupRow, the profile glyph the rest of the app uses, the same three-session preview, clicking the label scopes to that profile the way clicking a project enters it. New/import profile moved into the same menu.

Tokens and spend on group headers, for the Show options that count something. Summed in SQL over the whole project or profile rather than over the loaded page — a total that shrank as you scrolled would be worse than no total. The figures sit in the slot the kebab and the "+" hover over, the trade the session row already makes.

Scrollbars fade out until you're in the list. The sidebar stacks several scrollers, so it drew several thumbs at once on a list nobody was touching. They share the app's existing scrollbar colors and only change the thumb's color, so the reserved gutter still keeps rows from shifting sideways.

Fixes

Sorting did nothing inside groups. The sort key was applied where the flat list is assembled, so picking "cost" while grouped by project or profile left every lane in backend order. Ranking now lives in a store above any one view, and each surface applies it to the rows it owns — including before a group trims itself to a preview, so the rows it hides are the ones the sort ranked last.

Cron and messaging ignored the sidebar's scope. The batched sidebar endpoint returned them cross-profile unconditionally, which is why a concrete profile showed another profile's Telegram threads and cronjobs. Every slice answers to the one scope now, and all is how the caller asks for everything. Closes #65710, #42651, #70629.

A repo scan could clobber the cross-profile tree, because it refreshed the tree for its own gateway rather than through the active scope.

Row metadata had two homes. The PR and profile chips rendered in the row body while tokens, cost and age sat in the actions slot, so the chips were never flush right and never handed their space to the kebab — a row showing only a PR left a hole where the age would have been, and the hover-only age reserved 48px that re-truncated the title under the cursor. Everything the Show menu switches on now shares one right-aligned slot, the kebab covers the end of it, and hovering the PR chip holds the kebab back so the link is still clickable.

Upgrading

All-profiles is off by default and everything above is behind it, with one deliberate exception: the sidebar now ships with the timestamp pinned on each row instead of revealed on hover. Both scopes ship grouped by date, defaults live in one const, and "Reset to defaults" restores exactly that — in both scopes, so flipping the rail can't hand back the grouping you just cleared.

Test plan

  • apps/desktop: full vitest suite (4647 passing), including new coverage for the ranking store, rankSessions, preview ranking before the trim, and the shipped defaults + reset in both scopes.
  • scripts/run_tests.sh tests/hermes_cli/test_profiles_sidebar_scope.py tests/hermes_cli/test_profiles.py tests/tui_gateway — 470 passing.
  • Seeded several colored profiles with sessions and drove the sidebar: group by profile and by project, filter by profile, sort by cost/tokens inside groups, enter a project, reset to defaults.

…age totals

`projects.tree` answers for the backend's own profile, so the grouped
sidebar had nothing to draw once the user asked to see every profile.
Run the same authoritative builder once per profile against that
profile's state.db and merge the results by folder, so one checkout is
one group no matter how many profiles work in it, and the owning profile
rides on each session row where the badge and filter can read it.

Group totals are summed in SQL rather than over the loaded page — a
number that shrank as you scrolled would be worse than no number.

Scope the batched sidebar slices while we're here: cron and messaging
came back cross-profile unconditionally, which is why a concrete profile
showed another profile's Telegram threads and cronjobs.

Closes #65710
Closes #42651
Closes #70629
The sort key was applied where the flat recents list is assembled, so it
did nothing at all once rows moved into groups: picking "cost" while
grouped by project or profile left every lane in the order the backend
sent it. Rank in a store instead, above any one view, so a grouped
surface can order the rows it owns by the same key.
All-profiles mode listed a flat page of chats and stopped there: the
project tree was the active profile's, grouping and filtering had no
notion of an owner, and each profile lane paged itself against a
separate endpoint. Multi-agent workflows live across profiles, so the
sidebar now treats the owner as a first-class axis.

Group by profile (the default in this scope, with its own persisted
choice so flipping the rail doesn't reset how you read one profile),
filter by profile, and start or import one from the same menu. Profile
groups take the project row's shape rather than a hand-rolled header,
preview the same three sessions a project does, and carry their whole
tokens-and-spend total in the slot the kebab hovers over.

Grouped lanes now rank by the active sort key, before they trim
themselves, so the rows a group hides are the ones the sort ranked last.

Defaults live in one const: the sidebar ships grouped by date, sorted by
recency, with the timestamp pinned — and "Reset to defaults" puts back
exactly that.
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

running on 7e1f4f6 — fix(desktop): ship the sidebar grouped by date in every scop

waiting for jobs to start…

…list

A thumb parked on a list you aren't touching is chrome, not information,
and the sidebar stacks several scrollers so it draws several of them at
once. Fade them in on hover instead, sharing the existing scrollbar
colors and the webkit/Firefox split rather than styling a second kind of
bar. Only the thumb's color changes, so the reserved gutter still keeps
rows from shifting sideways.
@OutThisLife
OutThisLife enabled auto-merge August 10, 2026 08:24
@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) comp/cli CLI entry point, hermes_cli/, setup wizard comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/profiles Multi-profile isolation, HERMES_HOME scoping P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 10, 2026
@OutThisLife
OutThisLife disabled auto-merge August 10, 2026 08:31
The PR and profile chips rendered in the row body, left of the kebab's own
column: they never sat flush right and never handed their space to the kebab
on hover, so a row showing only a PR left a hole where the age would have been.
Both now join the tokens/cost/age figures in the actions slot, and the kebab
covers the end of it — losing whichever item reads last, not the whole slot.
The all-profiles scope defaulted to grouping by profile, so "Reset to defaults"
handed back a grouping the user never picked. Both scopes now ship by date, and
a reset clears the scope you are not looking at too — otherwise flipping the
rail restored the customization the reset was supposed to undo.

Hovering a row's PR chip also holds the kebab back now: the chip is a link, and
the button that covers the end of the trailing slot was taking the click.
@OutThisLife
OutThisLife force-pushed the bb/sidebar-all-profiles branch from 675de58 to 7e1f4f6 Compare August 10, 2026 08:50
@OutThisLife
OutThisLife enabled auto-merge August 10, 2026 08:54
@OutThisLife
OutThisLife merged commit b278dcb into main Aug 10, 2026
55 checks passed
@OutThisLife
OutThisLife deleted the bb/sidebar-all-profiles branch August 10, 2026 08:57
33hodl pushed a commit to 33hodl/hermes-agent that referenced this pull request Aug 12, 2026
…l-profiles

Sidebar: show every profile at once
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Desktop app shows Telegram sessions from ALL profiles in sidebar, ignoring active profile scope

2 participants