Product Requirements Document v2.0
Helm is a mobile-first web interface for orchestrating multiple OpenCode instances from anywhere. Built by forking chriswritescode-dev/opencode-web and incorporating the best ideas from opencode-vibe and VibeTunnel.
┌─────────────────────────────────────────────────────────────────┐
│ HELM │
│ "Take the helm from anywhere" │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Chat │ │ Files │ │ Tools │ │ Terminal │ │
│ │ │ │ │ │ │ │ │ │
│ │ Session │ │ Git diff │ │ MCP feed │ │ Raw TUI │ │
│ │ picker │ │ Browser │ │ Catalog │ │ Xterm.js │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Multi-Server Discovery │ │
│ │ project-a (TUI) │ project-b (serve) │ project-c (TUI) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
What we inherit:
- ✅ Mobile-first PWA architecture
- ✅ Docker deployment
- ✅ Git integration (diff, status, branches, PRs)
- ✅ MCP server configuration UI
- ✅ Session management
- ✅ File browser with syntax highlighting
- ✅ OAuth for Anthropic/GitHub
- ✅ TTS playback
- ✅ Slash commands
What we port:
- ✅ Multi-server auto-discovery via
lsof - ✅ Cross-process messaging (Web → TUI)
- ✅ Server routing (messages go to correct OpenCode instance)
- ✅ Real-time SSE sync patterns
What we adapt:
- ✅ Embedded terminal view (Xterm.js)
- ✅ Bidirectional stdin/stdout via named pipes
- ✅ Watch TUI visually from browser
What we build:
- ✅ MCP tool call visibility dashboard
- ✅ Touch-first gesture navigation
- ✅ Token/cost observability
- ✅ Model switching mid-session
- ✅ Continuum context integration
- ✅ Offline session review
Primary Persona:
- Runs multiple OpenCode instances across different projects on Mac
- Orchestrates complex coding tasks from iPhone while mobile
- Needs visibility into what agents are doing (MCP tools, costs)
- Uses Tailscale for secure remote access
- Values efficiency — no switching between multiple apps
Success Statement:
"I can manage all my OpenCode instances from one iPhone app, see exactly what tools are being called, switch between projects instantly, and the UX feels native — not like a shrunken desktop app."
Ported from opencode-vibe
The killer feature that makes Helm different from existing projects.
Requirements:
- Auto-discover all running OpenCode processes (TUI + serve modes)
- Discovery via
lsofto find processes listening on OpenCode ports - Server selector in UI showing all available instances
- Route messages to correct server based on session ownership
- Cross-process messaging: send from Helm, appears in TUI
- Health monitoring with auto-reconnect
- Project directory shown for each server
Implementation approach:
// Backend: discovery.ts
interface OpenCodeServer {
pid: number;
port: number;
mode: 'tui' | 'serve';
workdir: string;
status: 'healthy' | 'unhealthy';
sessions: string[];
}
async function discoverServers(): Promise<OpenCodeServer[]> {
// Use lsof to find opencode processes
// Parse their working directories
// Health check each one
// Return unified list
}
Acceptance Criteria:
- User starts 3 OpenCode instances in different directories
- Helm shows all 3 in server picker
- Selecting one loads its sessions
- Messages route to correct instance
Our addition
See exactly what your agents are doing.
Requirements:
- Real-time feed of tool calls across all servers
- Filter by server, tool name, status
- Expandable details: input, output, duration, tokens
- Visual indicator in chat when tool is executing
- Tool catalog showing all available tools per server
- Server connection status (green/yellow/red)
Our addition
Native-feeling iPhone experience.
Requirements:
- Bottom navigation (Chat, Files, Tools, Terminal, Settings)
- Swipe right: server/session picker
- Swipe left: file browser
- Long-press on message: copy, retry, branch
- Pull-to-refresh for server discovery
- 44x44pt minimum touch targets
- Safe area handling (notch, Dynamic Island)
- Haptic feedback on key actions
Adapted from VibeTunnel
Sometimes you want to see the raw TUI.
Requirements:
- Terminal tab showing live OpenCode TUI output
- Full Xterm.js rendering with ANSI support
- Bidirectional input (type commands)
- Server selector to pick which TUI to view
- Scrollback buffer
- Mobile-optimized terminal font sizing
- Real-time token counter per session
- Cost tracking with configurable model rates
- Historical usage charts
- Budget alerts
- Change models without new session
- Model badge on each message
- Quick-switch between recent models
- Load/save context to Continuum MCP
- Auto-suggest relevant contexts
- Sync indicator
- PWA with service worker
- Cache recent sessions
- Queue messages for later
- Display swarm task decomposition
- Show worker status
- Checkpoint visibility
┌─────────────────────────────────────────────────────────────────┐
│ iPhone (via Tailscale) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Helm PWA │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Chat │ │ Files │ │ Tools │ │Terminal │ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │ │
│ │ Server Picker (multi-select) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
│ HTTPS via Tailscale
│
┌─────────────────────────────────────────────────────────────────┐
│ Mac │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Helm Backend │ │
│ │ (Bun server) │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Discovery │ │ Router │ │ Terminal │ │ │
│ │ │ (lsof) │ │ (sessions) │ │ (pty/pipe) │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ OpenCode │ │ OpenCode │ │ OpenCode │ │
│ │ (project-a) │ │ (project-b) │ │ (project-c) │ │
│ │ TUI :4096 │ │ serve :4097 │ │ TUI :4098 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ MCP Servers │ │
│ │ filesystem │ continuum │ github │ custom... │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
// Discovery
GET /api/servers // List discovered OpenCode instances
GET /api/servers/:id/health // Health check specific server
POST /api/servers/refresh // Force re-discovery
// Routing (extends existing session endpoints)
GET /api/servers/:serverId/sessions
POST /api/servers/:serverId/sessions/:sessionId/message
// Terminal
GET /api/terminal/:serverId/stream // SSE for terminal output
POST /api/terminal/:serverId/input // Send keystrokes
// MCP Visibility
GET /api/mcp/servers // All MCP servers across all OpenCode instances
GET /api/mcp/tools // Aggregated tool catalog
GET /api/mcp/calls // Tool call history
SSE /api/mcp/events // Real-time tool call stream
frontend/src/
├── components/
│ ├── chat/ # Existing
│ ├── files/ # Existing
│ ├── settings/ # Existing
│ ├── servers/ # NEW: Multi-server management
│ │ ├── ServerPicker.tsx
│ │ ├── ServerCard.tsx
│ │ └── ServerHealth.tsx
│ ├── mcp/ # NEW: MCP visibility
│ │ ├── ToolCallFeed.tsx
│ │ ├── ToolCallDetail.tsx
│ │ ├── ToolCatalog.tsx
│ │ └── ServerStatus.tsx
│ ├── terminal/ # NEW: Embedded terminal
│ │ ├── TerminalView.tsx
│ │ ├── TerminalInput.tsx
│ │ └── TerminalTabs.tsx
│ └── mobile/ # NEW: Touch-first components
│ ├── BottomNav.tsx
│ ├── SwipeableView.tsx
│ ├── GestureHandler.tsx
│ └── MobileInput.tsx
├── stores/
│ ├── serverStore.ts # NEW: Multi-server state
│ ├── mcpStore.ts # NEW: MCP visibility state
│ ├── terminalStore.ts # NEW: Terminal state
│ └── gestureStore.ts # NEW: UI gesture state
└── hooks/
├── useServerDiscovery.ts # NEW
├── useToolCalls.ts # NEW
├── useTerminal.ts # NEW
└── useGestures.ts # NEW
- Fork chriswritescode-dev/opencode-web
- Rename to
helm(update package.json, Docker, etc.) - Audit codebase, document architecture
- Set up development environment
- Port discovery logic from opencode-vibe
- Implement server routing
- Build ServerPicker UI
- Test with multiple OpenCode instances
- Build MCP visibility components
- Integrate Xterm.js for terminal view
- Implement tool call feed
- Add terminal tab to navigation
- Implement touch gestures
- Bottom navigation
- Safe area handling
- Performance optimization
- Cost tracking
- Model switching
- Continuum integration
- Offline support
| Metric | Target |
|---|---|
| Time to switch between 3 projects | < 3 taps |
| MCP tool call visibility latency | < 100ms |
| PWA install rate | > 40% of mobile users |
| Server discovery accuracy | 100% (find all instances) |
| Terminal render fidelity | Matches native TUI |
- Naming: Is "Helm" the right name? Alternatives: Vigil, Relay, Lattice
- Upstream: Contribute multi-server back to chriswritescode, or maintain fork?
- Terminal: Embed Xterm.js directly or iframe VibeTunnel?
- Auth: Skip for v1, or implement basic auth for public deployments?
| Feature | Helm (Goal) | chriswritescode | opencode-vibe | VibeTunnel | oc-web (archived) |
|---|---|---|---|---|---|
| Multi-server discovery | ✅ | ❌ | ✅ | ❌ | ❌ |
| Cross-process messaging | ✅ | ❌ | ✅ | ❌ | ❌ |
| Mobile-first UX | ✅ | ✅ | ❌ | ❌ | |
| MCP tool visibility | ✅ | ❌ | ❌ | ❌ | ✅ |
| Embedded terminal | ✅ | ❌ | ❌ | ✅ | ❌ |
| Git integration | ✅ | ✅ | ❌ | ❌ | ❌ |
| Docker deployment | ✅ | ✅ | ❌ | ❌ | ❌ |
| Touch gestures | ✅ | ❌ | ❌ | ❌ | |
| Cost tracking | ✅ | ❌ | ❌ | ||
| Offline support | ✅ | ❌ | ❌ | ❌ |
Helm = Best of all worlds