Open TUI terminal MUX for VS Code with tmux, zellij, and native terminal support.
If this project helps your workflow, you can support it on GitHub Sponsors.
- Backend-first terminal: Starts a plain shell for your chosen backend (
native,tmux, orzellij) — no AI tool picker on open - Full TUI Support: Complete terminal emulation with xterm.js and WebGL rendering
- ULW Terminal Manager: Dedicated tmux session management surface with inline pane and window controls
- Tmux Integration: Automatic tmux session discovery, workspace-scoped session filtering, and tmux status bar hidden in sidebar
- Native shell switching: Switch to a normal shell in the sidebar when you need it
- Return to Workspace Banner: Quick navigation back to the active workspace from ULW Terminal Manager
- HTTP API Integration: Bidirectional communication with OpenCode CLI via HTTP API
- Auto-Context Sharing: Automatically shares editor context when terminal opens
- File References with Line Numbers: Send file references with
@filename#L10-L20syntax - Code Actions: Diagnostic-triggered code actions for errors and warnings
- Keyboard Shortcuts: Quick access with
Cmd+Alt+L,Cmd+Alt+A, andCmd+Alt+T - Drag & Drop Support: Hold Shift and drag files/folders to send as references
- Context Menu Integration: Right-click files in Explorer or text in Editor to send to OpenCode
- Secondary Sidebar: Dock the terminal in the secondary sidebar for split-screen workflows
- Configurable: Customize font, terminal settings, backend (
ulw.terminalBackend), and HTTP API behavior
This extension provides a sidebar-only terminal MUX experience. A normal shell (or your tmux / zellij session) runs in the VS Code sidebar instead of the native terminal panel. OpenCode and other AI CLIs are optional — start them yourself in the terminal when you want them.
The extension consists of two primary sidebar views:
- ULW Terminal (secondary sidebar): The main interactive TUI session.
- ULW Terminal Manager: A dedicated surface for managing tmux sessions, panes, and windows.
The extension uses a hybrid communication approach:
-
HTTP API: Primary communication channel with OpenCode CLI
- Port range: 16384-65535 (ephemeral ports)
- Endpoints:
/health,/tui/append-prompt - Auto-discovery of OpenCode CLI HTTP server
-
WebView Messaging: Terminal I/O between extension host and sidebar WebView
- xterm.js for terminal rendering
- Bidirectional message passing for input/output
- Open VS Code
- Go to Extensions (
Cmd+Shift+X/Ctrl+Shift+X) - Search for "ULW"
- Click Install
For VSCodium, Gitpod, Eclipse Theia, and other VS Code-compatible IDEs:
- Open your IDE's extension view
- Search for "ULW"
- Click Install
Or visit the OpenVSX page.
- Clone the repository:
git clone https://github.com/islee23520/ulwcode.git
cd ulwcode- Install dependencies:
npm install- Build the extension:
npm run compile- Package the extension:
npx @vscode/vsce package- Install in VS Code:
- Open VS Code
- Go to Extensions (
Cmd+Shift+X/Ctrl+Shift+X) - Click "..." menu → "Install from VSIX"
- Select the generated
.vsixfile
- Click the ULW icon in the Activity Bar (sidebar) to open ULW Terminal Manager
- The ULW Terminal is available in the secondary sidebar
- With
ulw.autoStartOnOpenenabled, ULW starts your configured backend (plain shell / tmux / zellij) when the view opens - Run any CLI (including OpenCode) manually in that terminal
- Start ULW Terminal - Manually start the sidebar terminal session
- ULW Terminal: Paste - Paste text into the terminal
- Send File Reference (@file) (
Cmd+Alt+L/Ctrl+Alt+L) - Send current file with line numbers- No selection:
@filename - Single line:
@filename#L10 - Multiple lines:
@filename#L10-L20
- No selection:
- Send All Open File References (
Cmd+Alt+A/Ctrl+Alt+A) - Send all open file references - Send to OpenCode - Send selected text or file from context menu
- Send to Active Terminal - Send selected text to the active terminal
- Open Tmux Session in New Window - Open the current tmux session in a new VS Code window
- Spawn Tmux Session for Workspace - Create a new tmux session scoped to the current workspace
- Select OpenCode Tmux Session - Choose from a list of available tmux sessions
- Switch Tmux Session - Switch to a different tmux session
- Browse Tmux Sessions (
Cmd+Alt+T/Ctrl+Alt+T) - Browse and switch between tmux sessions - Switch to Native Shell - Toggle between OpenCode and a native shell
- Open ULW Terminal Manager - Open the ULW Terminal Manager view
- Switch to Pane - Switch focus to a specific tmux pane
- Split Pane Horizontal - Split the current pane horizontally
- Split Pane Vertical - Split the current pane vertically
- Split Pane with Command - Split the pane and run a specific command
- Send Text to Pane - Send text directly to a specific tmux pane
- Resize Pane - Adjust the size of the current tmux pane
- Swap Panes - Swap positions of two tmux panes
- Kill Pane - Close the current tmux pane
- Next Window - Switch to the next tmux window
- Previous Window - Switch to the previous tmux window
- Create Window - Create a new tmux window
- Select Window - Choose from available tmux windows
- Kill Window - Close the current tmux window
- Kill Session - Kill the current tmux session
- Refresh ULW Terminal Manager - Refresh ULW Terminal Manager
| Shortcut | Command | Context |
|---|---|---|
Cmd+Alt+L / Ctrl+Alt+L |
Send File Reference | Editor or Terminal |
Cmd+Alt+A / Ctrl+Alt+A |
Send All Open Files | Editor or Terminal |
Cmd+Alt+T / Ctrl+Alt+T |
Browse Tmux Sessions | Terminal focused |
Cmd+V / Ctrl+V |
Paste | Terminal focused |
Ctrl+P |
Quick Open (native) | Terminal focused (passthrough) |
- Explorer: Right-click any file or folder → "Send to OpenCode"
- Editor: Right-click anywhere → "Send File Reference (@file)"
- Hold Shift and drag files/folders to the terminal to send as
@filereferences
The ULW Terminal Manager view provides advanced tmux session and pane management directly within the VS Code sidebar:
- Session Discovery: Automatically detects existing tmux sessions on your system.
- Workspace Filtering: Filters sessions to show those relevant to your current workspace.
- Pane Controls: Inline buttons to split panes (horizontal/vertical), switch focus, resize, swap, and kill panes.
- Window Controls: Navigate, create, select, and kill tmux windows.
- Return to Workspace: A quick-access banner to navigate back to the active workspace session.
- Clean UI: The tmux status bar is automatically hidden within the sidebar terminal to maximize vertical space.
The extension communicates with OpenCode CLI via an HTTP API for reliable bidirectional communication:
- Auto-Discovery: Automatically discovers OpenCode CLI HTTP server port
- Health Checks: Validates OpenCode CLI availability before sending commands
- Retry Logic: Exponential backoff for reliable communication
- Context Sharing: Automatically shares editor context on terminal open
- When OpenCode starts, it launches an HTTP server on an ephemeral port (16384-65535)
- The extension discovers the port and establishes communication
- File references and context are sent via HTTP POST to
/tui/append-prompt - Health checks ensure OpenCode is ready before sending data
{
"ulw.enableHttpApi": true,
"ulw.httpTimeout": 5000,
"ulw.autoShareContext": true
}When enabled, the extension automatically shares editor context with OpenCode when the terminal opens:
- Open Files: Lists all currently open files
- Active Selection: Includes line numbers for selected text
- Format:
@path/to/file#L10-L20
This feature eliminates the need to manually share context when starting a new OpenCode session.
Available settings in VS Code settings (Cmd+, / Ctrl+,):
| Setting | Type | Default | Description |
|---|---|---|---|
ulw.autoStart |
boolean | true |
Automatically start OpenCode when the view is activated |
ulw.autoStartOnOpen |
boolean | true |
Automatically start OpenCode when sidebar is opened |
ulw.fontSize |
number | 14 |
Terminal font size in pixels (6-25) |
ulw.fontFamily |
string | Nerd Font stack* | Terminal font family |
ulw.cursorBlink |
boolean | true |
Enable cursor blinking |
ulw.cursorStyle |
string | "block" |
Cursor style: block, underline, or bar |
ulw.scrollback |
number | 10000 |
Maximum lines in scrollback buffer (0-100000) |
ulw.autoSwitchKoreanKeyboard |
boolean | false |
Auto-switch the macOS system input source when likely Korean/English layout mistakes are detected |
ulw.terminal.defaultLocation |
string | "editor" |
Default terminal location: editor or sidebar |
ulw.autoFocusOnSend |
boolean | true |
Auto-focus ULW after sending file references |
ulw.shellPath |
string | "" |
Custom shell path (empty = VS Code default) |
ulw.shellArgs |
array | [] |
Custom shell arguments |
* Default: 'JetBrainsMono Nerd Font', 'FiraCode Nerd Font', 'CascadiaCode NF', Menlo, monospace
| Setting | Type | Default | Description |
|---|---|---|---|
ulw.enableHttpApi |
boolean | true |
Enable HTTP API for OpenCode communication |
ulw.httpTimeout |
number | 5000 |
HTTP API request timeout in ms (1000-30000) |
ulw.autoShareContext |
boolean | true |
Auto-share editor context with OpenCode |
ulw.contextDebounceMs |
number | 500 |
Debounce delay for context updates (100-5000 ms) |
| Setting | Type | Default | Description |
|---|---|---|---|
ulw.terminalBackend |
string | "tmux" |
Terminal backend: native, tmux, or zellij (unavailable backends fall back to native) |
ulw.enableAutoSpawn |
boolean | false |
When enabled, discovery may spawn OpenCode in the background if no instance is found (does not affect sidebar terminal startup) |
ulw.showTmuxWindowControls |
boolean | true |
Show tmux session/window controls in the terminal toolbar |
| Setting | Type | Default | Description |
|---|---|---|---|
ulw.logLevel |
string | "info" |
Log level: debug, info, warn, error |
ulw.maxDiagnosticLength |
number | 500 |
Maximum length of diagnostic messages (100-2000) |
ulw.codeActionSeverities |
array | ["error", "warning"] |
Diagnostic severities that trigger code actions |
{
"ulw.autoStart": true,
"ulw.fontSize": 14,
"ulw.fontFamily": "'JetBrainsMono Nerd Font', monospace",
"ulw.cursorBlink": true,
"ulw.cursorStyle": "block",
"ulw.scrollback": 10000,
"ulw.enableHttpApi": true,
"ulw.httpTimeout": 5000,
"ulw.autoShareContext": true,
"ulw.terminalBackend": "tmux",
"ulw.enableAutoSpawn": false
}- VS Code 1.106.0 or higher
- Node.js 20.0.0 or higher
- Optional: OpenCode (or another AI CLI) if you use HTTP prompts, auto-context, or
ulw.enableAutoSpawn
npm run compile # Development build
npm run watch # Watch mode
npm run package # Production build
npm run test # Run tests
npm run test:watch # Watch mode tests
npm run test:coverage # Run tests with coverage
npm run lint # Lint source
npm run format # Format sourcesrc/
├── extension.ts # VS Code entry (activate/deactivate)
├── types.ts # Shared host↔webview message contracts
├── types.test.ts # Type contract tests
├── core/
│ ├── ExtensionLifecycle.ts # Service wiring + activation/deactivation
│ ├── ExtensionLifecycle.test.ts # Lifecycle tests
│ └── commands/ # Command registration
│ ├── index.ts # registerCommands() orchestrator
│ ├── terminalCommands.ts # start, restart, paste, file references
│ ├── tmuxSessionCommands.ts # session switch, create, spawn, browse
│ └── tmuxPaneCommands.ts # pane + window commands + QuickPick helpers
├── providers/
│ ├── TerminalProvider.ts # Main sidebar terminal webview provider
│ ├── TerminalProvider.test.ts # Provider tests
│ ├── TerminalDashboardProvider.ts # ULW Terminal Manager provider
│ ├── TerminalDashboardProvider.test.ts # Dashboard tests
│ ├── CodeActionProvider.ts # Diagnostic code action provider
│ ├── CodeActionProvider.test.ts # Code action tests
│ └── opencode/ # Terminal core modules
│ ├── OpenCodeMessageRouter.ts # Message dispatch + handlers
│ └── OpenCodeSessionRuntime.ts # Start/restart/tmux/instance switching
├── terminals/
│ └── TerminalManager.ts # node-pty process lifecycle
├── services/
│ ├── InstanceStore.ts # In-memory instance state + EventEmitter
│ ├── InstanceController.ts # Instance lifecycle orchestration
│ ├── InstanceDiscoveryService.ts # Running instance discovery + auto-spawn
│ ├── InstanceRegistry.ts # Instance persistence (globalState)
│ ├── ConnectionResolver.ts # 4-tier port resolution + client pool
│ ├── OpenCodeApiClient.ts # HTTP client (retry/backoff)
│ ├── PortManager.ts # Ephemeral port allocation
│ ├── TmuxSessionManager.ts # tmux CLI wrapper (sessions, panes, windows)
│ ├── ContextManager.ts # Active editor/selection observer
│ ├── ContextSharingService.ts # @file#L context formatter
│ ├── FileReferenceManager.ts # File reference serialization
│ ├── InstanceQuickPick.ts # Quick pick UI for instance selection
│ ├── OutputChannelService.ts # Singleton logging service
│ └── OutputCaptureManager.ts # Terminal output capture
├── webview/
│ ├── main.ts # Terminal webview (xterm.js + WebGL)
│ ├── terminal.html # Terminal webview HTML
│ ├── terminal.css # Terminal webview styles
│ ├── dashboard-manager.ts # Dashboard webview logic
│ ├── dashboard.html # Dashboard webview HTML
│ └── dashboard.css # Dashboard webview styles
├── utils/
│ └── PromptFormatter.ts # Prompt formatting utilities
├── test/
│ └── mocks/ # Manual vscode + node-pty mocks
└── __tests__/
└── setup.ts # Vitest global setup
Webpack 2 bundles: extension.js (node), webview.js (web)
Based on the vscode-sidebar-terminal extension, streamlined specifically for ULW Terminal:
- Terminal Backend: node-pty for PTY support
- Terminal Frontend: xterm.js with WebGL rendering
- Process Management: Automatic OpenCode lifecycle
- Communication: HTTP API + WebView messaging
- Port Management: Ephemeral port allocation (16384-65535)
MIT
- Based on vscode-sidebar-terminal by s-hiraoku
- Development assisted by Sisyphus from oh-my-opencode
- Uses xterm.js for terminal emulation
- Uses node-pty for PTY support