Skip to main content

Design Rationale

Instead of running a single backend and restarting on venv changes, typemux-cc maintains a pool of concurrent backend processes — one per venv. This eliminates restart overhead when switching between projects in a monorepo.

Before: Single Backend

  • Switch venv → kill process → spawn new → re-index
  • 5-10s downtime per switch
  • Lost state on every transition

After: Multi-Backend Pool

  • Keep multiple backends alive
  • Instant switching (already indexed)
  • Preserve state per venv

Pool Configuration

Basic Settings

Monorepo with 2-3 projects

  • Keeps 1 backend per project + 1 spare
  • 30-minute TTL cleans up unused backends
  • Higher pool size for frequent project switches
  • 1-hour TTL for long coding sessions
  • Minimal pool (1 backend + 1 spare for nested venvs)
  • Disable TTL (backend never evicted)
  • Limit concurrent backends to 2
  • Aggressive 10-minute TTL

Backend Instance Structure

Each backend in the pool is represented by a BackendInstance (src/backend_pool.rs:44-55):
The session field is critical for stale message detection. See Architecture: Session-Based Detection.

LRU Eviction Strategy

When the pool reaches max_backends and a new backend is needed, typemux-cc evicts the least recently used (LRU) backend.

LRU Selection Algorithm

Code reference: src/backend_pool.rs:156-174

Eviction Sequence

What Happens During Eviction

  1. Cancel pending requests: All client requests waiting for responses from this backend receive a cancellation error (-32800)
  2. Clean up backend requests: Remove any pending backend→client requests from tracking
  3. Clear diagnostics: Send empty diagnostic messages to client to clear stale errors from evicted backend
  4. Shutdown process: Send LSP shutdown + exit to backend, kill process if unresponsive
  5. Abort reader task: Stop the background task reading from backend’s stdout
If you see frequent evictions in logs (grep "Evicting LRU backend" /tmp/typemux-cc.log), increase --max-backends to reduce thrashing.

TTL-Based Eviction

Backends idle for longer than backend_ttl are automatically evicted to free resources.

TTL Sweep Mechanism

  • Interval: 60 seconds (hardcoded in src/proxy/mod.rs event loop)
  • Check: Instant::now() - last_used >= backend_ttl
  • Safety: Skip backends with pending requests (both client→backend and backend→client)
Code reference: src/proxy/pool_management.rs:95-166

TTL Behavior Examples

Timeline:
  • 10:00 AM: User opens file in project-a → backend spawned
  • 10:30 AM: User switches to project-b → project-a backend becomes idle
  • 11:00 AM: TTL expires, project-a backend evicted (pool size: 1)

Session Tracking

Session ID Generation

Each backend gets a unique, monotonically increasing session ID when spawned: Code reference: src/backend_pool.rs:176-180
Starting from 0, each new backend (including re-spawns after crashes) gets the next ID: 1, 2, 3, …

Session Validation

Every message received from a backend includes its session ID. Before processing, the proxy checks: Code reference: src/proxy/backend_dispatch.rs:23-49

Why Session IDs Matter

Without Session IDs

Problem: Backend crashes, new backend spawned with same venv path. Old responses arrive → forwarded to client → wrong data.Example:
  1. Backend session 1 serves project-a/.venv
  2. Client sends request ID 42
  3. Backend session 1 crashes
  4. New backend session 2 spawned for project-a/.venv
  5. Old response from session 1 arrives (wrong index state)
  6. ❌ Client receives stale response

With Session IDs

Solution: Responses from old sessions are discarded.Example:
  1. Backend session 1 serves project-a/.venv
  2. Client sends request ID 42 (recorded as session 1)
  3. Backend session 1 crashes
  4. New backend session 2 spawned for project-a/.venv
  5. Old response from session 1 arrives
  6. ✅ Proxy discards (session 1 != session 2)
  7. Client receives cancellation error for request 42

Pool State Inspection

Current Pool Status

To see which backends are in the pool:
Look for log lines like:

Pool Activity Monitoring

Memory Considerations

Each backend process (pyright/ty/pyrefly) typically uses:
Rule of thumb: Allow ~500 MB per backend. For --max-backends 8, reserve ~4 GB RAM for the pool.

Memory-Constrained Recommendations

If running on systems with limited RAM (e.g., 8 GB with other applications):
Or monitor with:

Performance Tuning

Monorepo with Frequent Switches

Problem: Switching between 5 projects every few minutes. Solution:

Single Project with Nested Venvs

Problem: Main project + test venv + docs venv (3 total). Solution:

CI/CD or Short-Lived Sessions

Problem: Running typemux-cc in automated environments (tests, CI). Solution:
Start with defaults (--max-backends 8 --backend-ttl 1800) and adjust based on grep "Evicting" /tmp/typemux-cc.log frequency.