config: hot-reload via RPC, Arc<Config> for cheap sharing

Config is now stored in RwLock<Arc<Config>> instead of OnceLock<Config>.
get() returns Arc<Config> (cheap clone), and reload() re-reads from disk.

New RPC: "reload-config" — reloads config.jsonl without restarting
the daemon. Logs the change to daemon.log. Useful for switching
between API backends and claude accounts without losing in-flight
tasks.

New CLI: poc-memory agent daemon reload-config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kent Overstreet 2026-03-19 13:41:13 -04:00
parent 0944ecc43f
commit af3171d6ec
4 changed files with 43 additions and 7 deletions

View file

@ -13,9 +13,9 @@
// {"group": "orientation", "keys": ["where-am-i.md"], "source": "file"}
use std::path::PathBuf;
use std::sync::OnceLock;
use std::sync::{Arc, OnceLock, RwLock};
static CONFIG: OnceLock<Config> = OnceLock::new();
static CONFIG: OnceLock<RwLock<Arc<Config>>> = OnceLock::new();
#[derive(Debug, Clone, PartialEq)]
pub enum ContextSource {
@ -210,7 +210,23 @@ fn expand_home(path: &str) -> PathBuf {
}
}
/// Get the global config (loaded once on first access).
pub fn get() -> &'static Config {
CONFIG.get_or_init(Config::load_from_file)
/// Get the global config (cheap Arc clone).
pub fn get() -> Arc<Config> {
CONFIG
.get_or_init(|| RwLock::new(Arc::new(Config::load_from_file())))
.read()
.unwrap()
.clone()
}
/// Reload the config from disk. Returns true if changed.
pub fn reload() -> bool {
let lock = CONFIG.get_or_init(|| RwLock::new(Arc::new(Config::load_from_file())));
let new = Config::load_from_file();
let mut current = lock.write().unwrap();
let changed = format!("{:?}", **current) != format!("{:?}", new);
if changed {
*current = Arc::new(new);
}
changed
}