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…
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
$ npx -y skills add marcus/sidecar --skill shell-integration --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/shell-integrationContext preview
The summary Claude sees to decide when to auto-load this skill.
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
name: shell-integration description: > 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. user-invocable: false
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 reseedEmbeddable 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) []stringfunc 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. Worksp
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,…