Reload daemon configuration without restarting (#3365)

* feat(daemon): reload configuration without restarting

Keep config validation, reloadability classification, override handling, and atomic runtime application inside the daemon so local and remote clients share one authoritative workflow.

* fix(daemon): preserve reload resource ownership

Keep every materialized provider client under daemon-lifetime ownership and classify speech overrides from resolved providers. Restore the complete WebSocket config-store test contract exposed by CI.
This commit is contained in:
Mohamed Boudra
2026-08-14 22:46:32 +02:00
committed by GitHub
parent 75bbca4a1b
commit 4748aad103
36 changed files with 2590 additions and 246 deletions
+4
View File
@@ -202,9 +202,13 @@ Detaching is an explicit lifecycle action, not a creation flag. The agent keeps
paseo daemon start # Start the daemon
paseo daemon start --web-ui # Start and serve the bundled web UI
paseo daemon status # Check status
paseo reload # Reload config.json (top-level alias)
paseo daemon reload # Reload config.json
paseo daemon stop # Stop the daemon
```
Reload validates the whole file, applies runtime-safe changes, and reports `appliedPaths`, `restartRequiredPaths`, and `overrideControlledPaths`. Human output prints `paseo daemon restart` only when a changed setting needs it. Use `--json` or `--format yaml` for the structured result, and `--host` to reload a remote daemon's own configuration file. An older host that does not support reload returns an update-host error.
Use `PASEO_HOME` to run multiple isolated daemon instances.
## Hub
+23 -1
View File
@@ -49,6 +49,28 @@ Minimal example that configures listening address, hostnames, and MCP:
`daemon.hostnames` is the primary field. The old `daemon.allowedHosts` name still works as a deprecated alias for backward compatibility.
## Apply changes
After saving `config.json`, reload it:
```bash
paseo reload
```
The daemon validates the complete file before applying anything. It applies runtime-safe changes and lists any settings that still need a restart. If it reports restart-required paths, run:
```bash
paseo daemon restart
```
Runtime-safe settings include relay enablement, MCP settings, browser tools, hostnames, CORS origins, trusted proxies, Git process limits, agent and terminal profiles, provider definitions, metadata generation, the app base URL, and provider catalog timeout. Removing one of these settings applies its omitted-field behavior; removing a provider removes it from future launches.
New homes keep relay disabled when you remove `daemon.relay.enabled`. A daemon whose config already omitted this field when it started keeps the legacy relay-enabled behavior for compatibility. Set `daemon.relay.enabled` explicitly when editing an older config.
Listen addresses, authentication, relay endpoints and TLS, worktree allocation, service-proxy addresses, the bundled web UI, logging, speech, voice, credentials, and local model settings require a restart. Reload applies other valid edits in the same file before reporting those paths.
Environment variables and daemon start flags remain authoritative. Reload reports a changed file setting under `overrideControlledPaths` when a launch override prevents it from taking effect. This includes startup settings such as listen addresses, passwords, relay endpoints and TLS, service-proxy and web UI settings, logging, speech, and voice configuration. List settings such as hostnames and CORS origins still append across sources, so values from `config.json` continue to apply. Remove the override and restart the daemon if you want the file value to become authoritative.
## Agent providers
Agent providers, both the first-class ones Paseo ships with and custom entries you add under `agents.providers`, are documented on their own page.
@@ -144,7 +166,7 @@ The easiest way to set a password is with the CLI:
paseo daemon set-password
```
This prompts for a password, writes the bcrypt hash to `config.json`, and tells you to restart the daemon.
This prompts for a password, writes the bcrypt hash to `config.json`, and tells you to restart the daemon. Authentication is a startup setting, so `paseo reload` will also report it as restart-required.
Alternatively, set the `PASEO_PASSWORD` environment variable (plaintext, hashed automatically at startup):
+1 -1
View File
@@ -91,4 +91,4 @@ If the host was already paired through the relay, Paseo adds the direct connecti
- **Connection timed out:** Check that Tailscale is connected on both devices and that you used the daemon machine's Tailscale IP.
- **Connection refused:** Run `paseo daemon status` and confirm the daemon is running on the configured IP and port.
- **Config change has no effect:** Restart the daemon after editing `config.json`.
- **Config change has no effect:** Run `paseo reload`. `daemon.listen` is a startup setting, so restart when the command reports it.
+2
View File
@@ -16,6 +16,8 @@ Everything beyond the [supported providers](/docs/supported-providers) lives und
- **Add ACP agents**, Gemini CLI, Hermes, or any agent speaking the Agent Client Protocol over stdio.
- **Disable** a provider you don't use.
Run `paseo reload` after editing the file. Provider changes apply to future launches without restarting the daemon.
Provider IDs must be lowercase alphanumeric with hyphens (`/^[a-z][a-z0-9-]*$/`). Every custom entry needs `extends` (a first-class provider ID or `"acp"`) and a `label`.
The examples below are a quick tour. The full, up-to-date reference is on GitHub: [docs/custom-providers.md](https://github.com/getpaseo/paseo/blob/main/docs/custom-providers.md).
+6 -4
View File
@@ -53,7 +53,7 @@ If you'd rather pin it directly, set the binary path in `~/.paseo/config.json`:
}
```
`command` is `[binary, ...args]` and fully replaces the default launch command for that provider. Find the real path with `which -a claude`. `type -a claude` also tells you if `claude` is only a shell alias or function, those won't work, Paseo runs the binary directly, so use the path it points to. Restart the daemon after editing (see [below](#i-changed-configjson-but-nothing-happened)).
`command` is `[binary, ...args]` and fully replaces the default launch command for that provider. Find the real path with `which -a claude`. `type -a claude` also tells you if `claude` is only a shell alias or function, those won't work, Paseo runs the binary directly, so use the path it points to. Reload the configuration after editing (see [below](#i-changed-configjson-but-nothing-happened)).
For alternative endpoints, multiple profiles, custom binaries, and ACP agents, see [Custom providers](/docs/custom-providers). For per-agent install links, see [Supported providers](/docs/supported-providers).
@@ -84,13 +84,15 @@ Desktop app log location:
## I changed config.json but nothing happened
`config.json` is read when the daemon starts. Restart it after editing:
Reload the file after editing:
```bash
paseo daemon restart
paseo reload
```
Or in the app, open **Settings → your host → Overview** and use **Restart daemon**. Running agents keep going, and clients reconnect automatically.
Paseo applies runtime-safe settings and names any paths that require a restart. Invalid JSON or a schema error applies nothing; fix the reported error and run the command again. If a launch environment variable or flag owns a changed setting, reload reports it separately.
Run `paseo daemon restart` only when reload requests it. In the app, open **Settings → your host → Overview** and use **Restart daemon**. Running agents keep going, and clients reconnect automatically.
## Still stuck?