CLAUDE.md for macOS Development
SwiftUI Development Guidelines
- Aim to build all functionality using SwiftUI unless there is a feature that is only supported in AppKit.
- Design UI in a way that is idiomatic for the macOS platform and follows Apple Human Interface Guidelines.
- Use SF Symbols for iconography.
- Use the most modern macOS APIs. Since there is no backward compatibility constraint, this app can target the latest macOS version with the newest APIs.
- Use the most modern Swift language features and conventions. Target Swift 6 and use Swift concurrency (async/await, actors) and Swift macros where applicable.
Logging Guidelines
IMPORTANT: Never useprint()
statements in production code. Always use the unified logging system with proper Logger instances.
Setting up Loggers
Each Swift file should declare its own logger at the top of the file:Log Levels
Choose the appropriate log level based on context:-
.debug
- Detailed information useful only during development/debugging -
.info
- General informational messages about normal app flow -
.notice
- Important events that are part of normal operation -
.warning
- Warnings about potential issues that don’t prevent operation -
.error
- Errors that indicate failure but app can continue -
.fault
- Critical errors that indicate programming mistakes or system failures
Common Patterns
Benefits
- Logs are automatically categorized and searchable with
vtlog
- Performance optimized (debug logs compiled out in release builds)
- Privacy-aware (use
\(value, privacy: .public)
when needed) - Integrates with Console.app and system log tools
- Consistent format across the entire codebase
Important Build Instructions
Xcode Build Process
CRITICAL: When you build the Mac app with Xcode (using XcodeBuildMCP or manually), it automatically builds the web server as part of the build process. The Xcode build scripts handle:- Building the TypeScript/Node.js server
- Bundling all web assets
- Creating the native executable
- Embedding everything into the Mac app bundle
pnpm run build
in the web directory when building the Mac app - this is redundant and wastes time.
Always Use Subtasks
IMPORTANT: Always use the Task tool for operations, not just when hitting context limits:- For ANY command that might generate output (builds, logs, file reads)
- For parallel operations (checking multiple files, running searches)
- For exploratory work (finding implementations, debugging)
- This keeps the main context clean and allows better organization
VibeTunnel Architecture Overview
VibeTunnel is a macOS application that provides terminal access through web browsers. It consists of three main components:1. Mac App (Swift/SwiftUI)
- Native macOS application that manages the entire system
- Spawns and manages the Bun/Node.js server process
- Handles terminal creation and management
- Provides system tray UI and settings
2. Web Server (Node.js)
- Runs on localhost:4020 by default
- Serves the web frontend
- Manages WebSocket connections for terminal I/O
- Handles API requests and session management
- Routes logs from the frontend to the Mac app
3. Web Frontend (TypeScript/LitElement)
- Browser-based terminal interface
- Connects to the server via WebSocket
- Uses xterm.js for terminal rendering
- Sends logs back to server for centralized logging
Logging Architecture
VibeTunnel has a sophisticated logging system that aggregates logs from all components:Log Flow
Log Prefixing System
To help identify where logs originate, the system uses these prefixes:-
Frontend Logs:
- Browser console:
[module-name] message
- When forwarded to server:
[CLIENT:module-name] message
- Browser console:
-
Server Logs:
- Direct server logs:
[module-name] message
- No additional prefix needed
- Direct server logs:
-
Mac App Logs:
- Native Swift logs: Use specific categories (ServerManager, SessionService, etc.)
- Server output: All captured under “ServerOutput” category
Understanding Log Sources
When viewing logs withvtlog
, you can identify the source:
[CLIENT:*]
- Originated from web frontend[server]
,[api]
, etc. - Server-side modules- Category-based logs - Native Mac app components
Debugging and Logging
The VibeTunnel Mac app uses the unified logging system with the subsystemsh.vibetunnel.vibetunnel
. We provide a convenient vtlog
script to simplify log access.
Quick Start with vtlog
Thevtlog
script is located at scripts/vtlog.sh
. It’s designed to be context-friendly by default.
Default behavior: Shows last 50 lines from the past 5 minutes
Common Use Cases
Available Categories
- ServerManager - Server lifecycle and configuration
- SessionService - Terminal session management
- TerminalManager - Terminal spawning and control
- GitRepository - Git integration features
- ScreencapService - Screen capture functionality
- WebRTCManager - WebRTC connections
- UnixSocket - Unix socket communication
- WindowTracker - Window tracking and focus
- NgrokService - Ngrok tunnel management
- ServerOutput - Node.js server output (includes frontend logs)
Manual Log Commands
If you prefer using the nativelog
command directly:
Tips
- Run
./scripts/vtlog.sh --help
for full documentation - Use
-d
flag for debug-level logs during development - The app logs persist after the app quits, useful for crash debugging
- Add
--json
for machine-readable output - Server logs (Node.js output) are under the “ServerOutput” category
- Look for
[CLIENT:*]
prefix to identify frontend-originated logs
XcodeBuildMCP Usage Guide
XcodeBuildMCP is an MCP (Model Context Protocol) server that provides comprehensive Xcode build and automation capabilities. It’s the recommended way to build, test, and manage the VibeTunnel macOS project.Installation
If XcodeBuildMCP is not already installed, add it to Claude Code:Common XcodeBuildMCP Commands for VibeTunnel
Project Discovery
Building the Mac App
Running the App
Testing
Cleaning
Build Settings
Tips for Using XcodeBuildMCP
- Always use full paths: XcodeBuildMCP requires absolute paths for project files
- Check schemes first: Use
list_schems_proj
to verify available schemes - Use proper configuration: Debug for development, Release for distribution
- Handle build failures: If builds fail, check the error output and use
clean_proj
if needed - Incremental builds: XcodeBuildMCP supports incremental builds by default for faster iteration
Common Workflows
Development Build & Run
Release Build
CI Build
Testing
Running macOS Tests
IMPORTANT: macOS tests MUST be run using XcodeBuildMCP commands or xcodebuild, NOT withswift test
:
Why swift test
Fails
- Missing Server Binary: The
vibetunnel
SEA (Single Executable Application) binary is only created during the full Xcode build process. Tests expect this binary to be embedded in the app bundle’s Resources folder. - No Proper App Bundle:
swift test
runs in a minimal test bundle environment without the full app structure - UserNotifications Framework: Tests using UserNotifications will crash due to missing bundle configuration
- Missing Build Phases: The web frontend build and SEA creation only happen during Xcode builds
Correct Testing Methods
Using XcodeBuildMCP (Recommended):ServerBinaryAvailableCondition
) which correctly fail when the binary isn’t present, preventing tests from running in an incomplete environment.
Testing the Web Interface
The VibeTunnel server runs on localhost:4020 by default. To test the web interface:- Ensure the Mac app is running. The user does that. Do not start the mac app yourself!
- Access http://localhost:4020 in your browser
- Use Playwright MCP for automated testing:
Key Implementation Details
Server Process Management
- The Mac app spawns the Bun server using
BunServer.swift
- Server logs are captured and forwarded to macOS logging system
- Process lifecycle is tied to the Mac app lifecycle
Log Aggregation
- All logs flow through the Mac app for centralized access
- Use
vtlog
to see logs from all components in one place - Frontend errors are particularly useful for debugging UI issues
Development Workflow
- Use XcodeBuildMCP for Swift changes
- The web frontend auto-reloads on changes (when
pnpm run dev
is running) - Use Playwright MCP to test integration between components
- Monitor all logs with
vtlog -f
during development
Unix Socket Communication Protocol
Type Synchronization Between Mac and Web
When implementing new Unix socket message types between the Mac app and web server, it’s essential to maintain type safety on both sides:- Mac Side: Define message types in Swift (typically in
ControlProtocol.swift
or related files) - Web Side: Create corresponding TypeScript interfaces in
web/src/shared/types.ts
- Keep Types in Sync: Whenever you add or modify Unix socket messages, update the types on both platforms to ensure type safety and prevent runtime errors
- Add new message type to
ControlProtocol.swift
(Mac) - Add corresponding interface to
types.ts
(Web) - Update handlers on both sides to use the typed messages
- This prevents bugs from mismatched message formats and makes the protocol self-documenting