Best for
- Use when working on shell integration, tmux features, command execution, or interactive mode.
marcus/sidecar/.claude/skills/shell-integration/SKILL.md
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 handling, and inline editing. Use when working on shell integration, tmux features, command execution, or interactive mode.
Decision brief
Sidecar's interactive shell allows users to type directly into tmux sessions from within the TUI. Tmux remains the PTY backend. Sidecar renders ordered control-mode bytes through the shared tty.Model, whose VT behavior is behind the screenmodel adapter rather than implemented in…
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Declared | Source record | Install path and trigger |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/marcus/sidecar --skill ".claude/skills/shell-integration"Inspect the Agent Skill "shell-integration" from https://github.com/marcus/sidecar/blob/bb5d511984ecef93dd4cc559f94d384cb5b3aa65/.claude/skills/shell-integration/SKILL.md at commit bb5d511984ecef93dd4cc559f94d384cb5b3aa65. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
Review the “Package Structure” section in the pinned source before continuing.
Review the “Data Flow” section in the pinned source before continuing.
Embeddable component for interactive tmux functionality:
Embeddable component for interactive tmux functionality:
Review the “tty.State” section in the pinned source before continuing.
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 90/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 1,047 | Source | Repository attention, not individual Skill quality |
| Compatibility | 1 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Sidecar's interactive shell allows users to type directly into tmux sessions
from within the TUI. Tmux remains the PTY backend. Sidecar renders ordered
control-mode bytes through the shared tty.Model, whose VT behavior is behind
the screenmodel adapter rather than implemented in plugin code.
internal/tty/ # Shared tmux terminal abstraction
tty.go # Core Model and State types
keymap.go # Bubble Tea -> tmux key translation
messages.go # Owner/target/generation-scoped messages
session.go # tmux operations (send-keys, capture-pane, resize)
scheduler.go # Keyed fallback-poll generation ownership
control_*.go # Session-keyed tmux -C transport and manager
capture_range.go # Atomic bounded history capture
cursor.go # Cursor positioning helpers
paste.go # Paste handling (clipboard, bracketed paste)
terminal_mode.go # Capture-fallback mode recovery
output_buffer.go # Absolute, bounded live/history buffer
editor_session.go # Shared inline-editor tmux lifecycle
internal/plugins/workspace/
interactive.go # Workspace-specific interactive mode logic
interactive_selection.go # Text selection in interactive mode
terminal_viewport.go # Pure shared terminal viewport renderer
terminal_control.go # Workspace target/layout policy for tty.Model
terminal_history.go # Lazy absolute scrollback loading
terminal_search.go # Loaded-history search
terminal_links.go # Safe URL/path detection and activation
native_terminal.go # Native cursor and contextual mouse mode
view_preview.go # Agent/shell preview composition
mouse.go # Scroll handling
types.go # InteractiveState type
internal/plugins/filebrowser/
inline_edit.go # Inline editor mode using tty.Model
handlers.go # Message handling for inline edit
User Keypress -> handleInteractiveKeys() -> tty.MapKeyToTmux() -> tmux send-keys
Pane output -> tmux -C ordered %output bytes
-> session-pooled control actor
-> seeded screenmodel adapter
-> adaptive per-feed presentation publication
-> owner/target/generation-scoped Tea message
-> OutputBuffer + cursor/modes/history
-> pure terminal viewport + native Bubble Tea cursor
Open/resync/history -> bounded capture seed/range
Control unavailable/dead -> one scoped capture-poll fallback + clean reseed
Embeddable component for interactive tmux functionality:
type Model struct {
Config Config // Exit key, copy/paste keys, scrollback lines
State *State // Current interactive state
Width int
Height int
OnExit func() tea.Cmd
OnAttach func() tea.Cmd
}
// Usage:
p.inlineEditor = tty.New(&tty.Config{
ExitKey: "ctrl+\\",
ScrollbackLines: 600,
})
cmd := p.inlineEditor.Enter(sessionName, paneID)
type State struct {
Active bool
TargetPane string // tmux pane ID (e.g., "%12")
TargetSession string
LastKeyTime time.Time // Input timing and fallback polling decay
CursorRow, CursorCol int
CursorVisible bool
PaneHeight, PaneWidth int
BracketedPasteEnabled bool
MouseReportingEnabled bool
OutputBuf *OutputBuffer
PollGeneration int // For invalidating stale fallback polls
}
Thread-safe bounded buffer with hash-based change detection:
func (b *OutputBuffer) Update(content string) bool {
rawHash := maphash.String(seed, content)
if rawHash == b.lastRawHash { return false } // Skip ALL processing
content = mouseEscapeRegex.ReplaceAllString(content, "")
b.lines = strings.Split(content, "\n")
return true
}
func (b *OutputBuffer) LinesRange(start, end int) []string
keymap.go)func MapKeyToTmux(msg tea.KeyPressMsg) (key string, useLiteral bool) {
if msg.Mod.Contains(tea.ModCtrl) && msg.Code >= 'a' && msg.Code <= 'z' {
return "C-" + string(msg.Code), false
}
switch msg.Code {
case tea.KeyEnter: return "Enter", false
case tea.KeyBackspace: return "BSpace", false
case tea.KeyTab: return "Tab", false
case tea.KeyUp: return "Up", false
}
if msg.Text != "" {
return msg.Text, true // Literal mode
}
return "", true
}
Modified keys use CSI sequences:
case "shift+up": return "\x1b[1;2A", true
case "ctrl+up": return "\x1b[1;5A", true
case "alt+up": return "\x1b[1;3A", true
case "shift+tab": return "\x1b[Z", true
For printable characters, tmux send-keys -l prevents interpretation.
const (
PollingDecayFast = 50ms // During active typing
PollingDecayMedium = 200ms // After 2s inactivity
PollingDecaySlow = 250ms // After 10s inactivity
KeystrokeDebounce = 20ms // Delay after keystroke
)
Control-mode bytes are the ordinary presentation source for every visible terminal surface. Adaptive capture polling exists only until the first seeded frame and after control/model failure. Workspace agent and shell observation continues independently for provider activity evidence; those captures never overwrite a model-owned presentation buffer.
The control actor writes every ordered byte into screenmodel immediately. Presentation alone is adaptive: the first changed frame after idle publishes inline, sustained changed frames publish at no more than 30 fps per pane-model feed, and one tokenized timer guarantees the newest trailing frame. Seed, reseed, and generation changes bypass the cap; input never enters this cadence. Ordinary Frame() snapshots omit diagnostic cells, while screen comparison explicitly requests the canonical grid.
For isolated performance diagnostics, run with both SIDECAR_PPROF=<port> and SIDECAR_TERMINAL_PERF=1, then read GET /debug/terminalperf. The endpoint is localhost-only and returns fixed numeric counts plus output-to-frame samples, p95, and maximum in microseconds. Keep counters off during CPU profiles, use a separate diagnostic process, and never interpret process-wide model-frame counts as per-feed fps when more than one pane-model feed may be live.
Set SIDECAR_TERMINAL_TRACE=1 only in an isolated proof run to log privacy-safe
capture metadata (surface, role, reason, and generation). It never logs
session or pane identity, terminal text, commands, paths, titles, or provider
payloads. This distinguishes intentional semantic observation from presentation
fallback.
| State | Active | Idle |
|---|---|---|
| Visible + focused | 200ms | 2s |
| Visible + app unfocused | clamped to unfocused cadence | clamped |
| Not visible | 10-20s | 10-20s |
tty.KeyedScheduler owns a generation per logical source
(agent:<name>, shell:<tmuxName>, terminal-panel). Every schedule allocates
a fresh token, and the token travels through capture, result, retry, and
continuation messages. Reset invalidates pending timers and in-flight results.
token, cmd := scheduler.Schedule(key, delay, makeMessage)
if scheduler.IsCurrent(key, token) { /* apply result */ }
Control subscriptions are pooled by tmux session because a control client cannot observe panes in another session. Subscription close and manager stop invalidate and drain queued callbacks before returning.
cursor.go)func QueryCursorPositionSync(target string) (row, col, paneHeight, paneWidth int, visible, ok bool) {
cmd := exec.Command("tmux", "display-message", "-t", target,
"-p", "#{cursor_x},#{cursor_y},#{cursor_flag},#{pane_height},#{pane_width}")
}
Focused live terminal surfaces expose a tea.Cursor through the plugin
CursorProvider capability. Workspace, filebrowser, and notes compute exact
application coordinates and suppress the cursor under modals, while scrolled
back, outside the visible slice, or when another surface owns focus. A painted
cursor is not added to native-cursor content.
When display height differs from tmux pane height:
if paneHeight > displayHeight {
relativeRow = cursorRow - (paneHeight - displayHeight)
} else if paneHeight > 0 && paneHeight < displayHeight {
relativeRow = cursorRow + (displayHeight - paneHeight)
}
Scrolling operates on the captured buffer. No tmux copy-mode involved.
type Plugin struct {
previewOffset int // Lines from bottom (0 = at bottom/live)
autoScrollOutput bool // Auto-follow new output?
}
previewOffsetpreviewOffset, re-enable auto-scroll at 0alt+c (configurable via interactiveCopyKey), or super+c (Cmd+C) as a
built-in that a configured key does not replace. Cmd+C only arrives when the
emulator passes it through — terminals that keep it for themselves (iTerm2)
never deliver it, so alt+c stays the portable chord.alt+v (configurable via interactivePasteKey)Paste wraps text with bracketed paste sequences (\x1b[200~...\x1b[201~) when the application has enabled bracketed paste mode.
terminal_mode.go)When capture fallback owns presentation, detects bracketed paste and mouse reporting modes by scanning the fallback snapshot. Healthy model-backed presentation receives these modes from the shared screen model.
Tmux panes are resized in background at all times (not just interactive mode):
func ResizeTmuxPane(paneID string, width, height int) {
// resize-window, fallback to resize-pane for older tmux
}
Resize triggers: window resize, sidebar toggle/drag, selection change, agent/shell creation, interactive mode entry.
Uses tty.Model plus tty.EditorSession for vim/nano/emacs editing in the file
preview pane. Session creation is history-safe and asynchronous:
func (p *Plugin) enterInlineEditMode(path string) tea.Cmd {
return func() tea.Msg {
session, err := tty.StartEditorSession(tty.EditorSessionOptions{Path: path})
return InlineEditStartedMsg{Session: session, Err: err}
}
}
Workspace Plugin:
enter / E when preview pane focused with output tabCtrl+\ (instant) or double-Escape (150ms delay)Ctrl+] / t only when tmux_full_attach is on (default off)Filebrowser Plugin:
e or Enter on a file (if inline edit enabled)Ctrl+\ or double-EscapeCtrl+] only when tmux_full_attach is on (default off){
"features": {
"tmux_interactive_input": true,
"tmux_inline_edit": true,
"tmux_full_attach": false,
"workspace_terminal_panel": true
}
}
{
"plugins": {
"workspace": {
"interactiveExitKey": "ctrl+\\",
"interactiveAttachKey": "ctrl+]",
"interactiveCopyKey": "alt+c",
"interactivePasteKey": "alt+v",
"tmuxCaptureMaxBytes": 2097152,
"copyOnSelect": false
}
}
}
Init() or View(); use Start()/tea.Cmd.tea.Cmd callbacks; return a scoped message.docs/plans/implemented/spec-tmux-interactive-input.mdFrequently asked questions
Sidecar's interactive shell allows users to type directly into tmux sessions from within the TUI. Tmux remains the PTY backend. Sidecar renders ordered control-mode bytes through the shared tty.Model, whose VT behavior is behind the screenmodel adapter rather than implemented in…
The source record exposes this install command: npx skills add https://github.com/marcus/sidecar --skill ".claude/skills/shell-integration". Inspect the command and pinned source before running it.
The pinned source record declares support for: cursor.
Alternatives
brucesongs/kali-claw
Insecure Design (OWASP A06:2025) focuses on security flaws in system architecture and design phases, rather than code implementation-level bugs.
SerendipityOneInc/ZooData-Skills
API endpoint reference for the ZooData data platform: the 12 commerce endpoints plus 10 keyword-intelligence endpoints (categories, markets, products, competitors, realtime ASIN, AI review analysis, raw reviews, price band, brand, history, and the keyword detail/trend/extends/search/ market-profile/product-traffic/competitor-keywords/traffic-profile/ traffic-timeline family) — their inputs/outputs, parameter quirks, Quick Start (auth, base URL), how credits are tracked (meta.creditsConsumed), an
brucesongs/kali-claw
Binary reverse engineering covers the complete chain from static analysis, dynamic debugging, to vulnerability discovery, exploit development, and malware analysis.
wyre-technology/msp-claude-plugins
Cisco Meraki MCP fundamentals: the full tool catalog, gateway header authentication, Dashboard API v1 structure, Link-header cursor pagination, per-org rate limiting, the read-only / confirm_destructive_action safety model, the meraki_raw_request escape hatch, and error handling.