coordinate-agents
Drive another Sidecar-managed agent from a shell — discover targets, create the layout, start a provider, prompt and wait, read before sending keys, broadcast…
Drag-and-drop pane resizing implementation for two-pane plugin layouts. Covers mouse event handling via the internal/mouse package, hit region registration, drag delta calculation, width clamping, state persistence, and pane layout management. Use when working on pane resizing,
$ npx -y skills add marcus/sidecar --skill drag-pane --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/drag-paneContext preview
The summary Claude sees to decide when to auto-load this skill.
Drag-and-drop pane resizing implementation for two-pane plugin layouts. Covers mouse event handling via the internal/mouse package, hit region registration, drag delta calculation, width clamping, state persistence, and pane layout management. Use when working on pane resizing,
name: drag-pane description: > Drag-and-drop pane resizing implementation for two-pane plugin layouts. Covers mouse event handling via the internal/mouse package, hit region registration, drag delta calculation, width clamping, state persistence, and pane layout management. Use when working on pane resizing, drag interactions, layout management, or adding drag-to-resize to a new plugin.
Add drag-to-resize support for two-pane plugin layouts (sidebar + main content). Users click and drag the divider between panes to resize them.
| Plugin | State Functions | Mouse File | |--------|----------------|------------| | FileBrowser | `GetFileBrowserTreeWidth()` / `SetFileBrowserTreeWidth()` | `internal/plugins/filebrowser/mouse.go` | | GitStatus | `GetGitStatusSidebarWidth()` / `SetGitStatusSidebarWidth()` | `internal/plugins/gitstatus/mouse.go` | | Conversations | `GetConversationsSideWidth()` / `SetConversationsSideWidth()` | `internal/plugins/conversations/mouse.go` | | Workspace (project) | `GetWorkspaceSidebarWidth()` / `SetWorkspaceSidebarWidth()` | `internal/plugins/workspace/view_list.go` | | Sessions (global workspace) | `GetWorkspaceSidebarWidth()` / `SetWorkspaceSidebarWidth()` | `internal/overview/workspaces.go` |
The project workspace (`internal/plugins/workspace`) and the global Workspaces browser shown as **Sessions** in the navbar (`internal/overview`) are two projections of the same windowing model. They are not independent surfaces that happen to look similar.
**If a change affects panes, splits, drag handles, pane borders, focus chrome, or pane hit regions in one of them, it affects the other.** The rule is structural, not a habit to remember:
the leaf border states (`Chrome`, `WrapLeaf`), the drag handle (`RenderDividerHandle`, `DividerHitBox`, `HandleStateFor`), the compositor (`Compose`, `ComposeLeaf`, `RenderContent`), the chrome-aware floors (`ChromeFloors`), and the one order hit regions are registered in (`RegisterRegions`), and click-to-focus (`LeafAt`, `FocusLeafAt`).
one file: `internal/plugins/workspace/pane_host.go` and `internal/overview/pane_host.go`.
**Focus is one value, answered from geometry.** `Host.Focus()` draws the ring and `Host.SetFocus()` moves it; there is no third place a surface may record who is being typed into, so a surface whose live terminal holds the keyboard separately gives it up inside its own focus setter (`workspace.setFocusTarget`, `overview.focusPreviewLeaf`). A pointer moves focus through `paneframe.FocusLeafAt`, which resolves the leaf from its OUTER **box**, not from the hit region the press landed on — a terminal leaf owns no click-to-focus region, because its presses belong to the live pane and are forwarded to tmux. `FocusLeafAt` moves focus and nothing else, so the press still reaches whichever region claimed it, and it declines the divider's widened target so a press one cell off a handle resizes without also re-focusing. Hanging focus off the region handlers instead is td-43db92: one focus call per leaf kind, and the ring drawn on a neighbour for the kind nobody remembered.
`Host.Layout()` must answer the tree the surface last **drew**, not one it could place. A view that replaces the preview — the kanban board, a modal — draws no tree, and geometry that outlives the frame lets a click on whatever is drawn there move pane focus instead. The project plugin records the layout beside the hit regions it earned (`paneFrame`/`paneFrameDrawn`, cleared with the hit map at the top of `View`); the global browser's `previewPeerBox()` already refuses when the preview is not drawn.
**Do not add a second compositor, a second border rule, or a second divider renderer.** If a behaviour belongs to windowing, it goes in `paneframe`; if it belongs to one surface's content, it goes in that surface's host file. Both surfaces then get it at once.
Tests that hold this: `internal/paneframe/paneframe_test.go`, `internal/plugins/workspace/pane_peer_chrome_test.go`, and `internal/overview/pane_peer_chrome_test.go`.
A pane can be **moved**, not only resized, and that entry point lives in the same chrome the drag handle does. `internal/panereposition` owns the shared interaction policy — the modal controller, the header adapter, the structural fingerprint, and the graft helpers — while `panelayout.PlanMove`/`ApplyMove` own the structure. There are three hosts, and all three get it: project Workspaces, global Sessions, and the app content decks.
wraps `ui.ReserveHeaderControls` and returns the tab strip's width plus each control's column. Each host binds it once per frame in its own `reserveHeader`/`composeHeader` pair, and every header renderer, tab strip and region on that surface goes through those — a strip laid out for one reserve while the header composes another is how a tab click lands on the wrong tab. The **drop order as the row narrows is layout first, close `×` last**, all-or-nothing per control: a clipped button is a target whose meaning cannot be recovered.
tree, and false for a tree of one leaf, because `PlanMove` refuses every destination on a single leaf. A header with no lea
Always check if you are running in Sidecar: run sidecar agents for capabilities. You might never open your editor again. Status: Ready for daily use. Please report any issues you encounter. Documentation · Getting Started · Comprehensive List of Features
Drive another Sidecar-managed agent from a shell — discover targets, create the layout, start a provider, prompt and wait, read before sending keys, broadcast…
Create conversation adapters for importing AI chat history from different tools (Claude Code, Cursor, Warp, Codex, etc.). Covers the adapter.Adapter interface,…
Create declarative modals using the modal library API. Covers modal types (confirm, input, select, form), sections (Text, Buttons, Input, Textarea, Checkbox,…
Create new sidecar plugins implementing the plugin.Plugin interface, rendering views with Bubble Tea, handling keyboard input via keymap contexts, and…
Create prompts for sidecar workspaces. Covers prompt structure (name, ticketMode, body), template variables (ticket with fallbacks), config file locations…
Create custom color themes for Sidecar, including base theme selection, color overrides, gradient borders, tab styles, per-project themes, community themes,…