* fix: add concurrency controls for multiple sessions using the same provider
Adds OS-inspired scheduling primitives (from HiveMind/AIMD research) to prevent
concurrent sessions from the same provider from experiencing slowdowns, random
stops, and cascading failures.
Server-side:
- Health check skips OpenCode restart when sessions are actively busy — a busy
server under concurrent load can fail the health check timeout without being
dead. Staleness guard forces restart if unhealthy+busy persists >2 minutes.
- Upstream SSE stall timeout scaled from 20s to 60s to avoid unnecessary
reconnections when multiple sessions are waiting for LLM responses.
Client-side (HiveMind primitives, arXiv:2604.17111):
- Transparent retry with exponential backoff (1s→2s→4s, max 32s) for
429/502/503/504 errors — the #1 most effective primitive from the paper.
- Circuit breaker: opens after 3 consecutive retryable errors, cooldown
doubles each trip (30s→60s→120s, capped 128s), matching TCP AIMD.
- Per-provider session tracking with TTL eviction (1h idle sweep).
- Fetch-level retry gated on AbortError/TypeError only (not DNS failures).
Refs github-code-review skill findings (all 8 issues resolved).
* fix: use definite assignment assertion for response variable
Fixes TS2454: Variable 'response' is used before being assigned
in strict mode. The for-loop body always assigns it on every path
that reaches the post-loop code, but TS can't prove that.
* fix: add cleanupSession to error paths and remove unreachable code
P1 fixes (Greptile review):
- cleanupSession called on fetch error throw path
- cleanupSession called on non-retryable HTTP error throw path
- Removed unreachable post-loop code (loop always terminates via return or throw)
Adds explicit post-loop throw to satisfy TypeScript strict return check.
* fix: address Greptile review feedback on concurrent session controls
Removes client-side session tracking that leaked on normal completion paths.
The session tracking was redundant — the server-side health check already reads from
sessionRuntime.getSessionActivitySnapshot() for busy-session detection.
Changes:
- Remove activeSessions Set and all session-tracking functions from provider-tracker
- Remove trackSessionStarted/cleanupSession calls from client.ts
- Remove unreachable (response as Response) block after retry loop
- Make upstreamStallTimeoutMs conditional: 60s when >1 sessions, 20s otherwise
Refs #1069
* fix: enforce dynamic concurrency safeguards
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Security note: binding to 0.0.0.0 exposes the server on all network interfaces — use only on trusted networks and protect with firewall rules or --ui-password.
Managed-local path note: OPENCHAMBER_TUNNEL_CONFIG must use a container path under /home/openchamber/.... If the config file references credentials-file, ensure that JSON path is also mounted and reachable inside the container.
Data directory: mount data/ for persistent storage. Ensure permissions:
openchamber # Runs in background by default
openchamber stop # Stop background server
systemd service (VPN / LAN access)
Use --foreground to keep the CLI process alive so systemd (or any other process manager) can track and restart it. Combine with OPENCODE_HOST to connect to an OpenCode instance running as a separate service.
Why set PATH and SSH_AUTH_SOCK?
systemd user services start with a minimal environment — no shell profile is sourced.
Without an explicit PATH, OpenCode won't find tools installed via Homebrew, npm, or ~/.local/bin.
Without SSH_AUTH_SOCK, git operations over SSH (push, pull, clone) will fail.
%t expands to $XDG_RUNTIME_DIR (e.g. /run/user/1000), where most SSH agents write their socket.
--host 0.0.0.0 is required to listen on all interfaces (the default is 127.0.0.1). Use --host <ip> or OPENCHAMBER_HOST=<ip> to bind to a specific interface instead.
What makes the web version special
Remote access - Cloudflare tunnel with QR onboarding. Scan from your phone, start coding.