From 37be2cd3055a8b3792c93603cdad30e161781630 Mon Sep 17 00:00:00 2001 From: Eureka Date: Wed, 11 Nov 2026 09:21:26 +0000 Subject: [PATCH] mind-self-run: the child's HUGINN_SESSION is its run's label Spawner::spawn takes the session to export; the Self run gives the bare run label (the spelling the run's opening receipt carries). The Persona gives none. Co-Authored-By: Claude Sonnet 5.5 --- crates/mind-body/src/persona.rs | 2 +- crates/mind-body/src/persona/tests.rs | 4 +-- crates/mind-body/src/self_run.rs | 29 ++++++++++++---- crates/mind-body/src/self_run/tests.rs | 34 +++++++++++++++---- .../src/self_run/tests/process/lease_child.rs | 23 +++++++++++-- crates/mind-body/src/self_run/tests/resume.rs | 6 ++-- crates/mind-body/src/testkit.rs | 7 ++-- crates/mind-body/tests/public_surface.txt | 2 +- 8 files changed, 83 insertions(+), 24 deletions(-) diff --git a/crates/mind-body/src/persona.rs b/crates/mind-body/src/persona.rs index 5de05f5..d65e922 100644 --- a/crates/mind-body/src/persona.rs +++ b/crates/mind-body/src/persona.rs @@ -1006,7 +1006,7 @@ pub(crate) fn start_session( Ok(Lent::Granted(lease)) => lease, Ok(Lent::Refused(_)) | Err(_) => return Ok(Err(Failure::Lease)), }; - let Ok(child) = organs.spawner.spawn(&persona_args(session_id, &config.model, &schema, &prompt), lease.token()) else { return Ok(Err(Failure::Session)) }; + let Ok(child) = organs.spawner.spawn(&persona_args(session_id, &config.model, &schema, &prompt), lease.token(), None) else { return Ok(Err(Failure::Session)) }; Ok(Ok(Started { child, lease, started_ms })) } diff --git a/crates/mind-body/src/persona/tests.rs b/crates/mind-body/src/persona/tests.rs index 35a0446..548f066 100644 --- a/crates/mind-body/src/persona/tests.rs +++ b/crates/mind-body/src/persona/tests.rs @@ -247,7 +247,7 @@ struct FakeSession { } impl Spawner for FakeSession { - fn spawn(&self, args: &[String], _token: &TokenFd) -> Result> { + fn spawn(&self, args: &[String], _token: &TokenFd, _session: Option<&str>) -> Result> { if self.refuse.get() { return Err(anyhow!("refused")); } @@ -2711,7 +2711,7 @@ impl Child for Timed { struct ScriptedSpawner(RefCell>); impl crate::self_run::Spawner for ScriptedSpawner { - fn spawn(&self, _args: &[String], _token: &TokenFd) -> Result> { + fn spawn(&self, _args: &[String], _token: &TokenFd, _session: Option<&str>) -> Result> { self.0.borrow_mut().pop_front().map(|child| Box::new(child) as Box).ok_or_else(|| anyhow!("no more processes")) } } diff --git a/crates/mind-body/src/self_run.rs b/crates/mind-body/src/self_run.rs index a919156..9e6a4de 100644 --- a/crates/mind-body/src/self_run.rs +++ b/crates/mind-body/src/self_run.rs @@ -150,6 +150,8 @@ const ENV_SCRUB_VARIABLE: &str = "CLAUDE_CODE_SUBPROCESS_ENV_SCRUB"; /// Optional, set by the unit: `off` turns that scrub off for a run whose user holds root, where it /// protects nothing and its sandbox's no_new_privs would only stop `sudo`. Anything else keeps it on. const SCRUB_VARIABLE: &str = "MIND_SELF_SCRUB"; +/// The variable the child's `huginn` reads its `--session` from: the run's label, the id the start message names. +const SESSION_VARIABLE: &str = "HUGINN_SESSION"; /// The name the start message tells her to admit as. pub const AGENT: &str = "mind-self-run"; /// The namespace of the session id: the run id is the name in it. @@ -227,6 +229,12 @@ fn flush_text(why: Why) -> String { format!("{cause} {FLUSH_MESSAGE} Close each brief that is done by the closing rule; a brief whose change is not on its default branch stays open, or is superseded by your own follow-up when it waits on someone else, and the next session continues it.") } +/// The label of a run, the last segment of its id (`:run: