vde-monitor
v0.9.2
Published
Monitor tmux sessions with a web UI.
Readme
vde-monitor
Monitor tmux/WezTerm coding sessions from a browser with a single CLI. It is designed for Codex CLI / Claude Code workflows and optimized for quick checks and control from both desktop and mobile devices. Mobile application-grade UI/UX is a first-class goal, with touch-friendly controls and compact layouts prioritized for small screens.
Japanese version: README.ja.md
What you can do
- See active sessions in one place, with recent activity and status
- Open a session and send text, key input, or raw input to the pane
- Monitor terminal output in text mode (cross-platform)
- Use image mode on macOS terminals (when enabled)
- Track session/repo timeline and activity history across restarts
- Inspect Git diff/commits and keep repo-scoped notes while monitoring
- Launch Codex/Claude agents into tmux sessions
- Resume existing Codex/Claude sessions on a source pane and move context to another
vwworktree (when available) - Switch worktree context per session when reviewing timeline, diffs, commits, and files (
vde-worktree/vwrequired) - Open Usage Dashboard to monitor provider limits pace and billing trends
Main features
- Session List: grouped by repository/window with quick status checks, search/filter, and pin
- Session Detail: live screen view (text/image), timeline, notes, diff, commits, file navigator, worktree context switch, and input composer (text/keys/raw/image attachment)
- Timeline and context: state timeline, repo notes, git diff/commits, and file browsing
- Worktree context: inspect timeline/git/files against a selected worktree without leaving the session (
vde-worktree/vwrequired) - Agent operations: launch Codex/Claude, or resume/move an existing session into another worktree context
- Multi-pane monitoring: desktop-oriented Chat Grid for side-by-side pane tracking
- Mobile-first UI/UX: primary monitor/control flows are treated as first-class for phone browsers
- PWA push notifications: per-session notification toggle (default off) plus global config-level enable/disable
- Usage Dashboard: provider-level session/weekly pace plus token/USD billing summary
Requirements
- Node.js
22.12+ - tmux
2.0+or WezTerm withwezterm cli - Worktree integration requires
vde-worktreeCLI (vw) and is unavailable whenvwsnapshot cannot be resolved - macOS-only features (image capture / pane focus) require
osascript - On macOS, Screen Recording and Accessibility permissions may be required
Install
npx vde-monitor@latestor install globally:
npm install -g vde-monitorQuick start
Run one of the following:
# Local access only (default)
npx vde-monitor@latest
# Expose on trusted private LAN (bind to 0.0.0.0)
npx vde-monitor@latest --public
# Access from Tailscale devices (prints Tailscale URL)
npx vde-monitor@latest --tailscaleStartup prints a URL like:
vde-monitor: http://localhost:11080/#token=...Open the URL in your browser. When terminal height allows, a QR code is also printed for quick access from another device.
First 5 minutes
- Open the session list and choose the pane you want to monitor.
- In session detail, confirm live output in the screen panel.
- Send input from the composer:
- text input
- key input
- raw input
- Use timeline, notes, diff, and commits tabs to inspect progress in context.
UI workflows
Session Detail (single-session deep dive)
- Desktop layout: Screen + Notes on the left, Diff / Files / Commits / Worktree panels on the right.
- Mobile layout: the same sections are available via section tabs under the screen panel.
- Typical use:
- Monitor the current terminal state in the screen panel.
- Capture decisions and TODOs in Notes while reviewing.
- Validate changes through Diff and Commits, then inspect source files in File Navigator.
- Switch Worktree context to compare another branch/worktree view without leaving the session.
- Send follow-up prompts with text/keys/raw, and attach an image when needed.
Chat Grid (parallel monitoring)
- Track multiple panes side by side in one board.
- Use candidate selection to add/remove monitored panes quickly.
- Refresh all tiles and send inputs per tile to compare multi-agent progress in real time.
- Useful when running parallel experiments or reviewing several repos/windows at once.
Usage Dashboard (capacity and cost checks)
- Compare Codex and Claude provider snapshots in one view.
- Use Global State Timeline (range + compact mode) to identify waiting-heavy periods.
- Review issues/warnings surfaced by providers, then jump back to Session List for action.
- Useful for deciding when to rebalance active sessions or reduce costly runs.
Mobile device usage
Recommended access methods:
- SSH port-forward
- Tailscale
- Private LAN only
Typical flow:
- Start
npx vde-monitor@lateston your host machine. - Expose the printed URL safely:
--tailscaleis recommended when available--publiconly on trusted networks
- Open the URL on your mobile device and control sessions from
SessionDetail.
For Tailscale HTTPS access:
- Start with Tailscale + HTTPS mode (example):
npx vde-monitor@latest --tailscale --https. - On startup, answer
Run tailscale serve now? [y/N].y/yes: runstailscale serve --bg <printed-web-port>automatically.- default
N: skips auto setup and prints manual recovery command.
- If existing
tailscale servesettings are already present, vde-monitor does not overwrite them and prints guidance instead. - Open
https://<device>.<tailnet>.ts.net/#token=...(not the plainhttp://100.x.x.x/...URL). - Verify with
tailscale serve status.
Notes for iOS:
- Web Push on iOS requires an installed Home Screen web app (standalone PWA mode).
- In regular Safari tabs on iOS, the session notification toggle is hidden.
Useful commands
Start server
npx vde-monitor@latest [options]Common options:
--port <port> API/UI port
--public Bind to 0.0.0.0
--tailscale Use Tailscale IP for access URL
--https Enable Tailscale HTTPS guidance/QR (effective with `--tailscale`)
--bind <ip> Bind to specific IPv4
--multiplexer <name> `tmux` or `wezterm`
--backend <name> image backend (`alacritty`, `terminal`, `iterm`, `wezterm`, `ghostty`)Advanced options:
--web-port <port> Override displayed web port in URL
--wezterm-cli <path> wezterm binary path (default: `wezterm`)
--wezterm-target <t> wezterm target (`auto` or explicit target)
--socket-name <name> tmux socket name
--socket-path <path> tmux socket pathNotes:
--bindcannot be combined with--tailscale--bindtakes priority over--public--tailscalerequires a resolvable Tailscale IP--tailscalewithout--publicbinds to the Tailscale IP--public --tailscalebinds to0.0.0.0and prints a Tailscale URL--httpsonly takes effect when used with--tailscale(otherwise standard HTTP guidance is shown)--tailscale --httpsasks before auto-runningtailscale serve --bg <port>(defaultN)- Existing
tailscale servesettings are never auto-overwritten - For HTTPS on Tailscale, use
tailscale serveortailscale funnel; plain Tailscale IP HTTP is not HTTPS
Utility commands
npx vde-monitor@latest config init
npx vde-monitor@latest config regenerate
npx vde-monitor@latest config check
npx vde-monitor@latest config prune
npx vde-monitor@latest config prune --dry-run
npx vde-monitor@latest token rotate
npx vde-monitor@latest claude hooks print
npx --package vde-monitor@latest vde-monitor-hook <HookEventName>config init: create initial generated config only when no global config file existsconfig regenerate: overwrite existing global config with regenerated required templateconfig check: validate global config (parse/schema/required generated keys/unused keys)config prune: remove unused keys from global config and rewrite asconfig.yml(YAML)config prune --dry-run: show removable keys without updating files
Configuration
Global config file:
$XDG_CONFIG_HOME/vde/monitor/config.yml- fallback:
~/.config/vde/monitor/config.yml
Priority:
CLI args > global config > defaults
Global config file discovery order:
config.yml > config.yaml > config.json
Auto-generated required settings (config.yml):
| Key | Default | Meaning |
| ------------------------------ | --------------------------- | ----------------------------------------------------------------------------------- |
| multiplexer.backend | tmux | Multiplexer backend (tmux or wezterm) |
| screen.image.backend | terminal | Image capture backend on macOS (alacritty/terminal/iterm/wezterm/ghostty) |
| dangerKeys | ["C-c","C-d","C-z"] | Blocked danger keys |
| dangerCommandPatterns | existing default regex list | Regex list for dangerous command detection |
| launch.agents.codex.options | [] | Default options for Codex launch |
| launch.agents.claude.options | [] | Default options for Claude launch |
| workspaceTabs.displayMode | all | Mobile workspace tabs display mode (all/pwa/none) |
Configurable but optional settings (if omitted, runtime defaults are used):
| Key | Default |
| ---------------------------------------- | --------------------------------------------------- |
| bind | 127.0.0.1 |
| port | 11080 |
| allowedOrigins | [] |
| activity.pollIntervalMs | 1000 |
| activity.runningThresholdMs | 5000 |
| screen.maxLines | 2000 |
| screen.highlightCorrection.codex | true |
| screen.highlightCorrection.claude | true |
| multiplexer.wezterm.cliPath | wezterm |
| multiplexer.wezterm.target | auto |
| notifications.pushEnabled | true |
| notifications.enabledEventTypes | ["pane.waiting_permission","pane.task_completed"] |
| usage.session.providers.codex.enabled | true |
| usage.session.providers.claude.enabled | true |
| usage.pricing.providers.codex.enabled | true |
| usage.pricing.providers.claude.enabled | true |
| fileNavigator.includeIgnoredPaths | [] |
| fileNavigator.autoExpandMatchLimit | 100 |
| tmux.socketName | null |
| tmux.socketPath | null |
| tmux.primaryClient | null |
Notes:
config check/config prunetarget global config only.config checkexits with code1when any issue is found (including unused keys).config prunewrites YAML toconfig.yml; when source isconfig.json, it is removed after successful write.- Project-local config (
<repo-root>/.vde/monitor/config.*) is no longer loaded. Move required values to global config.
Platform behavior
- Text screen capture works cross-platform
- Image capture is macOS-only
- Pane focus integration is macOS-only
Runtime data paths
- Token:
~/.vde-monitor/token.json - Session/timeline persistence:
~/.vde-monitor/state.json - Push VAPID keys:
~/.vde-monitor/push-vapid.json - Push subscriptions:
~/.vde-monitor/notifications.json - Hook event logs:
~/.vde-monitor/events/<server-key>/claude.jsonl - Uploaded image attachments:
$TMPDIR/vde-monitor/attachments/<encoded-pane-id>/...
Security defaults
- Bearer token auth is required for API access
- Default bind host is loopback (
127.0.0.1) --publicis opt-in- Optional origin restriction via
allowedOrigins
Development
Install:
pnpm install --frozen-lockfileRun local development:
pnpm dev
pnpm dev:server
pnpm dev:web
pnpm dev:publicQuality checks:
pnpm run ci
pnpm run ci:diff
pnpm run ci:fix
pnpm test
pnpm test:runBuild package:
pnpm buildpnpm build assembles npm-ready artifacts in dist/, including CLI entry files and web assets.
To rebuild dist/ continuously while editing:
pnpm run build:watchTroubleshooting
- No sessions appear:
- confirm tmux/WezTerm is running
- verify socket/target options (
--socket-name,--socket-path,--multiplexer)
- URL opens but API fails:
- check token in URL hash (
#token=...) - rotate token with
npx vde-monitor@latest token rotate
- check token in URL hash (
- Mobile device cannot connect:
- re-check network path (SSH forward / Tailscale / LAN)
- avoid exposing to public internet without hardening
