# Plan: On-the-Fly Model Swap (Multi-Model Routing)

**Goal:** Maven can switch between LLM models at runtime — including using a remote `llama-server` instance on workpc over LAN — without restarting the daemon. The phraser, router (LLM router), and replier all point at a dynamic backend that can be re-pointed via IPC.

**Done when:**
- `internal/llm/client.go` supports a dynamic base URL that can be swapped at runtime
- `internal/phraser/llmphraser.go` can hot-swap its backend (stop current `llama-server` subprocess, start new one, or point to a remote one)
- Remote model config: `phraser.mode = "remote"` with `remote_url = "http://workpc:8080"` — connects without spawning a subprocess
- Swap is triggered via IPC (`MethodSwapModel`) with a new config block — no daemon restart
- Router's `LLMRouter` (in `internal/router/llmrouter.go`) follows the same swap
- Fallback: if the new model fails to respond within timeout, the old model stays active (never leave the user with no model)

**Scope:**
- `internal/llm/client.go` — add `SetBaseURL(string)` method for runtime re-pointing
- `internal/phraser/llmphraser.go` — add `Swap(Config) error` method
- `internal/router/llmrouter.go` — already holds a `Completer` interface; swap the underlying client
- `cmd/mavend/voice.go` — re-creates `LLMReplier` when model changes
- New IPC method `MethodSwapModel` in `internal/ipc/api.go`
- Config: `phraser.mode` field (`local|remote`), `phraser.remote_url`

**Steps:**
1. Add `SetBaseURL(url string)` to `internal/llm/client.go` — atomically swaps the `base` field under a mutex (add `sync.RWMutex` to `Client`)
2. Add `Swap(cfg Config) error` to `internal/phraser/llmphraser.go` — stops current `llama-server` (via `Close()`), starts new one with new config, or connects to remote URL without spawning
3. Extend `PhraserConfig` in `internal/config/config.go` with `Mode string` (`"local"` or `"remote"`) and `RemoteURL string`
4. Create new `internal/llm/manager.go` — manages a set of named backends, allows `SwitchModel(name)` that re-wires phraser + LLM router + replier atomically
5. Add `MethodSwapModel` to `internal/ipc/api.go` with request `{model_path, mode, remote_url, n_gpu_layers, n_ctx}`
6. Wire swap handler in `cmd/mavend/main.go` — `srv.ModelSwapFn` called from IPC dispatch, re-wires phraser, rebuilds router with new LLMRouter, rebuilds replier
7. Add `model` block to `config.Config` with named model definitions (local paths + remote URLs)
8. Test: swap between local `StubPhraser` and remote llama-server on LAN; verify phraser + router + replier all use the new backend
