Full Linux terminals in your Chrome sidebar
Watch: Subagent chaos with audio announcements - Multiple Claude subagents running with different voice status updates
Real bash terminals running in your browser sidebar. Not a web-based terminal emulator - actual Linux shells connected via WebSocket to your local machine.
Run anything you'd run in a normal terminal:
- Claude Code, Gemini CLI, OpenAI Codex - AI coding assistants side-by-side with your browser
- TUI applications - lazygit, htop, btop, vim, neovim, midnight commander
- Development servers - npm, yarn, docker, kubectl, any CLI tool
- Full interactivity - colors, mouse support, copy/paste, scrollback
Browse the web with your terminals always visible - no window juggling, no Alt+Tab. Terminals persist in tmux sessions, so they survive sidebar close/reopen and even browser restarts.
Why this exists: If you use AI coding tools (Claude Code, Gemini, Codex), you need terminals visible while browsing docs, PRs, and issues. Tabz keeps them docked to your browser instead of buried behind windows.
Give your AI full control: Through MCP tools and REST API, Claude Code can control your browser (screenshots, clicks, form filling, network inspection) and spawn/kill terminal sessions programmatically. Your AI assistant becomes a true automation partner.
⚠️ Security Note: By default, MCP tools only allow access to safe domains (GitHub, GitLab, Vercel, localhost, AI image generators). "YOLO mode" can be enabled in settings to allow all URLs, but we recommend using a separate Chrome profile without personal accounts or saved passwords if you do.
- Persistent sessions - Powered by tmux, terminals survive everything
- Profiles system - Save configurations for different tools (Claude Code, lazygit, htop)
- Category organization - Color-coded groups for easy identification
- Smart directory inheritance - Set a global working directory, profiles inherit it
- Local dashboard - Web UI at
localhost:8129for terminal management and quick stats - Tabz MCP tools - Let Claude Code control your browser (screenshots, clicks, form filling)
- Keyboard shortcuts - Quick access to paste text, send to chat, spawn terminals
TabzChrome is designed to work seamlessly with Claude Code:
🚀 Quick Setup - /discover-profiles command
- Scans your system for installed CLI tools (claude, lazygit, htop, nvim, etc.)
- Opens curated lists (awesome-tuis, modern-unix) to discover new tools
- Generates ready-to-import profiles with sensible defaults
⚡ 0 Token Cost Up Front - MCP tools with no context overhead!
Using Anthropic's experimental dynamic tool loading, Claude fetches tool schemas on-demand instead of loading all 20 definitions into context. Enable with the --dynamic-tool-discovery flag when adding the MCP server.
🎭 Power Features (Claude Code Integration):
TabzChrome includes a Claude Code plugin with agents, skills, and MCP tools:
| Component | Description |
|---|---|
| conductor agent | Orchestrate multi-session workflows - spawn Claude workers, send prompts via tmux, coordinate parallel tasks |
| tabz-mcp skill | Guided browser automation with dynamic tool discovery and workflow patterns |
| xterm-js skill | 13 battle-tested patterns for terminal development (resize handling, WebSocket, React hooks, tmux integration) |
| Tabz MCP Server | 20 browser control tools (screenshots, clicks, network capture, downloads) |
Quick setup: The plugin auto-loads when you run Claude Code in the TabzChrome directory.
📦 Install from anywhere via Plugin Marketplace:
/plugin marketplace add GGPrompts/TabzChromeThen use /plugin install to browse and install individual agents, skills, and commands from this repository.
| Component | Version | Notes |
|---|---|---|
| Node.js | 18+ | Backend server |
| Chrome | 116+ | Manifest V3, Side Panel API |
| tmux | 3.0+ | Session persistence |
| OS | WSL2 / Linux / macOS | Backend requires Unix shell |
📦 Installing tmux
| Platform | Command |
|---|---|
| macOS | brew install tmux |
| Ubuntu/Debian | sudo apt install tmux |
| Fedora | sudo dnf install tmux |
| Arch | sudo pacman -S tmux |
🔤 Installing Nerd Fonts (Optional)
The default terminal font is monospace (works everywhere). For better icons and ligatures, install the bundled Nerd Fonts:
Quick Install (fonts included in repo):
| Platform | Command |
|---|---|
| Windows | Open fonts/ folder → Select all .ttf → Right-click → Install |
| macOS | Double-click each .ttf in fonts/ → Click "Install Font" |
| Linux | cp fonts/*.ttf ~/.local/share/fonts/ && fc-cache -fv |
After installing, restart Chrome and select the font in Settings (⚙️) → Edit profile → Font Family.
See fonts/README.md for details.
Not on Chrome Web Store - This is a local developer tool that requires running a backend server. Install via "Load unpacked" in Chrome's developer mode.
⚠️ WSL Users: Run these commands inside a WSL terminal, not from Windows Git Bash or PowerShell accessing WSL paths. The backend uses native modules (node-pty) that require Linux npm to compile properly. Open WSL first:wslin Windows Terminal, then proceed.
# Clone
git clone https://github.com/GGPrompts/TabzChrome.git
cd TabzChrome
# Install dependencies
npm install
cd backend && npm install && cd ..
# Build extension
npm run build- Open
chrome://extensions - Enable Developer mode (top-right)
- Click Load unpacked → select
dist-extension/
# Recommended (WSL/Linux/macOS)
./scripts/dev.shWhy use dev.sh?
- Creates a
tabz-chrometmux session with correct config - Enables log forwarding so the "Backend Logs" profile works (shows live server output)
- Makes debugging with Claude Code easier (can capture logs via
tmux capture-pane)
Alternative: manual start
cd backend && npm start # Runs on port 8129Note: Without dev.sh, the "Backend Logs" profile won't show logs since it relies on the named tmux session.
- Click extension icon in toolbar
- Keyboard shortcut (set your own at
chrome://extensions/shortcuts) - Right-click page → "Open Terminal Sidebar"
Note: Chrome doesn't allow extensions to close sidebars programmatically (requires user gesture), so the menu always says "Open" rather than "Toggle". Close via Chrome's built-in panel menu (⋮).
Click the + dropdown to spawn terminals from saved profiles:
- Name - Display name for the profile
- Category - Optional grouping (e.g., "Claude Code", "TUI Tools") with color coding
- Working Directory - Optional (inherits from header if empty)
- Startup Command - Optional command to run on spawn (e.g.,
lazygit,htop) - Font Size - 12-24px per profile
- Theme - 6 color schemes + dark/light toggle (toggle in header bar)
Organize your profiles into color-coded groups:
- Collapsible Groups - Click category header to expand/collapse
- 9 Colors - Green, Blue, Purple, Orange, Red, Yellow, Cyan, Pink, Gray
- Color Picker - Click color dots next to category to change color
- Color-Coded Tabs - Selected terminal tabs show their category color
- Search - Filter profiles by name, command, or category
Backup and share your profile configurations:
- Export - Click the download icon to save all profiles as
tabz-profiles-{date}.json - Import - Click the upload icon to load profiles from a JSON file
- Merge - Add new profiles while keeping existing ones (duplicates by ID are skipped)
- Replace - Replace all existing profiles with imported ones
The folder icon in the header sets a global working directory. Profiles without an explicit directory inherit this, enabling:
- One "lazygit" profile that works for any project
- One "npm run dev" profile for any Node project
- Just change the header directory to switch projects
- Full xterm.js emulation - Colors, cursor, scrollback
- Copy/Paste - Ctrl+Shift+C / Ctrl+Shift+V
- Session persistence - Terminals survive sidebar close (tmux-backed)
- Tab management - Multiple terminals, click to switch
The 👻 badge appears in the header when orphaned tmux sessions exist (sessions running in tmux but not attached to the UI).
Use cases:
- Detach long-running sessions to free up tab space
- Recover sessions after browser crash or sidebar close
- Clean up forgotten sessions
How to use:
- Right-click a tab → "👻 Detach Session" - removes from UI but keeps tmux session alive
- Ghost badge appears with count of detached sessions
- Click badge → select sessions → Reattach (bring back as tabs) or Kill (destroy)
| Action | Result |
|---|---|
| Detach Session | Tab removed, tmux session preserved, appears in Ghost Badge |
| Reattach | Session restored as a tab with full terminal history |
| Kill | Tmux session destroyed permanently |
Terminal tabs show live Claude Code status with emoji indicators:
| Emoji | Meaning |
|---|---|
| 🤖✅ | Claude ready/waiting for input |
| 🤖⏳ | Claude is thinking |
| 🤖🔧 | Claude is using a tool |
Detailed status on tabs - Tabs show exactly what Claude is doing: "editing page.tsx", "reading utils.py", "running npm test". See the actual file names and actions at a glance.
Subagent indicators - When Claude spawns subagents, multiple robot emojis appear (🤖🤖) to show parallel work happening.
Setup required - See claude-hooks/README.md for installation.
Get voice announcements for Claude Code activity. Configure in Settings → Claude Audio:
Settings:
- Voice - Choose a specific voice or "Random (unique per terminal)" to distinguish multiple Claude sessions
- Speech Rate - Adjust speed (-50% to +100%)
- Volume - Master volume control
Events you can toggle:
| Event | What it announces |
|---|---|
| Ready notification | "Claude ready" when waiting for input |
| Session start | Terminal name when Claude session begins |
| Tool announcements | "Reading", "Editing", "Searching"... |
| Include file names | "Reading package.json", "Editing App.tsx" |
| Subagent activity | "Spawning agent", agent count changes |
Tool debounce prevents announcement spam during rapid tool usage.
Multi-Claude tip: Use "Random (unique per terminal)" voice so each Claude session has a distinct voice - makes it easy to know which one is talking!
The chat input bar includes command history:
- ↑/↓ arrows - Navigate through previous commands
- Clock icon - Open history dropdown with remove buttons
- Commands persist in Chrome storage
Access a web-based dashboard at http://localhost:8129 for terminal management:
Click this icon in the sidebar header to open the dashboard.
Pages:
| Page | URL | Features |
|---|---|---|
| Dashboard | / |
Quick stats (active terminals, uptime, memory), working directory selector, quick spawn |
| Terminals | /terminals.html |
Full terminal list, kill/reattach, orphan management |
Features:
- Working directory sync - Changes in dashboard sync to extension sidebar and vice versa
- Real-time stats - Active terminals, backend uptime, memory usage
- Orphan cleanup - Find and kill detached tmux sessions
- Quick spawn - Launch new terminals directly from the dashboard
Add data-terminal-command to any HTML element to create clickable command buttons:
<button data-terminal-command="npm run dev">Start Dev</button>
<a href="#" data-terminal-command="git status">Check Git</a>
<code data-terminal-command="npm install express">npm install express</code>Behavior:
- Click opens the sidebar and sends command to the chat input bar
- User selects which terminal tab receives the command
- Visual feedback: element shows "✓ Queued!" briefly
- Works on dynamically added elements (MutationObserver)
Right-click anywhere on a webpage to access terminal actions:
| Action | When Available | Destination |
|---|---|---|
| Open Terminal Sidebar | Always | Opens or focuses the sidebar (always says "Open" since Chrome can't close sidebars programmatically) |
| Send to Tabz | Text selected | Chat input bar - review/edit, then pick terminal |
| Paste to Terminal | Text selected | Active terminal - at cursor position, like typing |
| Read Aloud | Text selected | TTS playback - speaks the selected text through the sidebar |
Neither "Send to Tabz" nor "Paste to Terminal" auto-executes - press Enter to run the command. "Send to Tabz" lets you choose which terminal; "Paste to Terminal" goes to whichever tab is currently active.
Read Aloud uses your configured audio settings (Settings → Audio tab) including voice, rate, and volume. If you have "Random" voice selected, each read-aloud will use a different voice.
Note: When spawning new terminals via profiles or the Spawn API, the startup command does auto-execute after the shell is ready.
When browsing GitHub repository pages, a floating action button appears in the bottom-right corner:
| Button | Action |
|---|---|
| Star | Clicks GitHub's native star button (shows "Already!" if starred) |
| Clone | Queues git clone <url> && cd <repo> to the sidebar chat bar |
| Fork | Opens the repository's fork page in a new tab |
Features:
- Only appears on repo root and code pages (not on issues, PRs, or settings)
- Glassmorphism styling matching the extension theme
- Dismissible per-repo (X button) - remembers for the session
- Clone command includes
cdto enter the cloned directory
Spawn terminals directly from Chrome's address bar using the term keyword:
Usage: Type term + space + URL
Examples:
term github.com/user/repo- Open GitHub repositoryterm localhost:3000- Open local dev serverterm my-app.vercel.app- Open Vercel deployment
The URL opens in a new tab and the sidebar activates automatically.
Tabz includes an MCP server with 20 tools that let Claude Code control your browser:
| Tool | Description |
|---|---|
tabz_screenshot |
Capture viewport to disk |
tabz_screenshot_full |
Capture entire scrollable page |
tabz_click |
Click element by CSS selector |
tabz_fill |
Type into input fields |
tabz_execute_script |
Run JavaScript |
tabz_get_console_logs |
View browser console |
tabz_list_tabs |
List open tabs (accurate active tab detection) |
tabz_switch_tab |
Switch to a tab |
tabz_rename_tab |
Assign custom names to tabs |
tabz_open_url |
Navigate to allowed domains |
tabz_get_page_info |
Get current URL/title |
tabz_download_image |
Download images to disk (works with AI-generated images!) |
tabz_get_element |
Inspect element HTML/CSS |
tabz_enable_network_capture |
Start capturing network requests |
tabz_get_network_requests |
List captured XHR/fetch requests |
tabz_get_api_response |
Get full response body for a request |
tabz_clear_network_requests |
Clear captured requests |
tabz_download_file |
Download any URL to disk |
tabz_get_downloads |
List recent downloads with status |
tabz_cancel_download |
Cancel in-progress download |
Click ⚙️ → MCP Tools tab to configure which tools Claude can use:
- Toggle individual tools on/off
- See token usage estimates per tool
- Add custom allowed domains for
tabz_open_url - Apply presets (Minimal, Standard, Full)
Tip: Use
--dynamic-tool-discoveryflag when adding the MCP server to load tool schemas on-demand (0 tokens up front).
Install the tabz-mcp skill for guided browser automation. The skill dynamically discovers available tools and provides workflow patterns - never goes stale when tools are added.
Location: ~/.claude/skills/tabz-mcp/
| Feature | Remote Debugging Required? |
|---|---|
| Terminal sidebar | No |
| Profiles, audio, themes | No |
| Ghost badge, session persistence | No |
Tab management (list_tabs, switch_tab) |
No (extension-based) |
Downloads (download_file, download_image) |
No (extension-based) |
| Console logs | No (extension-based) |
| Screenshots, clicks, fill | Yes (CDP) |
| Network capture | Yes (CDP) |
Many MCP tools now work without remote debugging! Tab management uses the extension API for accurate active tab detection (Claude knows which tab you're actually looking at). Only advanced features like screenshots and network capture require CDP.
-
Start Chrome with remote debugging:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir=C:\Temp\chrome-debug
Tip: Create a desktop shortcut for this command so you don't forget the flag.
-
Configure MCP in your project's
.mcp.json:{ "mcpServers": { "tabz": { "command": "/path/to/TabzChrome/tabz-mcp-server/run-auto.sh", "args": [], "env": { "BACKEND_URL": "http://localhost:8129" } } } }
See tabz-mcp-server/MCP_TOOLS.md for full documentation.
Chrome Extension (React + TypeScript)
│
│ WebSocket + REST API
▼
Backend (Node.js + Express, port 8129)
│
│ PTY + tmux commands
▼
Tmux Sessions (source of truth)
Why tmux?
- Sessions survive backend restarts
- Free persistence - no database needed
- Single source of truth - no state sync bugs
TabzChrome/
├── extension/ # Chrome extension source
│ ├── sidepanel/ # Main sidebar UI (sidepanel.tsx)
│ ├── components/ # React components (Terminal, Settings, Dropdowns)
│ ├── hooks/ # React hooks (useProfiles, useTerminalSessions, etc.)
│ ├── background/ # Service worker (WebSocket relay)
│ ├── content/ # Content script (data-terminal-command triggers)
│ ├── shared/ # Messaging and storage helpers
│ └── manifest.json
├── backend/ # Node.js server
│ ├── server.js # Express + WebSocket (port 8129)
│ ├── modules/ # PTY handler, terminal registry, tmux manager
│ ├── routes/ # API routes (spawn, browser, files)
│ └── public/ # Dashboard web UI
├── tabz-mcp-server/ # MCP server for Claude Code browser control
├── claude-hooks/ # Claude Code status detection hooks
└── dist-extension/ # Built extension (load this in Chrome)
Default: 8129 (configured in backend/.env)
Extension shortcuts (set in Chrome):
| Shortcut | Action |
|---|---|
| Alt+T | New terminal tab (default profile) |
| Alt+W | Close current terminal tab |
| Alt+V | Paste selected text to terminal |
| Alt+C | Send selected text to chat |
Note: Alt+1-9 for tab switching has no default - set manually if desired. Customize all shortcuts at
chrome://extensions/shortcuts
In-terminal shortcuts (always available):
| Shortcut | Action |
|---|---|
| Ctrl+Shift+C | Copy selected text |
| Ctrl+Shift+V | Paste from clipboard |
Tmux shortcuts (all terminals use tmux):
| Shortcut | Action |
|---|---|
| Ctrl+B, d | Detach session (keeps running in background) |
| Ctrl+B, [ | Enter scroll/copy mode (q to exit) |
| Ctrl+B, ] | Paste from tmux buffer |
Tip: If your terminal seems "stuck" after pressing Ctrl+B, press Escape to cancel. See tmux cheatsheet for more commands.
The backend server supports optional environment variables in backend/.env:
| Variable | Default | Description |
|---|---|---|
PORT |
8129 |
HTTP/WebSocket server port |
LOG_LEVEL |
4 |
Logging verbosity: 0=silent, 1=fatal, 2=error, 3=warn, 4=info, 5=debug |
LOG_FILE |
(none) | Optional file path to write logs (e.g., logs/backend.log) |
CLEANUP_ON_START |
false |
Kill orphaned tmux sessions on backend start |
Example backend/.env:
PORT=8129
LOG_LEVEL=5 # Enable debug logging
# LOG_FILE=logs/backend.lognpm install fails with EPERM/UNC path errors (WSL)
- You're running npm from Windows (Git Bash/PowerShell) on a WSL path
- Fix: Open a WSL terminal first (
wslin Windows Terminal), then run commands there - The backend uses
node-ptywhich requires Linux npm to compile native modules
Backend won't start
lsof -i :8129 # Check if port in use
pkill -f "node.*server.js" # Kill orphaned processesTerminal won't connect
- Check backend:
curl http://localhost:8129/api/health - WSL users: Use
localhost, not127.0.0.1
Sidebar doesn't open
- Reload extension at
chrome://extensions - Check service worker console for errors
Sessions not persisting
tmux ls # Verify tmux is running
tmux kill-server # Reset if corruptedTerminal text has gaps/spacing between characters
- This can happen with custom fonts that aren't installed
- Fix: Settings (⚙️) → Edit profile → Change Font Family to "Monospace (Default)" or "Consolas"
- If using Nerd Fonts, make sure they're properly installed and restart Chrome
Terminal display looks corrupted (text wrapping wrong, duplicated lines)
- Can occasionally happen after rapidly resizing the sidebar during heavy output
- Fix: Click the ↻ refresh button in the header bar to reload the sidebar
- This forces tmux to redraw all terminals and fixes display issues
# Build extension
npm run build
# Build + copy to Windows Desktop (WSL2)
npm run build && rsync -av --delete dist-extension/ /mnt/c/Users/$USER/Desktop/TabzChrome/dist-extension/
# Run tests
npm test| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health |
Health check (uptime, memory, version, Node.js version) |
| POST | /api/spawn |
Spawn terminal (rate limited: 10/min) |
| GET | /api/tmux/sessions |
List sessions |
| GET | /api/settings/working-dir |
Get working directory settings |
| POST | /api/settings/working-dir |
Update working directory settings |
| POST | /api/audio/speak |
Generate TTS and broadcast to sidebar for playback |
Health Endpoint Response:
{
"success": true,
"status": "healthy",
"data": {
"uptime": 3600,
"activeTerminals": 3,
"totalTerminals": 5,
"memoryUsage": { "heapUsed": 45, "heapTotal": 65, "rss": 120, "unit": "MB" },
"version": "1.0.0",
"nodeVersion": "v20.10.0",
"platform": "linux",
"timestamp": "2025-12-12T12:00:00.000Z"
}
}curl -X POST http://localhost:8129/api/spawn \
-H "Content-Type: application/json" \
-d '{
"name": "My Terminal",
"workingDir": "~/projects",
"command": "lazygit"
}'Generate audio and play it through the sidebar. Useful for slash commands and automation.
curl -X POST http://localhost:8129/api/audio/speak \
-H "Content-Type: application/json" \
-d '{
"text": "Hello, this is a test",
"voice": "en-US-AndrewMultilingualNeural",
"rate": "+20%",
"volume": 0.8
}'| Parameter | Type | Default | Description |
|---|---|---|---|
text |
string | required | Text to speak |
voice |
string | en-US-AndrewMultilingualNeural |
Edge TTS voice name |
rate |
string | +0% |
Speech rate (-50% to +100%) |
volume |
number | 0.7 |
Playback volume (0-1) |
Audio is generated via edge-tts, cached, and broadcast to connected sidebars via WebSocket.
Recent improvements for stability and maintainability:
- Rate Limiting - Spawn endpoint limited to 10 requests/minute per IP to prevent DoS
- Error Boundaries - React error boundary catches crashes, shows recovery UI, preserves terminal sessions
- JSDoc Documentation - Key React components documented with prop types and usage examples
- Keyboard Navigation - Full arrow key, Enter, Escape, Home/End support in dropdowns
- Graceful Shutdown - SIGTERM/SIGINT handlers for clean process termination
- PM2 Configuration -
ecosystem.config.jswith cluster mode, log rotation, and auto-restart - Input Validation - Joi schemas validate all API inputs with clear error messages
- Health Monitoring - Enhanced
/api/healthendpoint with Node.js version, platform, detailed memory stats
Issues and PRs welcome! See CLAUDE.md for architecture details.
MIT License - see LICENSE
- Built with React, TypeScript, xterm.js
- Chrome Extension Manifest V3
- tmux for session persistence
GitHub | Built by Matt












