You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rail stays at 48px; hovering a project rail icon spawns a floating panel
C. Mobile drawer
<xl viewport, mobileSidebar.opened=true
Full-screen drawer overlay
Internally this is implemented as two persisted booleans (sidebar.opened, mobileSidebar.opened) plus a runtime state.hoverProject plus a createAim mouse-aim debounce plus an arm/disarm/navLeave 300ms grace timer plus a peek sub-state machine, all gated by xl: Tailwind viewport prefixes.
Why this is over-engineered
Three-question audit, user perspective:
1. Can it be cut?
Mode B serves no real user. It is a borrowed VSCode/Slack activity-bar pattern. PawWork's audience is "open-source AI agent for everyone" — non-technical knowledge workers. They either use the sidebar permanently (Mode A, the default) or they want the sidebar gone (and would press the toggle, not learn to hover a rail). The "rail-only with floating reveal" model is an IDE habit that does not map to agent management. ChatGPT, Claude.ai, and Cursor desktop apps all skip this mode.
Mode C serves no real user either. PawWork ships only as an Electron desktop app (packages/web does not exist; packages/console is upstream-only and not shipped). The only way to trigger Mode C is to drag the desktop window narrower than 1280px. On a 13" MBA half-snap that lands near 640px, on 14"+ MBP half-snap near 800px. Nobody actually manages agents in an 800px window — they either widen the window or quit. ChatGPT / Claude.ai / Cursor desktop all decline to ship a separate mobile drawer mode and rely on a window minWidth instead.
Both modes can be cut.
2. Is what remains good enough?
After removing B and C the sidebar collapses to two states:
Docked (default): occupies layout space, main shrinks
Hidden: removed from layout, main fills 100%, summon with mod+\
Same behavior across every viewport. This matches the ChatGPT / Claude.ai model and is straightforward to reason about.
3. Is it surprising in any bad way?
No. A single mod+\ toggle that always does the same thing is less surprising than the current "hover triggers floating panel that disappears if your mouse drifts" mechanic that today's aim + arm/disarm debounce is busy papering over.
Proposed change
Code
Delete:
state.hoverProject plus setHoverProject plus clearHoverProjectSoon plus createAim instance plus the arm / disarm / navLeave 300ms grace timer in packages/app/src/pages/layout.tsx
state.peek / peeked / peekt / peekProject (peek state machine, attached to Mode B)
sidebarHovering and sidebarExpanded derived memos and all 27+ downstream subscribers (collapse to plain sidebar.opened)
mobileSidebar store and its show / hide / toggle / opened API in packages/app/src/context/layout.tsx
The xl:hidden mobile drawer DOM and overlay in packages/app/src/pages/layout.tsx (around lines 2571-2596 in the current snapshot), and the xl:block desktop nav split (merged into a single nav)
The mobile menu icon trigger in packages/app/src/components/titlebar.tsx
The mobile?: boolean prop chain across pages/layout/pawwork-sidebar.tsx, pages/layout/sidebar-items.tsx, and any callers
Mobile-specific overlay and drawer rules in packages/app/src/index.css
Adjust:
Sidebar visibility comes from sidebar.opened only. When false, the sidebar is removed from the layout and main fills 100%. Summon with the existing mod+\ keybind; no floating overlay, no rail.
Raise minWidth from 480 to 768px in packages/desktop-electron/src/main/windows.ts. This guarantees a usable two-column layout for everyone and makes the "no mobile mode" decision honest. 768 keeps half-screen viable on 14"+ MBPs while 800+ would cut all MBP half-snap workflows.
Estimated impact
Roughly −400 to −500 net lines and the removal of one nontrivial state machine. No new dependencies. Stored layout retains a mobileSidebar key from this store; migrateStoredLayout in packages/app/src/context/layout.tsx will strip it on read.
Existing Mode A users keep the same default behavior. Existing Mode B users (if any) lose their preferred mode — acceptable given the audit above, but worth one line in the changelog.
A future "small-window adaptive layout" can always come back as a real responsive design if the data ever justifies it. Right now there is no data justifying it.
Verification plan when the PR opens
Sidebar docked (default) → main shrinks, identical to today's Mode A.
mod+\ once → sidebar hidden, main fills 100%, no rail visible, no floating overlay anywhere.
mod+\ again → sidebar restored to its previous docked width.
Resize Electron window to minWidth (768px) → sidebar still respects user's docked / hidden choice; no mobile drawer DOM rendered at any width.
Search for sidebarHovering, sidebarExpanded, mobileSidebar, hoverProject, peek, createAim across packages/app/src — zero references should remain.
Background
The sidebar currently has three render modes:
xl+viewport,sidebar.opened=truexl+viewport,sidebar.opened=false<xlviewport,mobileSidebar.opened=trueInternally this is implemented as two persisted booleans (
sidebar.opened,mobileSidebar.opened) plus a runtimestate.hoverProjectplus acreateAimmouse-aim debounce plus anarm/disarm/navLeave300ms grace timer plus apeeksub-state machine, all gated byxl:Tailwind viewport prefixes.Why this is over-engineered
Three-question audit, user perspective:
1. Can it be cut?
packages/webdoes not exist;packages/consoleis upstream-only and not shipped). The only way to trigger Mode C is to drag the desktop window narrower than 1280px. On a 13" MBA half-snap that lands near 640px, on 14"+ MBP half-snap near 800px. Nobody actually manages agents in an 800px window — they either widen the window or quit. ChatGPT / Claude.ai / Cursor desktop all decline to ship a separate mobile drawer mode and rely on a windowminWidthinstead.Both modes can be cut.
2. Is what remains good enough?
After removing B and C the sidebar collapses to two states:
mod+\Same behavior across every viewport. This matches the ChatGPT / Claude.ai model and is straightforward to reason about.
3. Is it surprising in any bad way?
No. A single
mod+\toggle that always does the same thing is less surprising than the current "hover triggers floating panel that disappears if your mouse drifts" mechanic that today'saim+arm/disarmdebounce is busy papering over.Proposed change
Code
Delete:
state.hoverProjectplussetHoverProjectplusclearHoverProjectSoonpluscreateAiminstance plus thearm/disarm/navLeave300ms grace timer inpackages/app/src/pages/layout.tsxstate.peek/peeked/peekt/peekProject(peek state machine, attached to Mode B)sidebarHoveringandsidebarExpandedderived memos and all 27+ downstream subscribers (collapse to plainsidebar.opened)mobileSidebarstore and itsshow/hide/toggle/openedAPI inpackages/app/src/context/layout.tsxxl:hiddenmobile drawer DOM and overlay inpackages/app/src/pages/layout.tsx(around lines 2571-2596 in the current snapshot), and thexl:blockdesktop nav split (merged into a single nav)packages/app/src/components/titlebar.tsxmobile?: booleanprop chain acrosspages/layout/pawwork-sidebar.tsx,pages/layout/sidebar-items.tsx, and any callerspackages/app/src/index.cssAdjust:
sidebar.openedonly. Whenfalse, the sidebar is removed from the layout and main fills 100%. Summon with the existingmod+\keybind; no floating overlay, no rail.minWidthfrom 480 to 768px inpackages/desktop-electron/src/main/windows.ts. This guarantees a usable two-column layout for everyone and makes the "no mobile mode" decision honest. 768 keeps half-screen viable on 14"+ MBPs while 800+ would cut all MBP half-snap workflows.Estimated impact
Roughly −400 to −500 net lines and the removal of one nontrivial state machine. No new dependencies. Stored layout retains a
mobileSidebarkey from this store;migrateStoredLayoutinpackages/app/src/context/layout.tsxwill strip it on read.Out of scope
Verification plan when the PR opens
mod+\once → sidebar hidden, main fills 100%, no rail visible, no floating overlay anywhere.mod+\again → sidebar restored to its previous docked width.minWidth(768px) → sidebar still respects user's docked / hidden choice; no mobile drawer DOM rendered at any width.sidebarHovering,sidebarExpanded,mobileSidebar,hoverProject,peek,createAimacrosspackages/app/src— zero references should remain.