per-agent /state dir for durable notes; manager sees them via /agents
This commit is contained in:
parent
7be64c5e66
commit
ff8f8c7c56
10 changed files with 66 additions and 10 deletions
|
|
@ -26,6 +26,11 @@ pub const CONTAINER_RUNTIME_MOUNT: &str = "/run/hive";
|
|||
/// Persistent across destroy/recreate so OAuth login survives.
|
||||
pub const CONTAINER_CLAUDE_MOUNT: &str = "/root/.claude";
|
||||
|
||||
/// Mount point of the per-agent durable knowledge dir inside the container.
|
||||
/// Agents are told (system prompt) to keep `notes.md` and any other scratch
|
||||
/// state here; persists across destroy/recreate.
|
||||
pub const CONTAINER_NOTES_MOUNT: &str = "/state";
|
||||
|
||||
const GIT_NAME: &str = "hive-c0re";
|
||||
const GIT_EMAIL: &str = "hive-c0re@hyperhive";
|
||||
|
||||
|
|
@ -98,6 +103,7 @@ fn validate(name: &str) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn spawn(
|
||||
name: &str,
|
||||
hyperhive_flake: &str,
|
||||
|
|
@ -105,16 +111,18 @@ pub async fn spawn(
|
|||
proposed_dir: &Path,
|
||||
applied_dir: &Path,
|
||||
claude_dir: &Path,
|
||||
notes_dir: &Path,
|
||||
dashboard_port: u16,
|
||||
) -> Result<()> {
|
||||
validate(name)?;
|
||||
setup_proposed(proposed_dir, name).await?;
|
||||
setup_applied(applied_dir, name, hyperhive_flake, dashboard_port).await?;
|
||||
ensure_claude_dir(claude_dir)?;
|
||||
ensure_state_dir(notes_dir)?;
|
||||
let container = container_name(name);
|
||||
let flake_ref = format!("{}#default", applied_dir.display());
|
||||
run(&["create", &container, "--flake", &flake_ref]).await?;
|
||||
set_nspawn_flags(&container, agent_dir, claude_dir)?;
|
||||
set_nspawn_flags(&container, agent_dir, claude_dir, notes_dir)?;
|
||||
set_resource_limits(&container)?;
|
||||
systemd_daemon_reload().await?;
|
||||
run(&["start", &container]).await
|
||||
|
|
@ -176,14 +184,16 @@ pub async fn rebuild(
|
|||
agent_dir: &Path,
|
||||
applied_dir: &Path,
|
||||
claude_dir: &Path,
|
||||
notes_dir: &Path,
|
||||
dashboard_port: u16,
|
||||
) -> Result<()> {
|
||||
validate(name)?;
|
||||
setup_applied(applied_dir, name, hyperhive_flake, dashboard_port).await?;
|
||||
ensure_claude_dir(claude_dir)?;
|
||||
ensure_state_dir(notes_dir)?;
|
||||
let container = container_name(name);
|
||||
let flake_ref = format!("{}#default", applied_dir.display());
|
||||
set_nspawn_flags(&container, agent_dir, claude_dir)?;
|
||||
set_nspawn_flags(&container, agent_dir, claude_dir, notes_dir)?;
|
||||
set_resource_limits(&container)?;
|
||||
systemd_daemon_reload().await?;
|
||||
run(&["update", &container, "--flake", &flake_ref]).await?;
|
||||
|
|
@ -349,6 +359,14 @@ fn ensure_claude_dir(claude_dir: &Path) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_state_dir(notes_dir: &Path) -> Result<()> {
|
||||
if !notes_dir.exists() {
|
||||
std::fs::create_dir_all(notes_dir)
|
||||
.with_context(|| format!("create {}", notes_dir.display()))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initial_agent_nix(name: &str) -> String {
|
||||
format!(
|
||||
"{{ ... }}:\n{{\n # Per-agent overrides for {name}. The manager edits this\n # file (and commits) to customise the agent's NixOS config.\n}}\n",
|
||||
|
|
@ -458,13 +476,19 @@ pub const CONTAINER_MANAGER_AGENTS_MOUNT: &str = "/agents";
|
|||
/// here so lifecycle stays usable as a leaf module).
|
||||
const HOST_AGENTS_ROOT: &str = "/var/lib/hyperhive/agents";
|
||||
|
||||
fn set_nspawn_flags(container: &str, runtime_dir: &Path, claude_dir: &Path) -> Result<()> {
|
||||
fn set_nspawn_flags(
|
||||
container: &str,
|
||||
runtime_dir: &Path,
|
||||
claude_dir: &Path,
|
||||
notes_dir: &Path,
|
||||
) -> Result<()> {
|
||||
let path = format!("/etc/nixos-containers/{container}.conf");
|
||||
let original = std::fs::read_to_string(&path).with_context(|| format!("read {path}"))?;
|
||||
let mut binds = format!(
|
||||
"--bind={runtime}:{CONTAINER_RUNTIME_MOUNT} --bind={claude}:{CONTAINER_CLAUDE_MOUNT}",
|
||||
"--bind={runtime}:{CONTAINER_RUNTIME_MOUNT} --bind={claude}:{CONTAINER_CLAUDE_MOUNT} --bind={notes}:{CONTAINER_NOTES_MOUNT}",
|
||||
runtime = runtime_dir.display(),
|
||||
claude = claude_dir.display(),
|
||||
notes = notes_dir.display(),
|
||||
);
|
||||
if container == MANAGER_NAME {
|
||||
// Manager edits sub-agent proposed/ repos and its own. RW so it can
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue