---
title: Customize the session menu (reorder + hide items)
---

# Customize the session menu (reorder + hide items)

Let each person reorder the items in a session's **⋯ (more actions) menu** and hide the ones they never use — so the menu shows what _they_ reach for, in _their_ order. It is a per-person preference that applies to every session, and it is currently behind an in-development flag (off by default, hidden until shipped).

## What the user sees

Every session has a **⋯ button** in its header that opens the session menu — Snooze, Pause, Send Later, Copy app link, Pop Out, Move to, Exports, and many more. That list is long, so it is grouped into **labeled sections** with a **filter box** above them: type a few letters and only matching rows stay, and a section whose rows all filter out disappears header and all.

**Three sections start open** — Session, Organize and Share — and **three start collapsed**: Setup, View and This session. A collapsed section still names what it holds and opens in one click, so nothing is hidden from you; it is just out of your way. This grouping **ships for everyone** — it is not behind the customization flag.

With the customization feature on, additionally:

- The menu renders in **the order the user chose**, with the items they hid removed.
- The bottom entry reads **"Customize menu…"** and jumps to the customizer. With the feature off it reads **"Customize session bar…"** instead. Either way it can never be hidden, so you can never strand yourself.

## Where you customize it

**Settings → Sessions → "Session menu"** card:

- **Reorder** — drag a row by its grip handle, or use the up/down arrows (the arrows are the keyboard- and phone-friendly path).
- **Show/hide** — the switch on each row; off hides that item from the menu. "Customize menu…" has no switch — it is always shown so you can never strand yourself.
- **Reset to default** — restores the built-in order and clears the hidden set (nothing is hidden by default any more; compactness comes from the collapsed sections).

The customizer only lists items that can actually appear for you: developer-only rows (CPU Burst) show only in dev builds, desktop-only rows (Pop Out) only on desktop, the mobile Scroll Log only on mobile, and feature-gated rows (Trajectory, Attach to task, Hand off, Inbox Pilot) only when their own feature is on.

## How it behaves

- **Per-person, every session** — the order and hidden set are your own settings; they are not per-session and not shared.
- **Persists** across restarts.
- **Feature-gated — but only the CUSTOMIZING half.** The labeled, collapsible sections and the filter box render for everyone. While `session-menu-customization` is off (the default today) the menu simply ignores any saved order or hidden set, so someone who has never opened the customizer can never have a stored set applied to them.
- **Mobile** — the same order/hidden choices apply to the mobile ⋯ menu; you set them from Settings (there is no right-click on a phone).
- **Pinning to the session bar is separate** — pinning a command to the header bar (the existing "Session bar" feature) still moves it out of the menu; hiding is a separate switch. The two compose: a pinned command is on the bar, a hidden one is gone from the menu, and both can be true.

### Mark as Read / Mark as Unread

One entry in the **This session** section is not a setting at all — it is how you tell a session
*"I have seen this, stop flagging it at me"* without doing anything to the work.

When a session is waiting on you it carries an attention badge. Reading the session does not clear
it — the badge stays until the work is actually dealt with, which is deliberate, because "I looked"
and "I handled it" are different things. **Mark as Read** is the middle ground: it acknowledges the
badge so the row stops pulling your eye, and leaves the session exactly as it was. Marking it does
not reply, resume, archive or change the session's status, and it does not affect anything the agent
is doing.

The menu shows one of the two, never both, depending on where the session stands:

- **Mark as Read** — shown while the badge is still unacknowledged; choosing it acknowledges it.
- **Mark as Unread** — shown once it has been acknowledged; choosing it puts the badge back, so the
  session starts flagging at you again.

Either way a confirmation appears with an **undo**, so a mis-click is one keypress from reverted.
The acknowledgement is remembered per session and survives a restart — and it is yours alone, not
something a teammate or another machine sees.

This is **not** "mark the messages read": a session has no unread-message count. The only thing this
touches is the attention badge, which is why it lives in the session menu next to the other
attention controls rather than anywhere in the transcript.

## Under the hood (for agents)

- **Mark as read / unread** — `SESSION_MARK_BADGE_READ` sets the session's `badgeReadAt` to now;
  unmarking writes it back to `null`. The menu shows **Mark as Unread** when
  `badgeReadAt >= needsYouAt` (the badge was acknowledged after it last became due) and **Mark as
  Read** otherwise. Undo labels are "Marked as read" / "Marked as unread". See
  `src/renderer/src/features/dashboard/SessionContextMenu.tsx` and
  `src/renderer/src/stores/session-store.ts` (`markBadgeRead` / `unmarkBadgeRead`).

- **Ordering/hiding logic** — [`session-menu-order.ts`](../../src/renderer/src/features/sessions/session-menu-order.ts): a React-free module owning `SESSION_MENU_ENTRY_IDS` (the default order), `DEFAULT_HIDDEN_ENTRY_IDS` (now empty, still kept in lock-step with `DEFAULT_SETTINGS.sessionMenuHidden`), `SESSION_MENU_ENTRY_GROUP` / `SESSION_MENU_GROUPS` / `groupSessionMenuEntries` (the sections and which start collapsed), `NON_HIDEABLE_ENTRY_IDS` (just `customize-menu`), and the pure `orderSessionMenuEntries` / `isSessionMenuEntryHidden` / `moveSessionMenuEntry` / `reorderSessionMenuEntry` / `toggleSessionMenuEntryHidden` helpers. Unknown/stale ids are ignored everywhere.
- **Entry metadata** — [`session-menu-entry-meta.ts`](../../src/renderer/src/features/sessions/session-menu-entry-meta.ts): a `Record<SessionMenuEntryId, {label, icon, customizable?}>` the customizer reads for each row's label + icon + "can it appear for this user" predicate.
- **The menu** — [`SessionOverflowMenu.tsx`](../../src/renderer/src/features/sessions/SessionOverflowMenu.tsx) renders a feature-gated **dual layout**: flag off → today's exact grouped JSX; flag on → the flat ordered/hidden list built from a per-entry `entryNodes` map.
- **The customizer** — [`SessionMenuCustomizer.tsx`](../../src/renderer/src/features/settings/sections/session/SessionMenuCustomizer.tsx) in the Session settings section.
- **Settings** — `sessionMenuOrder: string[]` + `sessionMenuHidden: string[]` (reachable via `GET`/`PATCH /settings`), plus the `sessionMenuCustomizationEnabled` gate. Empty order ⇒ the default registry order.
- **Contract** — [session-bar-commands-contract.md](../../.claude/memory/contracts/session-bar-commands-contract.md) (the menu-customization invariants, alongside the session-bar pinning ones).

**Not yet built:** an inline right-click "hide / move" menu on the rows themselves — a planned fast-follow; today you customize from Settings.
