No description
Find a file
Peter Steinberger f8a7cf9537
Add file-based quick start configuration and remove WebSocket sync (#436)
* feat(server): add configuration service with file-based persistence

- Implement ConfigService for managing application configurations
- Add REST API endpoints for quick start configuration
- Add comprehensive test coverage for config operations
- Define TypeScript types for configuration structures
- Replace WebSocket-based config sync with REST API

* feat(web): add quick start editor component

- Create fully-featured command editor with add, edit, delete functionality
- Add drag-and-drop reordering support
- Implement real-time validation and error handling
- Include comprehensive test coverage (100%)
- Support keyboard navigation and accessibility

* feat(web): add session status management

- Create session status dropdown component for state management
- Add session termination capabilities with proper cleanup
- Refactor session header to integrate status controls
- Support graceful disconnection and reconnection

* feat(mac): add directory autocomplete service

- Implement AutocompleteService for directory path completion
- Create AutocompleteView with native macOS UI
- Support home directory expansion (~/)
- Add system file browser integration
- Optimize performance for large directory structures

* feat(mac): add quick start settings interface

- Create SwiftUI settings view for managing quick start commands
- Implement inline editing with immediate feedback
- Add default commands for common workflows
- Include toggle for using current directory as default
- Add smooth animations and hover effects

* feat: integrate quick start in session creation

- Add quick start command buttons to session create form
- Implement directory picker with autocomplete support
- Update form layout for better user experience
- Add comprehensive tests for new functionality
- Sync quick start integration across web and native

* feat(web): add repository discovery to settings

- Add repository discovery functionality in unified settings
- Update settings UI to support new configuration options
- Remove WebSocket-based configuration sync
- Simplify settings component with REST API integration

* docs: add macOS quick start implementation guide

- Document architecture and implementation details
- Include code examples and best practices
- Explain integration between web and native components
- Provide troubleshooting guidance

* feat: enhance UI/UX across components

- Improve session list with better status indicators
- Update terminal binary detection and display
- Refine width selector and image upload interactions
- Clean up WebSocket control handler
- Update server configuration handling
- Fix notification status display
- Polish settings view layout

* feat(web): improve session header UI elements

- Position edit icon directly after text instead of far right
- Update magic wand icon with sparkles to match macOS design
- Change from grid to flex layout for better icon positioning
- Enhance visual consistency across platforms

* fix(web): improve OPTIONS label alignment in session create form

- Add flex-shrink-0 to chevron icon to prevent shrinking
- Add leading-none to OPTIONS label for better vertical alignment

* docs: update changelog for beta.14 with Quick Start features

- Document Quick Start Configuration System (#229, #250, #436)
- Add native macOS settings interface details
- Include session management improvements
- Add bug fixes and breaking changes
- Reference related issues and PRs

* feat(mac): add ConfigManager for synchronized quick start commands

- Create ConfigManager to sync commands with web UI config file
- Monitor ~/.vibetunnel/config.json for changes
- Replace UserDefaults with file-based configuration
- Ensure consistency between Mac app and web interface

* feat(mac): add ClickableURLView component

- Create reusable component for clickable URLs in SwiftUI
- Support for opening URLs in default browser
- Consistent styling across the app

* refactor(mac): simplify remote access settings UI

- Use ClickableURLView for consistent URL display
- Reduce code duplication in settings sections
- Improve maintainability of remote access views

* refactor(mac): integrate ConfigManager in NewSessionForm

- Replace direct UserDefaults access with ConfigManager
- Use synchronized quick start commands from shared config
- Improve command selection UI consistency

* fix(web): update terminal padding and termination handling

- Remove horizontal padding from terminal containers
- Implement proper session termination via DELETE API
- Keep vertical padding for better visual appearance
- Fix binary mode toggle styling

* fix(mac): resolve ConfigManager threading crash

- Fix main actor violation in file monitor callback
- Remove unsafe self reference in asyncAfter closure
- Capture monitor queue reference to avoid accessing self
- Ensure all @Published property updates happen on main thread

* feat(web): add reset to defaults button in quick start editor

- Add Reset to Defaults button for easy restoration
- Import DEFAULT_QUICK_START_COMMANDS from config types
- Improve user experience with quick command reset option

* fix(web): adjust OPTIONS chevron icon size

- Reduce chevron icon from 10x10 to 8x8 for better visual balance
- Update responsive size classes accordingly
- Remove leading-none from OPTIONS label for better alignment

* docs: update changelog with latest UI improvements and bug fixes

- Document ConfigManager and ClickableURLView additions
- Add AutocompleteService and reset to defaults features
- Include all UI fixes and threading crash resolution
- Document session header and terminal improvements

* fix(mac): fix ConfigManager threading crash when moving quick start items

- Remove background file monitor queue and use main queue directly
- ConfigManager is @MainActor so all operations must happen on main thread
- Simplify file monitor callback by removing unnecessary Task wrapper
- Fixes crash when reordering quick start commands in settings

* feat: add Zod validation for quick start configuration

- Add Zod dependency for runtime config validation
- Implement ConfigSchema to validate quick start commands
- Ensure commands have non-empty strings and valid structure
- Add validation on config load and update operations
- Fix auth headers for config API endpoints
- Remove unused repository path WebSocket handlers
- Update storage key for consistency

This improves config reliability and prevents invalid commands from being saved.

* docs: update changelog with comprehensive beta.14 release notes

- Reorganize changelog with clear user-focused sections
- Add detailed feature descriptions for Quick Start functionality
- Highlight UI/UX improvements with specific examples
- Document all bug fixes and stability improvements
- Include breaking changes and migration guidance
- Add emojis for better visual organization
- Expand technical details for developers

* fix: handle undefined activityStatus in session categorization

Sessions with undefined activityStatus were incorrectly shown as idle.
Now only sessions with explicitly false isActive are considered idle.

* feat: enhance quick start configuration with repository discovery

- Add repository discovery and filtering in AutocompleteService
- Support directory-only suggestions for quick start paths
- Improve autocomplete filtering to exclude hidden and system directories
- Update quick start settings UI with better directory selection
- Add tests for vibe-terminal-binary component
- Minor UI improvements to clickable URLs and form components

* fix: update tests for storage key change and terminal sizing

- Update repository-service tests to use new 'app_preferences' storage key
- Fix vibe-terminal-binary test to enable fitHorizontally for maxCols constraint
- Ensure tests align with recent configuration changes

* fix: update failing tests and improve repository status element

- Add id="repository-status" to repository counter for easier test selection
- Update quick-start-editor test to match actual button classes
- Fix all unified-settings tests to use the new repository-status ID
- Prevent tests from accidentally selecting unrelated elements

* docs: update beta 14 changelog to match earlier style

Simplified changelog format to be consistent with beta 13 and earlier versions,
making it more concise and easier to read.

* feat: add IDs to quick-start-editor elements for better testability

- Add id="quick-start-edit-button" to Edit button
- Add id="quick-start-save-button" to Save button
- Add id="quick-start-cancel-button" to Cancel button
- Add id="quick-start-reset-button" to Reset to Defaults button
- Add id="quick-start-add-command-button" to Add Command button
- Add dynamic IDs for remove buttons: quick-start-remove-command-{index}
- Add dynamic IDs for inputs: quick-start-name-input-{index}, quick-start-command-input-{index}
- Add dynamic IDs for command items: quick-start-command-item-{index}

This makes tests more maintainable by avoiding complex selectors that search by text content.

* test: update quick-start-editor tests to use element IDs

- Replace button text search with ID selectors for better reliability
- Update edit button selector to use #quick-start-edit-button
- Update add command button selector to use #quick-start-add-command-button
- Update reset button selectors to use #quick-start-reset-button

This demonstrates how the new IDs make tests more maintainable and less fragile.

* docs: rewrite beta 14 changelog with accurate feature descriptions

- Clarify that Quick Start commands became customizable (not new)
- Add accurate description of session status management dropdown
- Include proper technical details about systemd support
- Fix misleading descriptions about features
- Maintain concise style consistent with previous releases

* fix: remove obsolete tests and fix control-unix-handler tests

- Remove obsolete repository-path-sync.test.ts that was testing removed functionality
- Remove skipped session-view-drag-drop.test.ts that was causing import errors
- Fix control-unix-handler tests to test actual functionality instead of non-existent methods
- All tests now passing (1008 passed, 113 skipped)

* docs: update beta 14 contributors section

- Add Gopi as first-time contributor for ngrok clickable URLs (#422)
- Properly credit hewigovens and Claude as co-authors on systemd (#426)
- Remove duplicate first-time attribution for hewigovens

* docs: fix Claude contributor GitHub link to @claudemini

* docs: fix claudemini's contribution attribution

- claudemini improved theme toggle UI (PR #429/#438), not systemd
- List them as first-time contributor
- Keep Claude AI assistant as systemd co-author

* docs: remove incorrect AI assistant attribution

- There was no AI assistant Claude that co-authored systemd
- Keep only the correct contributors: 2 first-time and 1 additional

* fix: apply linter fixes for CI

- Fix optional chaining in test mock
- Fix unused parameters with underscore prefix
- Format quick-start-editor test file
- Keep any types in test file (acceptable for tests)

* fix: remove all any type warnings in tests

- Use proper ControlUnixHandler type import
- Type vi.importMock with typeof import('net')
- Type WebSocket mock with proper import type
- All lint warnings now resolved

* docs: add image upload feature to changelog

- Added image upload menu feature (#432)
- Also added theme toggle improvement (#438) that was missing

* refactor: add element IDs for improved test maintainability

- Added descriptive IDs to interactive elements across components
- Updated tests to use ID selectors instead of text-based queries
- Enhanced documentation with ID naming best practices
- Makes tests more reliable and less brittle to text changes

* fix: correct session-list test expectation for hideExited toggle

The component emits an event but doesn't directly change its state - the parent handles the state update

* docs: add more PR/issue references to beta 14 changelog

- Added fixes #368 for theme toggle improvement
- Added duplicate reference #421 for Chinese input issue #431
- All PR and issue references now properly documented

* fix: SwiftFormat modifier order and SystemControlHandler test race condition

* fix: repository scanner not showing discovered repositories

- Fixed storage key mismatch between 'app_preferences' and 'vibetunnel_app_preferences'
- Added missing authClient prop to unified-settings component in app.ts
- Updated all test files to use the correct storage key
- Repository scanner now correctly displays discovered repositories count

* refactor: extract session termination logic into reusable helper

- Create session-actions.ts utility for common session operations
- Refactor handleTerminateSession to use the new helper
- Fix handleClearSession to properly delete exited sessions before navigation
- Move Git branch indicator to header next to path in file browser
- Fix Options label alignment in session create form

* refactor: migrate repository base path from CLI arg to config.json

- Remove --repository-base-path command line argument
- Add repositoryBasePath to VibeTunnelConfig type and schema
- Update server to read/write repository path from config.json
- Refactor client to use ServerConfigService for repository path
- Update settings UI to manage path through server config API
- Ensure consistent naming with macOS app implementation

This simplifies configuration by using config.json as the single source
of truth for repository base path, with automatic file watching for
real-time updates.

* docs: remove --repository-base-path from README

This option was removed in the previous commit as repository base path
is now configured via config.json instead of command line arguments.

* fix: reduce Logs button border contrast and add comprehensive drag & drop tests

- Changed border opacity from 100% to 30% for softer appearance
- Created drag & drop tests with 21 passing tests covering:
  - Drag over/leave functionality
  - Drop handling for single and multiple files
  - Paste functionality with various UI states
  - Error handling and edge cases
- Fixed TypeScript lint errors in test files
- Disabled 2 visual overlay tests due to shadow DOM limitations in test environment

* fix: auto-format session-action-service.ts to pass CI checks

* fix: update tests to match refactored session action service implementation

- Fixed repository service tests by adding mock serverConfigService
- Updated session-card tests to expect DELETE endpoint instead of /cleanup
- Corrected error message expectations in session-card tests
- Fixed quick-start-editor test button class expectations
- Auto-formatted all files to pass CI checks

* fix: update session-action-service tests with proper mocks and window handling

- Added @vitest-environment happy-dom directive for DOM testing
- Set up proper mock for terminateSession to return success: true
- Mock window.dispatchEvent to prevent errors in test environment
- Fixed all test expectations to match refactored implementation

* fix: update server config tests to match refactored API implementation

- Updated config route tests to match new implementation that always returns serverConfigured: true
- Fixed error messages to match 'No valid updates provided' instead of 'Invalid quick start commands'
- Removed dependency on getRepositoryBasePath function, now using configService.repositoryBasePath
- Added tests for repository base path updates via PUT /api/config
- Added test for updating both repository path and quick start commands together

* fix: resolve remaining CI issues with type assertions and import ordering

* fix: update remaining tests and clean up imports

- Fix repository service test to include serverConfigService
- Update session card test error expectations
- Fix quick start editor button class tests
- Add proper mock setup for session action service
- Update server config tests for refactored API
- Clean up type assertions and import ordering

* fix: correct undefined runningSessions variable reference in Kill All button

The Kill All button was referencing a non-existent runningSessions variable after refactoring split it into activeSessions and idleSessions. Fixed by using the locally defined runningSessions variable in renderExitedControls() method.

* fix: improve Quick Start settings UI styling

- Use tertiaryLabelColor for better visual hierarchy
- Adjust opacity values for improved contrast
- Remove redundant "Quick Start" header

* fix: ensure thread safety in SystemControlHandlerTests

- Wrap notification flag updates in MainActor tasks
- Ensure test assertions run on MainActor
- Fixes potential race conditions in async tests

* fix: correct SwiftFormat modifier order in VibeTunnelApp

- Change 'weak static' to 'static weak' to match SwiftFormat rules
- Fixes CI linting failure

* fix: resolve Swift 6 concurrency errors in SystemControlHandlerTests

- Wrap MainActor property mutations in Task blocks for notification observers
- Fix test expectations to match actual path handling behavior
- SystemControlHandler stores paths as-is without tilde conversion

The CI failures were due to Swift 6's stricter concurrency checking
which prevented mutating MainActor-isolated properties from Sendable
closures. Also corrected the test expectation - the handler doesn't
convert paths to tilde notation, that only happens in UI components.

* fix: revert to correct SwiftFormat modifier order

- SwiftFormat expects 'weak static', not 'static weak'
- Fixes CI formatting check failure

* chore: trigger CI rebuild

* fix: resolve remaining CI issues with type assertions and import ordering

- Disable AppleScript tests on CI environment (not available in headless mode)
- Make SystemControlHandlerTests more robust with proper synchronization
- Add better error messages for test failures
- Fix exit code 126 issues by handling server startup failures gracefully

* Remove repository base path CLI argument from BunServer

- Server now reads repository base path directly from config.json
- Updated NewSessionForm to use ConfigManager for repository path
- Updated GeneralSettingsView to use ConfigManager instead of @AppStorage
- Updated ProjectFolderPageView to use ConfigManager
- Removed --repository-base-path CLI argument from BunServer
- RepositoryPathSyncService already updated to use ConfigManager

* Update tests to use ConfigManager and add CI diagnostics

- Updated RepositoryPathSyncServiceTests to use ConfigManager instead of UserDefaults
- Added diagnostic logging in BunServer for CI debugging when binary is not found
- Updated GitHub Actions workflows

* fix: simplify Mac CI by removing web artifact caching

- Remove web artifact download/upload between Node.js and Mac CI workflows
- Mac CI now builds web components directly via Xcode build process
- Eliminates file permission issues with artifact transfers
- Workflows can now run in parallel for faster CI
- Add better diagnostics for missing binary errors in BunServer

* fix: make tests properly fail when server binary is not available

- Update ServerManagerTests to require server binary presence
- Tests now fail with clear error if vibetunnel binary is missing
- Remove fallback logic that allowed tests to pass without binary
- ServerBinaryAvailableCondition now only checks app Resources folder

The server binary must be properly embedded in the Mac app's Resources
folder. Tests should not pass if the binary is missing, as this would
indicate a broken build.

* Refactor code to reduce duplication and improve structure

- Use AppConstants.getPreferredGitApp() instead of direct UserDefaults access
- Add getDashboardAccessMode() and setDashboardAccessMode() helpers to AppConstants
- Create GitAppHelper utility to centralize Git app preference logic
- Simplify GitRepositoryRow and SessionRow to use GitAppHelper
- Keep ConfigManager focused on server-needed config (quickStartCommands, repositoryBasePath)
- Mac-specific settings remain in UserDefaults with improved access patterns

* Move configuration enums to shared location

- Create ConfigurationEnums.swift with AuthenticationMode and TitleMode
- Remove duplicate enum definitions from UI files
- Fix ConfigManager to use correct enum case names (.osAuth instead of .os)
- Add description property to AuthenticationMode for UI display
- Proper separation of shared types from UI-specific code
2025-07-21 14:03:33 +02:00
.claude Merge PR #391: Add comprehensive vt command tests 2025-07-17 13:16:16 +02:00
.github Add file-based quick start configuration and remove WebSocket sync (#436) 2025-07-21 14:03:33 +02:00
.husky Add husky pre-commit hooks for code quality enforcement (#157) 2025-07-01 03:49:00 +01:00
apple Terminal theme improvements (#332) 2025-07-12 22:11:30 +02:00
assets chore: update banner.png with smaller file from parent directory 2025-07-20 12:28:12 +02:00
docs Improve changelog contributor attribution and management 2025-07-20 11:47:36 +02:00
ios Add Mintlify documentation configuration (#403) 2025-07-18 08:37:16 +02:00
mac Add file-based quick start configuration and remove WebSocket sync (#436) 2025-07-21 14:03:33 +02:00
scripts Add Mintlify documentation configuration (#403) 2025-07-18 08:37:16 +02:00
VibeTunnel.xcworkspace Add Mac test plan 2025-06-23 17:26:45 +02:00
web Add file-based quick start configuration and remove WebSocket sync (#436) 2025-07-21 14:03:33 +02:00
.dockerignore feat(tauri): Implement full feature parity with Mac app (#213) 2025-07-04 04:52:00 +01:00
.gitattributes Add .gitattributes to normalize line endings to LF 2025-06-19 17:44:30 +02:00
.gitignore Add opencode support to vibetunnel 2025-07-20 12:38:22 +02:00
.mcp.json Add Playwright MCP as project config 2025-06-28 15:22:05 +02:00
appcast-prerelease.xml Update appcast for v1.0.0-beta.13 2025-07-19 02:13:14 +02:00
appcast.xml Update appcast for 1.0-beta.1 2025-06-17 03:09:23 +02:00
CHANGELOG.md Add file-based quick start configuration and remove WebSocket sync (#436) 2025-07-21 14:03:33 +02:00
CLAUDE.md feat: Unified autocomplete for working directory in session creation (#435) 2025-07-20 21:11:21 +02:00
docs.json Fix Mintlify documentation generation (#434) 2025-07-20 17:52:33 +02:00
GEMINI.md Unified control protocol and deferred screen recording permissions (#239) 2025-07-08 00:42:13 +01:00
introduction.mdx Clean up and improve documentation across the project 2025-07-19 03:01:48 +02:00
LICENSE Initial commit 2025-06-15 19:56:11 +02:00
OpenCode.md Add opencode support to vibetunnel 2025-07-20 12:38:22 +02:00
README.md fix: remove redundant header text and horizontal line 2025-07-20 12:26:09 +02:00

VibeTunnel Banner

Turn any browser into your Mac terminal.
VibeTunnel proxies your terminals right into the browser, so you can vibe-code anywhere.

Download npm version Homebrew Node.js 20+ Discord Twitter

Linux Support License macOS 14.0+ Apple Silicon Support us on Polar Ask DeepWiki

DocumentationReleasesDiscordTwitter

Table of Contents

Why VibeTunnel?

Ever wanted to check on your AI agents while you're away? Need to monitor that long-running build from your phone? Want to share a terminal session with a colleague without complex SSH setups? VibeTunnel makes it happen with zero friction.

Installation Options

The native macOS app provides the best experience with menu bar integration and automatic updates.

npm Package (Linux & Headless Systems)

For Linux servers, Docker containers, or headless macOS systems, install via npm:

npm install -g vibetunnel

This gives you the full VibeTunnel server with web UI, just without the macOS menu bar app. See the npm Package section for detailed usage.

Quick Start

Requirements

macOS App: Requires an Apple Silicon Mac (M1+). Intel Macs are not supported for the native app.

npm Package: Works on any system with Node.js 20+, including Intel Macs and Linux. Windows is not yet supported (#252).

1. Download & Install

Option 1: Direct Download

Download VibeTunnel and drag it to your Applications folder.

Option 2: Homebrew

brew install --cask vibetunnel

2. Launch VibeTunnel

VibeTunnel lives in your menu bar. Click the icon to start the server.

3. Use the vt Command

The vt command is a smart wrapper that forwards your terminal sessions through VibeTunnel:

How it works:

  • vt is a bash script that internally calls vibetunnel fwd to forward terminal output
  • It provides additional features like shell alias resolution and session title management
  • Available from both the Mac app and npm package installations

Installation sources:

  • macOS App: Creates /usr/local/bin/vt symlink during installation
  • npm Package: Installs vt globally, with intelligent Mac app detection

Smart detection: When you run vt from the npm package, it:

  1. Checks if the Mac app is installed at /Applications/VibeTunnel.app
  2. If found, forwards to the Mac app's vt for the best experience
  3. If not found, uses the npm-installed vibetunnel fwd
  4. This ensures vt always uses the best available implementation
# Run any command in the browser
vt pnpm run dev
vt npm test
vt python script.py

# Monitor AI agents with automatic activity tracking
vt claude --dangerously-skip-permissions
vt --title-mode dynamic claude    # See real-time Claude status

# Use your shell aliases
vt gs              # Your 'git status' alias works!
vt claude-danger   # Custom aliases are resolved

# Open an interactive shell
vt --shell         # or vt -i

# For more examples and options, see "The vt Forwarding Command" section below

Git Repository Scanning on First Session

When opening a new session for the first time, VibeTunnel's working directory scanner will look for Git repositories. By default, this scans your home directory, which may trigger macOS permission prompts for accessing protected folders (like Desktop, Documents, Downloads, iCloud Drive, or external volumes).

To avoid these prompts:

  • Option 1: Navigate to your actual projects directory before opening a session
  • Option 2: Accept the one-time permission prompts (they won't appear again)

This only happens on the first session when the scanner discovers your Git repositories. For more details about macOS privacy-protected folders, see this explanation.

4. Open Your Dashboard

Visit http://localhost:4020 to see all your terminal sessions.

Features

  • 🌐 Browser-Based Access - Control your Mac terminal from any device with a web browser
  • 🚀 Zero Configuration - No SSH keys, no port forwarding, no complexity
  • 🤖 AI Agent Friendly - Perfect for monitoring Claude Code, ChatGPT, or any terminal-based AI tools
  • 📊 Dynamic Terminal Titles - Real-time activity tracking shows what's happening in each session
  • ⌨️ Smart Keyboard Handling - Intelligent shortcut routing with toggleable capture modes
  • 🔒 Secure by Design - Multiple authentication modes, localhost-only mode, or secure tunneling via Tailscale/ngrok
  • 📱 Mobile Ready - Native iOS app and responsive web interface for phones and tablets
  • 🎬 Session Recording - All sessions recorded in asciinema format for later playback
  • High Performance - Optimized Node.js server with minimal resource usage
  • 🍎 Apple Silicon Native - Optimized for Apple Silicon (M1+) Macs with ARM64-only binaries
  • 🐚 Shell Alias Support - Your custom aliases and shell functions work automatically

Note

: The iOS app is still work in progress and not recommended for production use yet.

Architecture

VibeTunnel consists of three main components:

  1. macOS Menu Bar App - Native Swift application that manages the server lifecycle
  2. Node.js Server - High-performance TypeScript server handling terminal sessions
  3. Web Frontend - Modern web interface using Lit components and xterm.js

The server runs as a standalone Node.js executable with embedded modules, providing excellent performance and minimal resource usage.

Remote Access Options

Tailscale creates a secure peer-to-peer VPN network between your devices. It's the most secure option as traffic stays within your private network without exposing VibeTunnel to the public internet.

How it works: Tailscale creates an encrypted WireGuard tunnel between your devices, allowing them to communicate as if they were on the same local network, regardless of their physical location.

Setup Guide:

  1. Install Tailscale on your Mac: Download from Mac App Store or Direct Download
  2. Install Tailscale on your remote device:
  3. Sign in to both devices with the same account
  4. Find your Mac's Tailscale hostname in the Tailscale menu bar app (e.g., my-mac.tailnet-name.ts.net)
  5. Access VibeTunnel at http://[your-tailscale-hostname]:4020

Benefits:

  • End-to-end encrypted traffic
  • No public internet exposure
  • Works behind NAT and firewalls
  • Zero configuration after initial setup

Option 2: ngrok

ngrok creates secure tunnels to your localhost, making VibeTunnel accessible via a public URL. Perfect for quick sharing or temporary access.

How it works: ngrok establishes a secure tunnel from a public endpoint to your local VibeTunnel server, handling SSL/TLS encryption and providing a unique URL for access.

Setup Guide:

  1. Create a free ngrok account: Sign up for ngrok
  2. Copy your auth token from the ngrok dashboard
  3. Add the token in VibeTunnel settings (Settings → Remote Access → ngrok)
  4. Enable ngrok tunneling in VibeTunnel
  5. Share the generated https://[random].ngrok-free.app URL

Benefits:

  • Public HTTPS URL with SSL certificate
  • No firewall configuration needed
  • Built-in request inspection and replay
  • Custom domains available (paid plans)

Note: Free ngrok URLs change each time you restart the tunnel. You can claim one free static domain per user, or upgrade to a paid plan for multiple domains.

Option 3: Local Network

  1. Configure authentication (see Authentication section)
  2. Switch to "Network" mode
  3. Access via http://[your-mac-ip]:4020

Option 4: Cloudflare Quick Tunnel

  1. Install cloudflared
  2. Run cloudflared tunnel --url http://localhost:4020
  3. Access via the generated *.trycloudflare.com URL

Terminal Title Management

VibeTunnel provides intelligent terminal title management to help you track what's happening in each session:

Title Modes

  • Dynamic Mode (default for web UI): Shows working directory, command, and real-time activity

    • Generic activity: ~/projects — npm — •
    • Claude status: ~/projects — claude — ✻ Crafting (45s, ↑2.1k)
  • Static Mode: Shows working directory and command

    • Example: ~/projects/app — npm run dev
  • Filter Mode: Blocks all title changes from applications

    • Useful when you have your own terminal management system
  • None Mode: No title management - applications control their own titles

Activity Detection

Dynamic mode includes real-time activity detection:

  • Shows when there's terminal output within 5 seconds
  • Claude commands show specific status (Crafting, Transitioning, etc.)
  • Extensible system for future app-specific detectors

Authentication

VibeTunnel provides multiple authentication modes to secure your terminal sessions:

Authentication Modes

1. System Authentication (Default)

Uses your operating system's native authentication:

  • macOS: Authenticates against local user accounts
  • Linux: Uses PAM (Pluggable Authentication Modules)
  • Login with your system username and password

2. Environment Variable Authentication

Simple authentication for deployments:

export VIBETUNNEL_USERNAME=admin
export VIBETUNNEL_PASSWORD=your-secure-password
npm run start

3. SSH Key Authentication

Use Ed25519 SSH keys from ~/.ssh/authorized_keys:

# Enable SSH key authentication
npm run start -- --enable-ssh-keys

# Make SSH keys mandatory (disable password auth)
npm run start -- --enable-ssh-keys --disallow-user-password

4. No Authentication

For trusted environments only:

npm run start -- --no-auth

5. Local Bypass (Development Only)

Allow localhost connections to bypass authentication:

# Basic local bypass (DEVELOPMENT ONLY - NOT FOR PRODUCTION)
npm run start -- --allow-local-bypass

# With token for additional security (minimum for production)
npm run start -- --allow-local-bypass --local-auth-token mytoken

Security Note: Local bypass uses req.socket.remoteAddress which cannot be spoofed remotely due to TCP's three-way handshake. The implementation also rejects requests with proxy headers (X-Forwarded-For, etc.) to prevent header injection attacks. However:

  • Development only: Basic bypass without token should never be used in production
  • Local processes: Any process on the same machine can access the API
  • Always use tokens: In production, always require --local-auth-token
  • Consider alternatives: For production, use proper authentication instead of local bypass

macOS App Authentication

The macOS menu bar app supports these authentication modes:

  • No Authentication: For trusted environments only
  • System Authentication: Uses your macOS user account credentials
  • SSH Key Authentication: Uses Ed25519 SSH keys from ~/.ssh/authorized_keys
  • Configure via Settings → Security when in "Network" mode

Security Best Practices

  1. Always use authentication when binding to network interfaces (--bind 0.0.0.0)
  2. Use HTTPS in production with a reverse proxy (nginx, Caddy)
  3. Rotate credentials regularly
  4. Consider SSH keys for stronger security
  5. Never use local bypass without tokens in production environments
  6. Monitor access logs for suspicious authentication patterns
  7. Default to secure - explicitly enable less secure options only when needed

SSH Key Authentication Troubleshooting

If SSH key generation fails with crypto errors, see the detailed troubleshooting guide for solutions.

npm Package

The VibeTunnel npm package provides the full server functionality for Linux, Docker, CI/CD environments, and headless macOS systems.

Installation

# Install globally via npm
npm install -g vibetunnel

# Or with yarn
yarn global add vibetunnel

# Or with pnpm
pnpm add -g vibetunnel

Requirements: Node.js 20.0.0 or higher

Running the VibeTunnel Server

Basic Usage

# Start with default settings (localhost:4020)
vibetunnel

# Bind to all network interfaces
vibetunnel --bind 0.0.0.0

# Use a custom port
vibetunnel --port 8080

# With authentication
VIBETUNNEL_USERNAME=admin VIBETUNNEL_PASSWORD=secure vibetunnel --bind 0.0.0.0

# Enable debug logging
VIBETUNNEL_DEBUG=1 vibetunnel

# Run without authentication (trusted networks only!)
vibetunnel --no-auth

Using the vt Command

The vt command wrapper makes it easy to forward terminal sessions:

# Monitor AI agents with automatic activity tracking
vt claude
vt claude --dangerously-skip-permissions
vt --title-mode dynamic claude    # See real-time Claude status

# Run any command and see it in the browser
vt npm test
vt python script.py
vt cargo build --release

# Open an interactive shell
vt --shell
vt -i  # short form

# Control terminal titles
vt --title-mode static npm run dev    # Shows path and command
vt --title-mode dynamic python app.py  # Shows path, command, and activity
vt --title-mode filter vim            # Blocks vim from changing title

# Control output verbosity
vt -q npm test         # Quiet mode - no console output
vt -v npm run dev      # Verbose mode - show more information
vt -vv cargo build     # Extra verbose - all except debug
vt -vvv python app.py  # Debug mode - show everything

# Shell aliases work automatically!
vt claude-danger  # Your custom alias for claude --dangerously-skip-permissions

# Update session title (inside a VibeTunnel session)
vt title "My Project - Testing"

The vt Forwarding Command

The vt command is VibeTunnel's terminal forwarding wrapper that allows you to run any command while making its output visible in the browser. Under the hood, vt is a convenient shortcut for vibetunnel fwd - it's a bash script that calls the full command with proper path resolution and additional features like shell alias support. The vt wrapper acts as a transparent proxy between your terminal and the command, forwarding all input and output through VibeTunnel's infrastructure.

Command Syntax

vt [options] <command> [args...]

Options

Terminal Title Control:

  • --title-mode <mode> - Control how terminal titles are managed:
    • none - No title management, apps control their own titles (default)
    • filter - Block all title changes from applications
    • static - Show working directory and command in title
    • dynamic - Show directory, command, and live activity status (auto-enabled for Claude)

Verbosity Control:

  • -q, --quiet - Quiet mode, no console output (logs to file only)
  • -v, --verbose - Verbose mode, show errors, warnings, and info messages
  • -vv - Extra verbose, show all messages except debug
  • -vvv - Debug mode, show all messages including debug

Other Options:

  • --shell, -i - Launch your current shell interactively
  • --no-shell-wrap, -S - Execute command directly without shell interpretation
  • --log-file <path> - Override default log file location (defaults to ~/.vibetunnel/log.txt)
  • --help, -h - Show help message with all options

Verbosity Levels

VibeTunnel uses a hierarchical logging system where each level includes all messages from more severe levels:

Level Flag Environment Variable Shows
SILENT -q VIBETUNNEL_LOG_LEVEL=silent No console output (file logging only)
ERROR (default) VIBETUNNEL_LOG_LEVEL=error Errors only
WARN - VIBETUNNEL_LOG_LEVEL=warn Errors and warnings
INFO -v VIBETUNNEL_LOG_LEVEL=info Errors, warnings, and informational messages
VERBOSE -vv VIBETUNNEL_LOG_LEVEL=verbose All messages except debug
DEBUG -vvv VIBETUNNEL_LOG_LEVEL=debug Everything including debug traces

Note: All logs are always written to ~/.vibetunnel/log.txt regardless of verbosity settings. The verbosity only controls terminal output.

Examples

# Basic command forwarding
vt ls -la                    # List files with VibeTunnel monitoring
vt npm run dev              # Run development server
vt python script.py         # Execute Python script

# With verbosity control
vt -q npm test              # Run tests silently
vt -v npm install           # See detailed installation progress
vt -vvv python debug.py     # Full debug output
vt --log-file debug.log npm run dev  # Write logs to custom file

# Terminal title management
vt --title-mode static npm run dev    # Fixed title showing command
vt --title-mode dynamic claude         # Live activity updates
vt --title-mode filter vim            # Prevent vim from changing title

# Shell handling
vt --shell                  # Open interactive shell
vt -S /usr/bin/python      # Run python directly without shell

How It Works

  1. Command Resolution: The vt wrapper first checks if your command is an alias, shell function, or binary
  2. Session Creation: It creates a new VibeTunnel session with a unique ID
  3. PTY Allocation: A pseudo-terminal is allocated to preserve terminal features (colors, cursor control, etc.)
  4. I/O Forwarding: All input/output is forwarded between your terminal and the browser in real-time
  5. Process Management: The wrapper monitors the process and handles signals, exit codes, and cleanup

Environment Variables

  • VIBETUNNEL_LOG_LEVEL - Set default verbosity level (silent, error, warn, info, verbose, debug)
  • VIBETUNNEL_TITLE_MODE - Set default title mode (none, filter, static, dynamic)
  • VIBETUNNEL_DEBUG - Legacy debug flag, equivalent to VIBETUNNEL_LOG_LEVEL=debug
  • VIBETUNNEL_CLAUDE_DYNAMIC_TITLE - Force dynamic title mode for Claude commands

Special Features

Automatic Claude Detection: When running Claude AI, vt automatically enables dynamic title mode to show real-time activity status (thinking, writing, idle).

Shell Alias Support: Your shell aliases and functions work transparently through vt:

alias gs='git status'
vt gs  # Works as expected

Session Title Updates: Inside a VibeTunnel session, use vt title to update the session name:

vt title "Building Production Release"

Mac App Interoperability

The npm package is designed to work seamlessly alongside the Mac app:

Smart Command Routing

  • The vt command automatically detects if the Mac app is installed
  • If found at /Applications/VibeTunnel.app, it defers to the Mac app
  • If not found, it uses the npm-installed server
  • This ensures you always get the best available implementation

Installation Behavior

  • If /usr/local/bin/vt already exists (from another tool), npm won't overwrite it
  • You'll see a helpful warning with alternatives: vibetunnel or npx vt
  • The installation always succeeds, even if the vt symlink can't be created

When to Use Each Version

  • Mac app only: Best for macOS users who want menu bar integration
  • npm only: Perfect for Linux, Docker, CI/CD, or headless servers
  • Both installed: Mac app takes precedence, npm serves as fallback
  • Development: npm package useful for testing without affecting Mac app

Package Contents

The npm package includes:

  • Full VibeTunnel server with web UI
  • CLI tools (vibetunnel and vt commands)
  • Native PTY support via node-pty
  • Pre-built binaries for common platforms
  • Complete feature parity with macOS app (minus menu bar)

Building the npm Package

For maintainers who need to build the npm package:

Unified Build (Multi-Platform by Default)

# Build with prebuilt binaries for all platforms
# Requires Docker for Linux cross-compilation
npm run build:npm

This creates prebuilt binaries for:

  • macOS (x64, arm64) - Node.js 20, 22, 23, 24
  • Linux (x64, arm64) - Node.js 20, 22, 23, 24

Build Options

# Current platform only (faster for development)
node scripts/build-npm.js --current-only

# Specific platform/architecture
node scripts/build-npm.js --platform darwin --arch arm64

# Skip Docker builds
node scripts/build-npm.js --no-docker

Publishing

# Test the package locally
npm pack

# Publish to npm
npm publish

Building from Source

Prerequisites

  • macOS 14.0+ (Sonoma) on Apple Silicon (M1+)
  • Xcode 16.0+
  • Node.js 20+ (minimum supported version)

Build Steps

# Clone the repository
git clone https://github.com/amantus-ai/vibetunnel.git
cd vibetunnel

# Set up code signing (required for macOS/iOS development)
# Create Local.xcconfig files with your Apple Developer Team ID
# Note: These files must be in the same directory as Shared.xcconfig
cat > mac/VibeTunnel/Local.xcconfig << EOF
// Local Development Configuration
// DO NOT commit this file to version control
DEVELOPMENT_TEAM = YOUR_TEAM_ID
CODE_SIGN_STYLE = Automatic
EOF

cat > ios/VibeTunnel/Local.xcconfig << EOF
// Local Development Configuration  
// DO NOT commit this file to version control
DEVELOPMENT_TEAM = YOUR_TEAM_ID
CODE_SIGN_STYLE = Automatic
EOF

# Build the web server
cd web
pnpm install
pnpm run build

# Optional: Build with custom Node.js for smaller binary (46% size reduction)
# export VIBETUNNEL_USE_CUSTOM_NODE=YES
# node build-custom-node.js  # Build optimized Node.js (one-time, ~20 min)
# pnpm run build              # Will use custom Node.js automatically

# Build the macOS app
cd ../mac
./scripts/build.sh --configuration Release

Custom Node.js Builds

VibeTunnel supports building with a custom Node.js for a 46% smaller executable (61MB vs 107MB):

# Build custom Node.js (one-time, ~20 minutes)
node build-custom-node.js

# Use environment variable for all builds
export VIBETUNNEL_USE_CUSTOM_NODE=YES

# Or use in Xcode Build Settings
# Add User-Defined Setting: VIBETUNNEL_USE_CUSTOM_NODE = YES

See Custom Node Build Flags for detailed optimization information.

Development

For development setup and contribution guidelines, see CONTRIBUTING.md.

Key Files

  • macOS App: mac/VibeTunnel/VibeTunnelApp.swift
  • Server: web/src/server/ (TypeScript/Node.js)
  • Web UI: web/src/client/ (Lit/TypeScript)
  • iOS App: ios/VibeTunnel/

Testing & Code Coverage

VibeTunnel has comprehensive test suites with code coverage enabled for all projects:

# Run all tests with coverage
./scripts/test-all-coverage.sh

# macOS tests with coverage (Swift Testing)
cd mac && swift test --enable-code-coverage

# iOS tests with coverage (using xcodebuild)
cd ios && ./scripts/test-with-coverage.sh

# Web tests with coverage (Vitest)
cd web && ./scripts/coverage-report.sh

Coverage Requirements:

  • macOS/iOS: 75% minimum (enforced in CI)
  • Web: 80% minimum for lines, functions, branches, and statements

Development Server & Hot Reload

VibeTunnel includes a development server with automatic rebuilding for faster iteration:

Development Mode

cd web
pnpm run dev

What this provides:

  • Automatic Rebuilds: esbuild watches for file changes and rebuilds bundles instantly
  • Fast Feedback: Changes are compiled within seconds of saving
  • Manual Refresh Required: Browser needs manual refresh to see changes (no hot module replacement)

How it works:

  • esbuild watch mode detects file changes in src/
  • Automatically rebuilds JavaScript bundles and CSS
  • Express server serves updated files immediately
  • Visit http://localhost:4020 and refresh to see changes

Testing on External Devices (iPad, iPhone, etc.)

When developing the web interface, you often need to test changes on external devices to debug browser-specific issues. Here's how to do it:

Quick Setup
  1. Run the dev server with network access:

    cd web
    pnpm run dev --port 4021 --bind 0.0.0.0
    

    This binds to all network interfaces, making it accessible from other devices.

  2. Find your Mac's IP address:

    • System Preferences → Network → Wi-Fi → Details
    • Or run: ipconfig getifaddr en0
  3. Access from your external device:

    http://[your-mac-ip]:4021
    
Important Notes
  • Port conflict: The Mac app runs on port 4020, so use a different port (e.g., 4021) for development
  • Same network: Ensure both devices are on the same Wi-Fi network
  • Firewall: macOS may prompt to allow incoming connections - click "Allow"
  • Auto-rebuild: Changes to the web code are automatically rebuilt, but you need to manually refresh the browser
Pasting on Mobile Devices

When using VibeTunnel on mobile browsers (Safari, Chrome), pasting works differently than on desktop:

To paste on mobile:

  1. Press the paste button on the keyboard toolbar
  2. A white input box will appear
  3. Long-press inside the white box to bring up the paste menu
  4. Select "Paste" from the menu
  5. The text will be pasted into your terminal session

Note: Due to browser security restrictions on non-HTTPS connections, the paste API is limited on mobile devices. The white input box is a workaround that allows clipboard access through the browser's native paste functionality.

Future: Hot Module Replacement

For true hot module replacement without manual refresh, see our Vite migration plan which would provide:

  • Instant updates without page refresh
  • Preserved application state during development
  • Sub-second feedback loops
  • Modern development tooling

Mac App Development Server Mode

The VibeTunnel Mac app includes a special development server mode that integrates with the web development workflow:

Setup:

  1. Open VibeTunnel Settings → Debug tab (enable Debug Mode first in General settings)
  2. Enable "Use Development Server"
  3. Set the path to your web/ directory
  4. Restart the VibeTunnel server

How it works:

  • Instead of using the bundled production server, the Mac app runs pnpm run dev in your web directory
  • Provides hot reload and automatic rebuilding during development
  • Maintains all Mac app functionality (session management, logging, etc.)
  • Shows "Dev Server" in the menu bar and status indicators

Benefits:

  • No need to manually rebuild after code changes
  • Automatic esbuild watch mode for instant compilation
  • Full integration with Mac app features
  • Same terminal session management as production

Alternative: Standalone Development

If you prefer working outside the Mac app:

  1. Build the web project: cd web && pnpm run build
  2. In VibeTunnel settings, set Dashboard Access to "Network"
  3. Access from external device: http://[your-mac-ip]:4020

Note: This requires rebuilding after each change, so the dev server mode above is preferred for rapid iteration.

Debug Logging

Enable debug logging for troubleshooting:

# Enable debug mode
export VIBETUNNEL_DEBUG=1

# Or use inline
VIBETUNNEL_DEBUG=1 vt your-command

Debug logs are written to ~/.vibetunnel/log.txt.

Verbosity Control

Control the amount of output from VibeTunnel commands:

# Command-line flags
vt -q npm test                # Quiet mode - no console output
vt npm test                   # Default - errors only
vt -v npm run dev            # Verbose - errors, warnings, and info
vt -vv cargo build           # Extra verbose - all except debug
vt -vvv python script.py     # Debug mode - everything

# Environment variable
export VIBETUNNEL_LOG_LEVEL=error    # Default
export VIBETUNNEL_LOG_LEVEL=warn     # Show errors and warnings
export VIBETUNNEL_LOG_LEVEL=info     # Show errors, warnings, and info
export VIBETUNNEL_LOG_LEVEL=verbose  # All except debug
export VIBETUNNEL_LOG_LEVEL=debug    # Everything

# Or use inline
VIBETUNNEL_LOG_LEVEL=silent vt npm test

Note: All logs are always written to ~/.vibetunnel/log.txt regardless of verbosity level. The verbosity settings only control what's displayed in the terminal.

Documentation

macOS Permissions

macOS is finicky when it comes to permissions. The system will only remember the first path from where an app requests permissions. If subsequently the app starts somewhere else, it will silently fail. Fix: Delete the entry and restart settings, restart app and next time the permission is requested, there should be an entry in Settings again.

Important: You need to set your Developer ID in Local.xcconfig. If apps are signed Ad-Hoc, each new signing will count as a new app for macOS and the permissions have to be (deleted and) requested again.

Debug vs Release Bundle IDs: The Debug configuration uses a different bundle identifier (sh.vibetunnel.vibetunnel.debug) than Release (sh.vibetunnel.vibetunnel). This allows you to have both versions installed simultaneously, but macOS treats them as separate apps for permissions. You'll need to grant permissions separately for each version.

If that fails, use the terminal to reset:

# This removes Accessibility permission for a specific bundle ID:
sudo tccutil reset Accessibility sh.vibetunnel.vibetunnel
sudo tccutil reset Accessibility sh.vibetunnel.vibetunnel.debug  # For debug builds

sudo tccutil reset ScreenCapture sh.vibetunnel.vibetunnel
sudo tccutil reset ScreenCapture sh.vibetunnel.vibetunnel.debug  # For debug builds

# This removes all Automation permissions system-wide (cannot target specific apps):
sudo tccutil reset AppleEvents

Contributing

We welcome contributions! VibeTunnel is a community-driven project and we'd love to have you join us.

Join Our Community

Connect with the VibeTunnel team and other contributors on our Discord server. It's the best place to:

  • Discuss new features and ideas
  • Get help with development setup
  • Coordinate on larger changes
  • Share your VibeTunnel use cases

How to Contribute

  1. Join Discord: Start by joining our Discord server to say hello!
  2. Check Issues: Look for issues labeled good first issue or help wanted
  3. Development Setup: Follow our Contributing Guide for detailed setup instructions
  4. Submit PRs: Fork the repo, create a branch, and submit your changes

For technical details on building and developing VibeTunnel, see our Contributing Guide.

Support VibeTunnel

Love VibeTunnel? Help us keep the terminal vibes flowing! Your support helps us buy pizza and drinks while we keep hacking on your favorite AI agent orchestration platform.

All donations go directly to the development team. Choose your own amount - one-time or monthly! Visit our Polar page to support us.

Credits

Created with ❤️ by:

License

VibeTunnel is open source software licensed under the MIT License. See LICENSE for details.


Ready to vibe? Download VibeTunnel and start tunneling!