Tool to send cross-session opencode messages, including as request-response pattern
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

add PLAN for sensing active opencode instances and sessions

rektide 403ed346 264a9b51

+292 -1
+1 -1
README.md
··· 6 6 7 7 | tool | description | params=[default] | 8 8 | ---------- | ----------------------------------- | --------------------------------------------------- | 9 - | `list` | list all sessions | `dir=[pwd]` constraint | 9 + | `list` | list all sessions | `dir=[pwd]` constraint, `active=[false]` | 10 10 | `call` | send a request or message | `session=[new]`, `elaborate=[true]`, `fork=[false]` | 11 11 | `response` | multitool for queues responses, get | `get=[top]`, `list=[false]` |
+291
doc/PLAN-sense-active.md
··· 1 + # Sensing Active OpenCode Instances and Sessions 2 + 3 + ## Goal 4 + 5 + Detect all running OpenCode instances and identify which sessions are currently active/busy in order to manage agent lifecycle and avoid conflicts. 6 + 7 + ## Detection Strategy 8 + 9 + ### Priority Order 10 + 11 + 1. **mDNS Discovery** (Preferred - if enabled) 12 + 2. **Process Detection** (Fallback - parse running processes) 13 + 3. **Port Scanning** (Last resort - scan localhost) 14 + 15 + --- 16 + 17 + ## 1. mDNS Discovery 18 + 19 + OpenCode can broadcast itself via mDNS/Bonjour when configured. 20 + 21 + ### Detection 22 + 23 + - Query mDNS for `_opencode._tcp` service 24 + - Each response provides: 25 + - Hostname/IP 26 + - Port number 27 + - Service name (can be used to identify instance) 28 + 29 + ### Prerequisites 30 + 31 + - OpenCode must have `mdns: true` in config OR `--mdns` flag enabled 32 + - This is off by default 33 + 34 + ### Advantages 35 + 36 + - Clean, standard service discovery 37 + - Multiple instances on different hosts can be discovered 38 + - No special permissions needed 39 + 40 + ### Disadvantages 41 + 42 + - Disabled by default, so won't work in most scenarios 43 + - Requires mDNS library (e.g., `bonjour-service`, `mdns-js`, `node-dnssd`) 44 + 45 + --- 46 + 47 + ## 2. Process Detection 48 + 49 + Parse `/proc` entries on Linux to find OpenCode processes. 50 + 51 + ### Detection Steps 52 + 53 + 1. List all processes in `/proc` 54 + 2. Find processes matching OpenCode (e.g., `bun opencode`, `node opencode`) 55 + 3. For each matching process: 56 + - Read `/proc/[PID]/cmdline` to get full command line 57 + - Parse `--port <N>` argument to extract port 58 + - Parse working directory from `/proc/[PID]/cwd` 59 + - Parse `--dir` or directory from `/proc/[PID]/environ` 60 + 61 + ### Information Extracted 62 + 63 + | Process ID | Port | Working Directory | Args | 64 + | ---------- | ---- | ---------------- | ---- | 65 + | 12345 | 4096 | /home/user/project | --model claude-3-5 | 66 + 67 + ### Prerequisites 68 + 69 + - Linux system with `/proc` filesystem 70 + - Read access to `/proc` entries 71 + 72 + ### Advantages 73 + 74 + - Works even if mDNS is disabled 75 + - Extracts port and working directory directly 76 + - No network overhead 77 + 78 + ### Disadvantages 79 + 80 + - Linux-specific (won't work on macOS/Windows) 81 + - Requires reading `/proc` (may fail with restricted permissions) 82 + - Assumes port is in command line args (could be in config file) 83 + 84 + --- 85 + 86 + ## 3. Port Scanning 87 + 88 + Scan localhost for HTTP servers that respond like OpenCode. 89 + 90 + ### Detection Steps 91 + 92 + 1. Scan ports `4096-65535` (or configurable range) 93 + 2. For each open port: 94 + - Send `GET /api/session/status` request 95 + - If response is JSON with status info, it's an OpenCode instance 96 + 3. Extract instance info: 97 + - Port number 98 + - Session statuses from `/api/session/status` endpoint 99 + 100 + ### Information Extracted 101 + 102 + | Port | Session ID | Status | 103 + | ---- | ---------- | ------ | 104 + | 4096 | ses_abc123 | busy | 105 + | 5173 | ses_def456 | idle | 106 + 107 + ### Prerequisites 108 + 109 + - OpenCode server running and accessible via HTTP 110 + 111 + ### Advantages 112 + 113 + - Works on any OS 114 + - Directly retrieves session status (no parsing needed) 115 + - Can detect sessions across multiple instances 116 + 117 + ### Disadvantages 118 + 119 + - Slow to scan many ports 120 + - Only finds instances with HTTP server running 121 + - May miss instances bound to specific IPs (not 0.0.0.0 or 127.0.0.1) 122 + 123 + --- 124 + 125 + ## 4. Additional Fallbacks (Lower Priority) 126 + 127 + ### Lock Files 128 + 129 + - Check for lock files in `~/.local/share/opencode/` or `$XDG_RUNTIME_DIR/opencode/` 130 + - Format: `opencode-<port>.lock` containing PID 131 + - Remove after checking if process still exists 132 + 133 + ### Unix Domain Sockets 134 + 135 + - Check for sockets in `$XDG_RUNTIME_DIR/opencode/` 136 + - Can query socket for status 137 + 138 + ### Systemd/User Service Status 139 + 140 + - Check `systemctl --user status opencode*` for running services 141 + - Extract port from unit file or ExecStart command 142 + 143 + ### PID Files 144 + 145 + - Check for PID files in standard locations 146 + - Use `systemd-run` or similar to manage instance lifecycle 147 + 148 + --- 149 + 150 + ## Session Status API 151 + 152 + Once an instance is detected, query it for session activity. 153 + 154 + ### Endpoint 155 + 156 + ``` 157 + GET /api/session/status 158 + ``` 159 + 160 + ### Response Format 161 + 162 + ```json 163 + { 164 + "ses_abc123": { 165 + "type": "busy" 166 + }, 167 + "ses_def456": { 168 + "type": "idle" 169 + }, 170 + "ses_ghi789": { 171 + "type": "retry", 172 + "attempt": 3, 173 + "message": "Connection error", 174 + "next": 1737789123456 175 + } 176 + } 177 + ``` 178 + 179 + ### Status Types 180 + 181 + | Type | Meaning | 182 + | ---- | ------- | 183 + | `idle` | Session not actively processing | 184 + | `busy` | Session currently processing a prompt | 185 + | `retry` | Session encountered error and retrying (includes attempt count and message) | 186 + 187 + --- 188 + 189 + ## Implementation Plan 190 + 191 + ### Phase 1: Basic Detection 192 + 193 + 1. Implement process detection (Linux `/proc` parsing) 194 + 2. Implement port scanning with `/api/session/status` check 195 + 3. Return list of instances: `{ pid, port, cwd, sessions[] }` 196 + 197 + ### Phase 2: mDNS Support 198 + 199 + 1. Add mDNS discovery library 200 + 2. Query for `_opencode._tcp` services 201 + 3. Merge with other discovery methods 202 + 203 + ### Phase 3: Cross-Platform 204 + 205 + 1. Add macOS process detection (using `ps` command) 206 + 2. Add Windows process detection (using `wmic` or PowerShell) 207 + 3. Use lock files as universal fallback 208 + 209 + ### Phase 4: API Client 210 + 211 + 1. Create simple HTTP client to query OpenCode API 212 + 2. Add helper: `getActiveSessions(port)` → returns `sessionID[]` with `type: "busy"` 213 + 3. Add helper: `getSessionStatus(port, sessionID)` → returns session details 214 + 215 + --- 216 + 217 + ## Configuration 218 + 219 + Users can configure discovery: 220 + 221 + ```json 222 + { 223 + "discovery": { 224 + "methods": ["mdns", "process", "port"], 225 + "portRange": [4096, 65535], 226 + "timeout": 5000, 227 + "scanInterval": 30000 228 + } 229 + } 230 + ``` 231 + 232 + ### Options 233 + 234 + - `methods`: List of discovery methods to try, in priority order 235 + - `portRange`: Port range to scan for port-based discovery 236 + - `timeout`: Timeout for HTTP requests to instances (ms) 237 + - `scanInterval`: How often to re-scan for instances (ms) 238 + 239 + --- 240 + 241 + ## Use Cases 242 + 243 + ### Finding an idle session to attach to 244 + 245 + ```typescript 246 + const instances = await discoverOpenCodeInstances() 247 + for (const instance of instances) { 248 + const sessions = await getInstanceSessions(instance.port) 249 + const idle = sessions.filter(s => s.status.type === 'idle') 250 + if (idle.length > 0) { 251 + return { instance, session: idle[0] } 252 + } 253 + } 254 + // Create new session if none available 255 + ``` 256 + 257 + ### Checking if a session is busy before sending commands 258 + 259 + ```typescript 260 + const instance = await discoverInstanceAtPort(4096) 261 + const status = await getSessionStatus(instance.port, 'ses_abc123') 262 + if (status.type === 'busy') { 263 + console.log('Session is busy, waiting...') 264 + await waitForIdle(instance.port, 'ses_abc123') 265 + } 266 + ``` 267 + 268 + ### Listing all active sessions across all instances 269 + 270 + ```typescript 271 + const instances = await discoverOpenCodeInstances() 272 + const allSessions: Array<{sessionID: string, port: number, status: string}> = [] 273 + 274 + for (const instance of instances) { 275 + const sessions = await getInstanceSessions(instance.port) 276 + for (const [id, status] of Object.entries(sessions)) { 277 + allSessions.push({ sessionID: id, port: instance.port, status: status.type }) 278 + } 279 + } 280 + 281 + console.table(allSessions.filter(s => s.status === 'busy')) 282 + ``` 283 + 284 + --- 285 + 286 + ## Notes 287 + 288 + - Session status is **in-memory only** - lost when server restarts 289 + - Multiple OpenCode instances can run simultaneously on different ports 290 + - Default port is `4096` but can be auto-assigned if `0` is specified 291 + - mDNS uses hostname `0.0.0.0` when enabled, making it discoverable on LAN