Feature hasn't been suggested before.
Describe the enhancement you want to request
Problem
When OpenCode starts its HTTP server, the actual port used is not easily discoverable by child processes. This creates issues for integrations that need to spawn additional OpenCode instances (e.g., tmux panes, background tasks, CI/CD scripts).
Current Behavior
Server URL discovery relies on ctx.serverUrl, which returns a fallback when no server is running:
// From server/server.tsexportfunctionurl(): URL{return_url??newURL("http://localhost:4096")// Always returns fallback}Port auto-fallback is silent:
// From server/server.ts:2883constserver=opts.port===0 ? (tryServe(4096)??tryServe(0))// Tries 4096, then random port
: tryServe(opts.port)
- If port 4096 is taken, OpenCode silently uses a random OS-assigned port
- Child processes have no way to discover the actual port used
Multi-instance conflicts:
- User runs OpenCode in Project A → binds to port 4096
- User runs OpenCode in Project B → falls back to random port (e.g., 49152)
- Child processes from Project B can't discover port 49152
Real-World Use Case: Tmux Integration
Our plugin (oh-my-opencode-slim) spawns tmux panes that run opencode attach <url> --session <id> to show sub-agent work in real-time.
Current workaround:
- Require users to configure a fixed port:
{ "server": { "port": 4096 } } - This breaks when multiple OpenCode instances run simultaneously
- Port conflicts cause startup failures
What we need:
- Discover the actual server URL dynamically
- Support multiple concurrent OpenCode instances on different ports
Proposed Solution
Export the actual server URL as an environment variable when the server starts:
// After server starts successfully (server.ts:2886)constserver=opts.port===0 ? (tryServe(4096)??tryServe(0)) : tryServe(opts.port)if(!server)thrownewError(`Failed to start server on port ${opts.port}`)_url=server.url// NEW: Export for child processesprocess.env.OPENCODE_SERVER_URL=server.url.toString()Environment Variables to Export
| Variable | Example Value | Description |
|---|
OPENCODE_SERVER_URL | http://localhost:4096 | Full URL of running server |
OPENCODE_SERVER_PORT | 4096 | Port number (optional, for convenience) |
Benefits
Child processes can discover server:
# In tmux pane or background task
opencode attach $OPENCODE_SERVER_URL --session abc123
Multi-instance support:
- Each OpenCode instance exports its own URL
- Child processes automatically connect to the correct parent
No breaking changes:
- Existing code continues to work
- Environment variable is purely additive
Better than file-based coordination:
- Environment variables inherit automatically (Unix convention)
- No cleanup required
- No file permission issues
Alternative Considered
File-based approach: Write server URL to .opencode/.server-url
- Pros: Works across all platforms
- Cons: Requires cleanup, file watching, permission handling, race conditions
Environment variables are cleaner and more Unix-idiomatic.
Implementation Notes
Where to Add This
In packages/opencode/src/server/server.ts after line 2886:
exportfunctionlisten(opts: {port: number;hostname: string;mdns?: boolean;cors?: string[]}){// ... existing code ...constserver=opts.port===0 ? (tryServe(4096)??tryServe(0)) : tryServe(opts.port)if(!server)thrownewError(`Failed to start server on port ${opts.port}`)_url=server.url// Export for child processesprocess.env.OPENCODE_SERVER_URL=server.url.toString()process.env.OPENCODE_SERVER_PORT=server.port.toString()// ... rest of existing code ...}Cleanup on Server Stop
server.stop=async(closeActiveConnections?: boolean)=>{if(shouldPublishMDNS)MDNS.unpublish()// Clean up environment variablesdeleteprocess.env.OPENCODE_SERVER_URLdeleteprocess.env.OPENCODE_SERVER_PORTreturnoriginalStop(closeActiveConnections)}
Example Usage
Plugin Code (Tmux Integration)
// Before (hardcoded or unreliable fallback)constserverUrl=ctx.serverUrl?.toString()??"http://localhost:4096"// After (dynamic discovery)constserverUrl=process.env.OPENCODE_SERVER_URL??ctx.serverUrl?.toString()
Shell Scripts
#!/bin/bash# Spawn a background OpenCode task connected to the parent serverif [ -n"$OPENCODE_SERVER_URL" ];then
opencode attach "$OPENCODE_SERVER_URL" --session "$SESSION_ID"elseecho"No OpenCode server found"exit 1
fi
Related
- Similar pattern used by tools like
DOCKER_HOST, DISPLAY, SSH_AUTH_SOCK - Follows Unix convention of using environment variables for service discovery
- Enables better ecosystem integrations (plugins, scripts, CI/CD)
Would you be open to this enhancement? Happy to submit a PR if this approach makes sense!
Feature hasn't been suggested before.
Describe the enhancement you want to request
Problem
When OpenCode starts its HTTP server, the actual port used is not easily discoverable by child processes. This creates issues for integrations that need to spawn additional OpenCode instances (e.g., tmux panes, background tasks, CI/CD scripts).
Current Behavior
Server URL discovery relies on
ctx.serverUrl, which returns a fallback when no server is running:Port auto-fallback is silent:
Multi-instance conflicts:
Real-World Use Case: Tmux Integration
Our plugin (oh-my-opencode-slim) spawns tmux panes that run
opencode attach <url> --session <id>to show sub-agent work in real-time.Current workaround:
{ "server": { "port": 4096 } }What we need:
Proposed Solution
Export the actual server URL as an environment variable when the server starts:
Environment Variables to Export
OPENCODE_SERVER_URLhttp://localhost:4096OPENCODE_SERVER_PORT4096Benefits
Child processes can discover server:
Multi-instance support:
No breaking changes:
Better than file-based coordination:
Alternative Considered
File-based approach: Write server URL to
.opencode/.server-urlEnvironment variables are cleaner and more Unix-idiomatic.
Implementation Notes
Where to Add This
In
packages/opencode/src/server/server.tsafter line 2886:Cleanup on Server Stop
Example Usage
Plugin Code (Tmux Integration)
Shell Scripts
Related
DOCKER_HOST,DISPLAY,SSH_AUTH_SOCKWould you be open to this enhancement? Happy to submit a PR if this approach makes sense!