Architecture¶
This document describes the internal architecture of the OpenCode Home Assistant Plugin.
Overview¶
The plugin acts as a bridge between OpenCode and Home Assistant, using native WebSocket communication.
┌────────────────────────────────────────────────────────────────────┐
│ OpenCode Process │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ha-opencode Plugin │ │
│ │ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌─────────────┐ │ │
│ │ │ State │ │ Commands │ │ WebSocket │ │ Config │ │ │
│ │ │ Tracker │ │ Handler │ │ Client │ │ Store │ │ │
│ │ └────┬────┘ └────┬─────┘ └─────┬─────┘ └──────┬──────┘ │ │
│ │ │ │ │ │ │ │
│ └───────┼────────────┼──────────────┼───────────────┼───────────┘ │
│ │ │ │ │ │
└──────────┼────────────┼──────────────┼───────────────┼───────────────┘
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────────┐ │
│ └─────►│ Home Assistant │◄────┘
└──────────────────►│ WebSocket API │
└─────────────────┘
Core Components¶
Entry Point (index.ts)¶
The main plugin entry point that:
- Implements the OpenCode plugin interface
- Initializes all components
- Handles plugin lifecycle (start/stop)
- Subscribes to OpenCode events
- Manages pairing flow
WebSocket Client (websocket.ts)¶
Handles communication with Home Assistant:
- Connects to HA WebSocket API
- Authenticates with access token
- Sends session updates
- Receives commands from HA
- Handles reconnection
Message Types:
| Type | Direction | Purpose |
|---|---|---|
opencode/pair |
Plugin → HA | Initial pairing |
opencode/connect |
Plugin → HA | Reconnect with token |
opencode/session_update |
Plugin → HA | Session state update |
opencode/command |
HA → Plugin | Commands (prompt, permission, etc.) |
opencode/history_response |
Plugin → HA | Session history |
opencode/agents_response |
Plugin → HA | Available agents |
State Tracker (state.ts)¶
Manages session state and pushes updates to Home Assistant.
Responsibilities:
- Track current session ID and state
- Monitor permission requests
- Aggregate session data (tokens, cost, etc.)
- Send updates via WebSocket
State Machine:
┌─────────────────────────────────────┐
│ │
▼ │
┌───────┐ task started ┌─────────┐ │
│ idle │─────────────────►│ working │───┤
└───────┘ └────┬────┘ │
▲ │ │
│ ▼ │
│ ┌─────────────┐ │
│ approved/ │ waiting_ │ │
│ rejected │ permission │ │
│◄───────────────────└─────────────┘ │
│ │
│ task complete │
└─────────────────────────────────────┘
Command Handler (commands.ts)¶
Processes commands received from Home Assistant:
send_prompt- Send prompt to OpenCoderespond_permission- Approve/reject permissionsget_history- Retrieve session historyget_agents- List available agents
Command Flow:
WebSocket Message
│
▼
┌─────────────┐
│ Parse │
│ Command │
└──────┬──────┘
│
▼
┌─────────────┐
│ Execute │
│ Action │
└──────┬──────┘
│
▼
┌─────────────┐
│ Send │
│ Response │
└─────────────┘
Configuration (ha-config.ts)¶
Manages persistent configuration:
- Stores connection details after pairing
- Loads saved configuration on startup
- Supports environment variable overrides
Notifications (notify.ts)¶
Sends local terminal notifications using OSC escape sequences (Kitty terminal protocol).
Event Flow¶
Pairing Flow¶
- User adds OpenCode integration in HA
- HA generates pairing code
- User invokes
ha_pairin OpenCode - Plugin connects to HA WebSocket
- Plugin sends
opencode/pairwith code - HA validates code, returns instance token
- Plugin stores token for future connections
Session Start¶
- OpenCode emits
session.createdevent - Plugin captures session ID
- State tracker initializes session data
- Session update sent to HA via WebSocket
- HA creates entities for the session
Permission Request¶
- OpenCode emits
permission.requestedevent - State tracker stores permission details
- State changes to
waiting_permission - Session update sent to HA
- HA fires
opencode_permission_requestevent - Automations/card show permission details
Permission Response¶
- User approves/rejects in HA (card, notification, or automation)
- HA sends
opencode/commandvia WebSocket - Command handler receives
respond_permission - Response sent to OpenCode SDK
- State returns to
workingoridle
Message Processing¶
- OpenCode emits
message.updatedevent - Plugin extracts tool info, tokens, cost
- Session update sent to HA
- HA entities update automatically
Reconnection¶
The plugin handles disconnections gracefully:
- WebSocket closes unexpectedly
- Reconnection timer starts (5 second delay)
- Plugin reconnects using saved instance token
- HA recognizes returning instance
- State synchronization occurs
- Normal operation resumes
Error Handling¶
- WebSocket failures: Automatic reconnect with backoff
- Invalid commands: Logged via notification
- SDK errors: Logged, state set to
error - Authentication errors: Clear config, require re-pairing
Testing Strategy¶
- Unit tests for each component
- Mock WebSocket client for integration tests
- Mock OpenCode SDK responses
- All 43 tests passing