## Context Currently, tool types have inconsistent port configuration: - `code-server`: default_port=8443, interfaces=["web"] - `jupyter-notebook`: default_port=8888, interfaces=["web"] - `opencode`: default_port=undefined, interfaces=["terminal"] The tunnel creation code falls back to port 8080 when no default_port is set, which causes 502 Bad Gateway errors since OpenCode doesn't listen on any port. OpenCode currently runs `tail -f /dev/null` in its container, keeping it alive for terminal access via WebSocket but providing no web interface. The user wants OpenCode accessible via a web terminal in the browser. ## Goals / Non-Goals **Goals:** - Make `default_port` a required field for all tool types with validation - Add a web server to OpenCode so it exposes a port for browser access - Ensure tunnel creation always uses the correct port from tool type config - Support tools with both terminal and web interfaces - Add compose template validation to ensure defined ports are actually exposed **Non-Goals:** - Changing the existing WebSocket terminal implementation - Adding new authentication or authorization - Supporting non-HTTP protocols for tunnels - Modifying code-server or jupyter configurations ## Decisions ### Decision: OpenCode exposes a web terminal on port 3000 **Rationale:** OpenCode needs a web interface for browser access. We'll run a lightweight web server (using `npx serve` or a simple Node.js HTTP server) alongside the OpenCode CLI. **Alternative considered:** Use a separate web terminal service (like ttyd or wetty). Rejected because it adds complexity and another dependency. ### Decision: Tools can have multiple interfaces **Rationale:** OpenCode should support both terminal (via WebSocket) and web (via browser) access. The `interfaces` field should allow `["terminal", "web"]`. ### Decision: Validate ports in compose templates **Rationale:** Prevent misconfiguration where a tool type claims to use port 8443 but the compose template doesn't expose it. **Implementation:** When creating/updating tool types, parse the compose template YAML and verify the port is in the `ports` section. ### Decision: Store tunnel URL in instance.url, not public_url **Rationale:** Simplify the data model. The `url` field is what the frontend uses to open tools. `public_url` is redundant. ## Risks / Trade-offs - **[Risk]** OpenCode web terminal may not work well without proper TTY support → **Mitigation**: Test thoroughly, fall back to raw terminal if needed - **[Risk]** Running a web server in OpenCode container increases resource usage → **Mitigation**: Use a minimal static file server (~5MB memory) - **[Risk]** Port conflicts if multiple instances use the same default_port → **Mitigation**: Docker maps container ports to host ports automatically, internal ports can overlap ## Migration Plan 1. Update OpenCode compose template to include a web server 2. Add `default_port: 3000` to OpenCode seed data 3. Add port validation to tool type API 4. Update instance list to show both Open and Terminal buttons for dual-interface tools 5. Test OpenCode instance creation and tunnel access ## Open Questions - Should we use `npx serve` or a custom Node.js server for OpenCode web UI? - Should the web terminal use the existing xterm.js component or redirect to a separate page?