Coding Agent Session Finder
code-yeongyu/oh-my-openagent
Finds, reads and reconstructs past coding-agent sessions across Codex, Claude, OpenCode, Senpi and many other local agent logs.
Drag-and-drop pane resizing implementation for two-pane plugin layouts.
$ npx skills add marcus/sidecar --skill drag-pane -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install marcus/sidecar drag-pane --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/drag-pane .claude/skills/drag-pane && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .claude/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-paneType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add marcus/sidecar --skill drag-pane -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install marcus/sidecar drag-pane --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/drag-pane .agents/skills/drag-pane && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .agents/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add marcus/sidecar --skill drag-pane -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install marcus/sidecar drag-pane --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/drag-pane .cursor/skills/drag-pane && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .cursor/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/marcus/sidecar.git --path .claude/skills/drag-pane--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add marcus/sidecar --skill drag-pane -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install marcus/sidecar drag-pane --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/drag-pane .gemini/skills/drag-pane && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .gemini/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install marcus/sidecar drag-paneInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add marcus/sidecar --skill drag-pane -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/drag-pane .github/skills/drag-pane && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .github/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add marcus/sidecar --skill drag-pane -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install marcus/sidecar drag-pane --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marcus/sidecar.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/drag-pane .opencode/skills/drag-pane && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "drag-pane" agent skill from https://github.com/marcus/sidecar/tree/main/.claude/skills/drag-pane into .opencode/skills/drag-pane/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "drag-pane", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
drag-paneDrag-and-drop pane resizing implementation for two-pane plugin layouts.
Drag Pane is an agent skill from marcus/sidecar. 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.
Its SKILL.md is about 3.9k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Agent Workflows, covering Agent memory. The repository describes itself as: Use sidecar next to CLI agents for diffs, file trees, conversation history, and task management with td. The licence is MIT.
8 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 3792a4e. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are go).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Drag Pane loads about 3.9k tokens when it runs. Until then it costs about 92 tokens; SKILL.md has 1,254 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from marcus/sidecar at commit 3792a4e, republished under its MIT licence (© marcus). 1,254 words, ~3,888 tokens.
.claude/skills/drag-pane/SKILL.md (or your agent's skills folder).Add drag-to-resize support for two-pane plugin layouts (sidebar + main content). Users click and drag the divider between panes to resize them.
internal/state/state.go (each plugin has its own getter/setter)internal/mouse package| 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:
internal/panelayout owns pane-tree structure and geometry.internal/paneframe owns presentation: chrome geometry (Inset, Geometry),
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).paneframe.Host and paneframe.RegionSink in exactly
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.
panereposition.ReserveMovableHeader(width, movable, hasClose)
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.movable comes from the tree (panereposition.Movable): false with no
tree, and false for a tree of one leaf, because PlanMove refuses every
destination on a single leaf. A header with no leaf also used to compare hover
against leaf 0, which every un-hovered header matches, and painted a
permanently hovered button.paneframe.RegionSink.Layout(node, hit) is registered after
Title and before Close — one rung earlier than the close button, for the
reason RegisterRegions already documents. Regions are tested in reverse
order, so Close keeps the cell it occupies and Layout still outranks the
title strip beneath it. Each host binds it in its own pane_host.go beside
the close region, with the same hover tracking.⊞ and the M key open the same
panereposition.Controller; the controller edits a clone and commits
atomically, so no host mutates a live tree from a mouse handler. sidecar layout move is the third caller of the same planner.A zoomed leaf is drawn through the shared compose/register path, so the visible
⊞ and its hit region come from the same placement — the regression that made a
zoomed Primary's button unclickable on one surface and not the other.
import "github.com/marcus/sidecar/internal/mouse"
type Plugin struct {
// ... other fields
mouseHandler *mouse.Handler
sidebarWidth int // Current sidebar width (persisted)
}
func New() *Plugin {
return &Plugin{
mouseHandler: mouse.NewHandler(),
}
}const (
regionSidebar = "sidebar"
regionMainPane = "main-pane"
regionPaneDivider = "pane-divider"
dividerWidth = 1 // Visual divider width
)Important: Do NOT load width in Init() - plugin dimensions (p.width) are not available yet. Initialize lazily on first render:
func (p *Plugin) renderTwoPane() string {
p.mouseHandler.HitMap.Clear() // CRITICAL: clear every render
if p.sidebarWidth == 0 {
p.sidebarWidth = state.GetYourPluginSidebarWidth()
if p.sidebarWidth == 0 {
available := p.width - dividerWidth
p.sidebarWidth = available * 30 / 100 // Default 30%
}
}
// ... rest of render
}func (p *Plugin) Update(msg tea.Msg) (plugin.Plugin, tea.Cmd) {
switch msg := msg.(type) {
case tea.MouseMsg:
return p.handleMouse(msg)
}
}func (p *Plugin) handleMouse(msg tea.MouseMsg) (*Plugin, tea.Cmd) {
action := p.mouseHandler.HandleMouse(msg)
switch action.Type {
case mouse.ActionClick:
return p.handleMouseClick(action)
case mouse.ActionDrag:
return p.handleMouseDrag(action)
case mouse.ActionDragEnd:
return p.handleMouseDragEnd()
}
return p, nil
}
func (p *Plugin) handleMouseClick(action mouse.MouseAction) (*Plugin, tea.Cmd) {
if action.Region == nil {
return p, nil
}
switch action.Region.ID {
case regionSidebar:
p.activePane = PaneSidebar
case regionMainPane:
p.activePane = PaneMain
case regionPaneDivider:
p.mouseHandler.StartDrag(action.X, action.Y, regionPaneDivider, p.sidebarWidth)
}
return p, nil
}
func (p *Plugin) handleMouseDrag(action mouse.MouseAction) (*Plugin, tea.Cmd) {
if p.mouseHandler.DragRegion() != regionPaneDivider {
return p, nil
}
startValue := p.mouseHandler.DragStartValue()
newWidth := startValue + action.DragDX
// Clamp to bounds
// NOTE: Offset varies by plugin (border styling differences):
// GitStatus: -5, FileBrowser: -6, Conversations: -5, Workspace: just dividerWidth
available := p.width - 5 - dividerWidth
minWidth := 25
maxWidth := available - 40
if newWidth < minWidth {
newWidth = minWidth
} else if newWidth > maxWidth {
newWidth = maxWidth
}
p.sidebarWidth = newWidth
return p, nil
}
func (p *Plugin) handleMouseDragEnd() (*Plugin, tea.Cmd) {
_ = state.SetYourPluginSidebarWidth(p.sidebarWidth)
return p, nil
}This is where most bugs occur. Follow this pattern exactly:
func (p *Plugin) renderTwoPane() string {
p.mouseHandler.HitMap.Clear() // CRITICAL: clear every render
available := p.width - 5 - dividerWidth
sidebarWidth := p.sidebarWidth
if sidebarWidth == 0 {
sidebarWidth = available * 30 / 100
}
if sidebarWidth < 25 {
sidebarWidth = 25
}
if sidebarWidth > available-40 {
sidebarWidth = available - 40
}
mainWidth := available - sidebarWidth
p.sidebarWidth = sidebarWidth
// ... render panes and divider ...
// CRITICAL: Register in priority order (last = highest priority)
p.mouseHandler.HitMap.AddRect(regionSidebar, 0, 0, sidebarWidth, p.height, nil)
mainX := sidebarWidth + dividerWidth
p.mouseHandler.HitMap.AddRect(regionMainPane, mainX, 0, mainWidth, p.height, nil)
// Divider LAST = highest priority
dividerX := sidebarWidth
dividerHitWidth := 3 // Wider than visual for easier clicking
p.mouseHandler.HitMap.AddRect(regionPaneDivider, dividerX, 0, dividerHitWidth, p.height, nil)
return content
}Never hand-roll a divider. Use the shared handle so hover and drag colouring, the one-cell inset at each end, and the theme blend are the same everywhere:
divider := ui.RenderHandle(paneHeight, true, ui.HandleStateFrom(p.hoverDivider, dragging))Inside a pane tree, go through the frame instead, which picks the axis and the per-split state for you:
handle := paneframe.RenderDividerHandle(divider, host.HandleState(divider.SplitID))
hit := paneframe.DividerHitBox(divider)Add plugin-specific functions to internal/state/state.go:
// In State struct
YourPluginSidebarWidth int `json:"yourPluginSidebarWidth,omitempty"`
// Getter
func GetYourPluginSidebarWidth() int {
mu.RLock()
defer mu.RUnlock()
if current == nil { return 0 }
return current.YourPluginSidebarWidth
}
// Setter
func SetYourPluginSidebarWidth(width int) error {
mu.Lock()
if current == nil { current = &State{} }
current.YourPluginSidebarWidth = width
mu.Unlock()
return Save()
}WRONG:
func (p *Plugin) View(width, height int) string {
p.sidebarWidth = width * 30 / 100 // BUG: Overwrites drag changes every render!
}CORRECT: Width is only set when sidebarWidth == 0. All other code paths must not unconditionally overwrite it.
Divider X position = sidebarWidth, NOT sidebarWidth + borderWidth.
When lipgloss renders Width(sidebarWidth), the pane occupies columns 0 to sidebarWidth-1. The divider starts at column sidebarWidth.
HitMap.Test() checks regions in reverse order - last added = checked first.
The divider region MUST be registered LAST so it takes priority over overlapping pane regions.
// CORRECT ORDER:
p.mouseHandler.HitMap.AddRect(regionSidebar, ...) // Lowest priority
p.mouseHandler.HitMap.AddRect(regionMainPane, ...) // Medium priority
p.mouseHandler.HitMap.AddRect(regionPaneDivider, ...) // HIGHEST priority (last)Use dividerHitWidth := 3 (wider than the visual 1-character divider) to make
clicking easier. Inside a pane tree, call paneframe.DividerHitBox rather than
widening by hand: a row divider must widen only upward, or it masks the header
row — tabs and close button — of the leaf stacked below it.
Use p.height for hit region height, not paneHeight or paneHeight + 2.
For plugins with many hit regions, use a dirty flag to avoid rebuilding every render:
type Plugin struct {
hitRegionsDirty bool
prevWidth int
prevHeight int
prevScrollOff int
}
func (p *Plugin) renderTwoPane() string {
if p.width != p.prevWidth || p.height != p.prevHeight {
p.hitRegionsDirty = true
p.prevWidth = p.width
p.prevHeight = p.height
}
if p.scrollOffset != p.prevScrollOff {
p.hitRegionsDirty = true
p.prevScrollOff = p.scrollOffset
}
// ... render content ...
if p.hitRegionsDirty {
p.mouseHandler.HitMap.Clear()
// Register all hit regions...
p.hitRegionsDirty = false
}
return content
}Also mark hitRegionsDirty = true when:
See internal/plugins/conversations/view_layout.go and plugin_input.go for a complete implementation.
If drag is not working, add temporary logging:
func (p *Plugin) handleMouseClick(action mouse.MouseAction) (*Plugin, tea.Cmd) {
log.Printf("CLICK x=%d y=%d region=%v", action.X, action.Y, action.Region)
}Common issues:
handleMouseDrag is being calledsidebarWidth unconditionally© marcus, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/drag-pane of marcus/sidecar.
Open the folder on GitHubat commit 3792a4e
Drag Pane next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Drag Pane this skillmarcus/sidecar | 1.1k | — | ~3.9k | Automated safety check: Pass | MIT | |
| Coding Agent Session Findercode-yeongyu/oh-my-openagent | 70k | 1 repos | ~2.8k | Automated safety check: Pass | Custom licence | |
| Claude-Mem Cloud Syncthedotmack/claude-mem | 98k | 1 repos | ~1k | Automated safety check: Notes | Apache-2.0 | |
| Cognee CLI Memory Commandstopoteretes/cognee | 32k | 1 repos | ~2.2k | Automated safety check: Notes | Apache-2.0 | |
| Neat-Freak Knowledge CloseoutKKKKhazix/khazix-skills | 21k | — | ~1.9k | Automated safety check: Pass | MIT | |
| Claude-Mem Searchthedotmack/claude-mem | 98k | 1 repos | ~511 | Automated safety check: Pass | Apache-2.0 |
code-yeongyu/oh-my-openagent
Finds, reads and reconstructs past coding-agent sessions across Codex, Claude, OpenCode, Senpi and many other local agent logs.
thedotmack/claude-mem
Checks claude-mem cloud sync status and guides you through connecting a cmem.ai Pro account without the sync token ever passing through the chat.
topoteretes/cognee
Drives cognee from the terminal with remember, recall, forget and improve memory commands, dataset and config management and database migrations.
KKKKhazix/khazix-skills
Brings project docs, agent rule files, authorized memory and leftover workspace files back in line with what the code and runtime actually do at the end of a work session.
thedotmack/claude-mem
Searches the user's persistent cross-session memory for timestamped observations synthesized from past agent sessions on cmem.ai.
gastownhall/beads
Tracks multi-session work with dependencies in the bd issue tracker so the agent can find ready tasks and recover its context after conversation compaction.
marcus/sidecar
Create conversation adapters for importing AI chat history from different tools (Claude Code, Cursor, Warp, Codex, etc.).
marcus/sidecar
Create declarative modals using the modal library API. An agent skill from marcus/sidecar.
marcus/sidecar
Create new sidecar plugins implementing the plugin.Plugin interface, rendering views with Bubble Tea, handling keyboard input via keymap contexts, and integrating with the app shell (footer hints…
marcus/sidecar
Project switching implementation in sidecar: project discovery, state management, UI flow, modal rendering, filtering, theme preview, and plugin reinitialization.
marcus/sidecar
Interactive shell/TTY integration with tmux session management, shell command execution, control-mode output capture with polling fallback, native cursor rendering, lazy scrollback, selection, paste…
marcus/sidecar
Writing and maintaining the Sidecar Docusaurus documentation site, including page structure, doc authoring, blog posts, styling, images, and deployment workflow.
Categories
Drag-and-drop pane resizing implementation for two-pane plugin layouts. Drag Pane is an agent skill from marcus/sidecar. Drag-and-drop pane resizing implementation for two-pane plugin layouts.
Drag Pane fits situations like: working on pane resizing; drag interactions; layout management; adding drag-to-resize to a new plugin.
Run `npx skills add marcus/sidecar --skill drag-pane -a claude-code`. Or copy the skill folder (.claude/skills/drag-pane in marcus/sidecar) into .claude/skills/drag-pane in your project. Claude Code loads it when a task matches its description.
Run `npx skills add marcus/sidecar --skill drag-pane -a codex`. Or copy the skill folder (.claude/skills/drag-pane in marcus/sidecar) into .agents/skills/drag-pane in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add marcus/sidecar --skill drag-pane -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/drag-pane, .gemini/skills/drag-pane, .github/skills/drag-pane and .opencode/skills/drag-pane in your project.
SKILL.md names no scripts, command-line tools or credentials: Drag Pane is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Drag Pane is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.9k tokens (SKILL.md is roughly 16k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Drag Pane: Coding Agent Session Finder (code-yeongyu/oh-my-openagent, 70k stars), Claude-Mem Cloud Sync (thedotmack/claude-mem, 98k stars), Cognee CLI Memory Commands (topoteretes/cognee, 32k stars) and Neat-Freak Knowledge Closeout (KKKKhazix/khazix-skills, 21k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
marcus (a GitHub user) maintains it in marcus/sidecar, which has 1,085 GitHub stars. The repository holds 19 skills in this directory. The repository was last updated on October 5, 2026.
Source: marcus/sidecar on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.