VibeTUI is a terminal-based user interface (TUI) for managing multiple coding agent sessions running in tmux. It provides a unified dashboard to monitor, create, and switch between sessions running Amp, Claude Code, OpenCode, and Codex. The tool is designed for developers who run multiple AI coding agents in parallel and need visibility into what each agent is doing.
VibeTUI runs on a server accessed via SSH, displaying a two-pane interface: a collapsible sidebar showing all sessions with their status, and a main pane displaying the active agent's terminal output.
- Provide a single dashboard to view all coding agent sessions at a glance
- Show real-time status (running/idle/detached/dead) for each session
- Display agent type, project context, and session description in the sidebar
- Enable quick switching between multiple concurrent agent sessions
- Streamline creation of new sessions with agent selection and project setup
- Support git worktrees for parallel work on the same project
- Integrate with GitHub CLI for repository creation
- Auto-manage agent installation and upgrades
Description: As a developer, I want to see all my coding agent sessions in a sidebar so I can understand what's happening across all my projects at once.
Acceptance Criteria:
- Sidebar displays list of all vibetui-managed tmux sessions
- Each session shows: agent icon, session name, status indicator, short description
- Sessions are grouped by status: Running | Idle | Detached
- Within each group, sessions are sorted by recency (most recent first)
- Current working directory is visible for each session
- Context window usage is shown for agents that expose it (Amp, OpenCode)
- Git repos are highlighted with an icon
- Typecheck/lint passes
Description: As a developer, I want to hide the sidebar to maximize screen real estate when I'm focused on a single agent.
Acceptance Criteria:
- Pressing Ctrl+B toggles sidebar visibility
- When hidden, main pane expands to full width
- Sidebar state persists during session
- Visual indicator shows sidebar toggle keybinding
- Typecheck/lint passes
Description: As a developer, I want to select a session from the sidebar to view its terminal output in the main pane.
Acceptance Criteria:
- Arrow keys (↑/↓) navigate session list
- Enter selects the highlighted session
- Selected session's terminal output appears in main pane
- Main pane header shows current directory path
- Switching is instant (no perceptible delay)
- Typecheck/lint passes
Description: As a developer, I want to quickly start a new agent session in the current directory.
Acceptance Criteria:
- Pressing Ctrl+N opens new session modal
- Modal shows agent selection (Amp, Claude Code, OpenCode, Codex)
- Default agent is pre-selected from config (default: Amp)
- Selecting agent creates tmux session and starts agent
- Session is added to sidebar in Running group
- If current directory is outside projects_folder, auto-navigate to projects_folder and notify user
- Typecheck/lint passes
Description: As a developer, I want to start a new agent session in an existing project.
Acceptance Criteria:
- New session modal shows list of projects from projects_folder
- Projects are sorted by recency
- User can filter/search projects by name
- After selecting project, user selects agent
- If project has existing sessions, offer to create git worktree
- Typecheck/lint passes
Description: As a developer, I want to create a new project with optional GitHub repository.
Acceptance Criteria:
- New session modal has "Create New Project" option
- User enters project name
- User chooses: Local only | Create GitHub repo
- If GitHub: prompt for public/private (default: private)
- Creates directory in projects_folder
- Runs
git initand optionallygh repo create - Starts selected agent in new project directory
- If gh CLI not installed, offer to install it
- Typecheck/lint passes
Description: As a developer, I want to close a session with confirmation to prevent accidental data loss.
Acceptance Criteria:
- Pressing 'd' or Delete on selected session opens confirmation dialog
- Dialog asks: "Kill session?" with options: Kill | Detach | Cancel
- Kill: terminates tmux session and removes from sidebar
- Detach: moves session to Detached group, keeps running
- Detached sessions can be reattached later
- Typecheck/lint passes
Description: As a developer, I want to see whether each agent is actively running or idle so I know which sessions need attention.
Acceptance Criteria:
- Running status: agent has produced output in last 5 seconds
- Idle status: no output for more than 5 seconds
- Status is polled every 2-5 seconds using
tmux capture-pane - Visual indicator (icon or color) distinguishes Running from Idle
- Dead sessions (tmux died unexpectedly) show in Detached group with "dead" status
- Typecheck/lint passes
Description: As a developer, I want sessions to have meaningful descriptions so I can remember what each one is about.
Acceptance Criteria:
- For Amp: use thread title from Amp API if available
- For other agents: generate description from first message using Claude Haiku
- Description is generated once at session creation
- Pressing Ctrl+R regenerates description using full context
- Network errors during generation retry silently in background
- Description is stored in ~/.vibetui/sessions.json
- Typecheck/lint passes
Description: As a developer, I want vibetui to handle agent installation and upgrades so I always have working agents.
Acceptance Criteria:
- On startup, detect which agents are installed using
whichcommand - If agent not installed, show as unavailable with "Install" option
- Selecting "Install" runs appropriate install command (with sudo if needed)
- When starting new session, check if agent upgrade is available
- If upgrade available, show modal: "Upgrade available. Upgrade now?"
- Upgrade blocks session creation until resolved (Upgrade | Skip | Cancel)
- Typecheck/lint passes
Description: As a developer, I want to use git worktrees when creating multiple sessions in the same project so agents don't conflict.
Acceptance Criteria:
- When creating session in project with existing sessions, offer worktree option
- "Create in worktree?" dialog with Yes | No | Cancel
- If Yes: create worktree with branch name based on session purpose
- Each worktree is treated as separate project in sidebar
- Main pane header clearly shows worktree path
- Typecheck/lint passes
Description: As a developer, I want to see available keybindings so I can learn the interface quickly.
Acceptance Criteria:
- Pressing
?shows help overlay with all keybindings - Overlay is dismissible with
?or Escape - Footer or status bar shows hint: "Press ? for help"
- Help includes all navigation, session management, and special keys
- Typecheck/lint passes
Description: As a developer, I want to configure vibetui defaults so it matches my workflow.
Acceptance Criteria:
- Config file at ~/.vibetui.yaml
- Config includes: projects_folder (default: ~/git), default_agent (default: amp)
- Invalid config shows clear error message on startup
- Missing config creates default config automatically
- Typecheck/lint passes
Description: As a developer, I want session information to persist across vibetui restarts.
Acceptance Criteria:
- Session metadata stored in ~/.vibetui/sessions.json
- Metadata includes: session_id, agent_type, description, project_path, created_at
- On startup, reconcile stored metadata with live tmux sessions
- Sessions in metadata but not in tmux are marked as dead/cleaned up
- Sessions in tmux but not in metadata (external) are discovered if they match naming pattern
- Typecheck/lint passes
- FR-1: Create tmux sessions with naming pattern
vibe-{agent}-{project}-{shortid} - FR-2: Track sessions via metadata file, reconcile with live tmux state on startup
- FR-3: Support session states: starting, running, idle, detached, dead
- FR-4: Poll session status every 2-5 seconds using
tmux capture-pane - FR-5: Detect running/idle by tracking last output timestamp (idle if >5 seconds)
- FR-6: Support four agents at launch: Amp (
amp), Claude Code (claude), OpenCode (opencode), Codex (codex) - FR-7: Detect agent availability using
which {agent}command - FR-8: Install missing agents using official install commands (with sudo confirmation)
- FR-9: Check for agent upgrades when starting new session
- FR-10: Show modal for upgrade with options: Upgrade | Skip | Cancel
| Agent | Install Command | Upgrade Command |
|---|---|---|
| Amp | curl -fsSL https://claude.ai/install.sh | bash |
amp update |
| Claude Code | npm i -g @anthropic-ai/claude-code |
claude update |
| OpenCode | curl -fsSL https://opencode.ai/install | bash |
opencode upgrade |
| Codex | npm i -g @openai/codex |
npm i -g @openai/codex@latest |
- FR-11: Determine status by parsing
tmux capture-pane -t SESSION -poutput - FR-12: Track last output timestamp per session
- FR-13: Running = output within last 5 seconds; Idle = no output for >5 seconds
- FR-14: Dead = tmux session no longer exists but metadata present
- FR-15: For Amp: parse "X% of 968k" indicator if visible in output
- FR-16: For OpenCode: use
opencode statsor parse auto-compact messages - FR-17: For Claude Code: parse status line if available
- FR-18: Show "N/A" for agents that don't expose context usage
- FR-19: For Amp: query thread title via Amp API (
GET /api/threads/{threadId}) - FR-20: For other agents: generate using Claude Haiku from first message
- FR-21: Store descriptions in ~/.vibetui/sessions.json
- FR-22: Ctrl+R regenerates description using full context (all sources weighted)
- FR-23: Retry network errors silently in background
- FR-24: Read projects from config
projects_folder(default: ~/git) - FR-25: Any directory in projects_folder is a project
- FR-26: Git repos are highlighted with icon
- FR-27: Support git worktree creation for parallel sessions in same project
- FR-28: Each worktree treated as separate project entry
- FR-29: Integrate with gh CLI for repo creation
- FR-30: If gh not installed, offer to install it
- FR-31: New repo flow: name → public/private (default: private) → create
- FR-32: After creation:
git init+gh repo create+ add remote
- FR-33: Two-pane layout: sidebar (left) + main pane (right)
- FR-34: Sidebar shows session list grouped by: Running | Idle | Detached
- FR-35: Main pane shows active agent terminal output
- FR-36: Main pane header shows current working directory
- FR-37: Sidebar collapsible via Ctrl+B
- FR-38: Footer shows "Press ? for help"
| Key | Action |
|---|---|
| ↑/↓ | Navigate session list |
| Enter | Select session |
| Ctrl+N | New session modal |
| Ctrl+B | Toggle sidebar |
| Ctrl+R | Refresh session description |
| d / Delete | Close/kill session (with confirmation) |
| ? | Show help overlay |
| Escape | Close modal/overlay |
| q | Quit vibetui |
- FR-39: Run inside existing tmux session (nested tmux support)
- FR-40: Create one tmux session per agent session
- FR-41: Use
tmux set-option -t SESSION remain-on-exit onfor crash visibility - FR-42: Discover existing vibetui sessions by naming pattern on startup
- No support for agents beyond Amp, Claude Code, OpenCode, Codex
- No multi-user / team features
- No cloud sync of sessions or metadata
- No integration with GitHub Issues or Pull Requests
- No automatic context window summarization
- No sending commands/prompts to agents from vibetui (view-only main pane)
- No custom themes or color configuration
- No mouse support beyond basic Textual defaults
- Language: Python 3.11+
- TUI Framework: Textual (built on Rich)
- Config Format: YAML
- Metadata Storage: JSON files in ~/.vibetui/
- tmux (auto-install if missing)
- gh CLI (auto-install if missing, for GitHub features)
- Anthropic API key (for Claude Haiku description generation)
~/.vibetui/
├── config.yaml # User configuration (created from ~/.vibetui.yaml symlink)
├── sessions.json # Session metadata
└── cache/ # Cached descriptions, agent status
vibe-{agent}-{project}-{shortid}
# Examples:
# vibe-amp-myapp-a3f2
# vibe-claude-backend-b7c1
# vibe-opencode-frontend-d4e5
def get_session_status(session_name: str) -> str:
"""Determine if session is running, idle, or dead."""
try:
output = subprocess.check_output(
["tmux", "capture-pane", "-t", session_name, "-p"],
timeout=1
)
last_activity = get_last_activity_timestamp(session_name)
if time.time() - last_activity < 5:
return "running"
return "idle"
except subprocess.CalledProcessError:
return "dead"AGENTS = {
"amp": {"command": "amp", "icon": "⚡"},
"claude": {"command": "claude", "icon": "🤖"},
"opencode": {"command": "opencode", "icon": "📝"},
"codex": {"command": "codex", "icon": "🔮"},
}
def detect_installed_agents() -> dict:
"""Check which agents are available on PATH."""
result = {}
for name, config in AGENTS.items():
path = shutil.which(config["command"])
result[name] = {"installed": path is not None, "path": path}
return result- User can view all active agent sessions within 1 second of launching vibetui
- Switching between sessions takes less than 100ms
- Session status updates within 5 seconds of agent activity change
- New session creation (existing project) completes in under 3 seconds
- Agent installation completes successfully when user confirms
Resolution: Use AMP_API_KEY environment variable or existing Amp credentials. Amp supports --stream-json for programmatic access via CLI. For thread titles, use amp threads commands. The API key can be obtained from ampcode.com/install. Vibetui should check for existing Amp auth first, then fall back to prompting user.
Resolution: Amp shows "X% of 968k" in the terminal. Parse this with regex pattern: (\d+)%\s+of\s+(\d+)k. For OpenCode, the TUI shows context usage but there's no direct CLI command for per-session context — OpenCode uses auto-compact at 95% of context window. For Claude Code, parse status line if available. Show "N/A" when not parseable.
Resolution: opencode stats shows aggregate statistics across all sessions (token usage, costs), not per-session context. It accepts --days, --tools, --models, --project flags. For session-specific info, use opencode session list --format json. OpenCode stores sessions in SQLite and has auto-compact feature that triggers at 95% context. Recommendation: Don't rely on context window for OpenCode — just track activity status.
Resolution: Based on Toad patterns, use double-tap escape (400ms window) to exit terminal focus, and avoid Ctrl+B entirely. New keybindings:
F2orAlt+Bfor sidebar toggle (instead of Ctrl+B)- Double-tap
Escapeto unfocus terminal and return to sidebar Tabto cycle between sidebar and main pane- Consider making toggle key configurable in ~/.vibetui.yaml
Resolution: Cache aggressively in ~/.vibetui/sessions.json. Generate description once at session creation. Ctrl+R regenerates on demand. For Amp, prefer native thread titles (free via Amp API) over Haiku generation. Only use Haiku for agents that don't expose titles. Rate limit regeneration to max 1 per minute per session.
Resolution: Use pattern vibe/{session-shortid} for auto-generated branches. Examples: vibe/a3f2, vibe/b7c1. This keeps branches namespaced and identifiable. If user provides a purpose/description, generate a slug: vibe/{purpose-slug}-{shortid} (e.g., vibe/fix-auth-a3f2).
- Session naming:
task_{taskId}_agent_{agentId}— we usevibe-{agent}-{project}-{shortid} - Terminal capture:
tmux capture-pane -t SESSION -e -p -S -20(last 20 lines with ANSI colors) - Agent detection:
which {agent}for all supported agents - Status polling: 5-second intervals for terminal preview refresh
- WebSocket + PTY for live terminal:
tmux attach-session -t SESSIONthrough PTY wrapper - Cleanup: kill tmux sessions, run teardown, remove dirs in order
- Activity idle timeout: 5 seconds (configurable)
- Track multiple timestamps: lastOutputTimestamp, lastInputTimestamp, lastModified, startedAt
- Use most recent timestamp from any source for activity detection
- Foreground process tracking: 500ms polling to detect command start/finish
- Claude agent detection: check if command contains "claude"
- Session watcher: 100ms polling for metadata file changes
- Double-tap escape (400ms window) to exit terminal focus
- PTY setup:
pty.openpty()with non-blocking I/O viafcntl - Environment:
TERM=xterm-256color,COLORTERM=truecolor,FORCE_COLOR=1 - Keybinding groups with
check_action()for context-aware handling - Reactive variables (
var()) for all mutable state - Custom messages for inter-widget communication
- CSS-based visibility toggle for sidebar (offset-x: -100% when hidden)
- Alternate screen detection for vim/less/etc full-screen apps
| Key | Action |
|---|---|
| ↑/↓ | Navigate session list |
| Enter | Select session |
| Ctrl+N | New session modal |
| F2 or Alt+B | Toggle sidebar |
| Ctrl+R | Refresh session description |
| d / Delete | Close/kill session (with confirmation) |
| ? | Show help overlay |
| Escape (double-tap) | Unfocus terminal, return to sidebar |
| Tab | Cycle focus between sidebar and main pane |
| q | Quit vibetui |
- Use
tmux attach-session -t SESSIONthrough PTY for live terminal in main pane - Capture preview with
tmux capture-pane -t SESSION -e -p -S -20 - Track last output timestamp per session for running/idle detection
- Poll every 2-5 seconds for status updates
- Handle alternate screen mode (vim, less) — terminal widget should detect CSI sequences