hero_proc forks managed daemons without propagating PATH_ROOT — daemons panic at startup #109

Closed
opened 2026-05-19 15:30:38 +00:00 by timur · 2 comments
Owner

Context

Discovered by the hero_skills#261 agent while bootstrapping hero_service. The agent could launch both hero_service_server and hero_service_admin binaries directly and they worked fine, but when hero_proc start forked them as managed daemons they panicked at startup because PATH_ROOT wasn't in their environment.

What to do

Pick one (or both):

  • Propagate the parent env, or at least propagate the Hero env vars (PATH_ROOT, HERO_SOCKET_DIR, etc.), from the supervisor to the child at fork time.
  • Persist Hero env vars under ~/hero/cfg/env/ and have managed daemons source those at startup (matches the existing forgejo.env / secrets.env pattern).

The persist-and-load path is the more durable fix since it survives hero_proc restart without depending on whoever started the supervisor.

Acceptance

  • hero_proc start <service> works for a service that requires PATH_ROOT without the user explicitly exporting it in hero_proc's shell.
  • Existing services unaffected.
## Context Discovered by the [hero_skills#261 agent](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/261#issuecomment-34264) while bootstrapping `hero_service`. The agent could launch both `hero_service_server` and `hero_service_admin` binaries directly and they worked fine, but when `hero_proc start` forked them as managed daemons they panicked at startup because `PATH_ROOT` wasn't in their environment. ## What to do Pick one (or both): - **Propagate the parent env**, or at least propagate the Hero env vars (`PATH_ROOT`, `HERO_SOCKET_DIR`, etc.), from the supervisor to the child at fork time. - **Persist Hero env vars** under `~/hero/cfg/env/` and have managed daemons source those at startup (matches the existing `forgejo.env` / `secrets.env` pattern). The persist-and-load path is the more durable fix since it survives `hero_proc` restart without depending on whoever started the supervisor. ## Acceptance - `hero_proc start <service>` works for a service that requires `PATH_ROOT` without the user explicitly exporting it in `hero_proc`'s shell. - Existing services unaffected. ## Related - [hero_skills#261](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/261) — discovery context. - Parent META: [hero_skills#262](https://forge.ourworld.tf/lhumina_code/hero_skills/issues/262).
Author
Owner

Starting work on this. Branch: issue-109-path-root-env (off development).

Investigation summary:

  • hero_proc_server spawns child processes via tokio::process::Command in crates/hero_proc_server/src/supervisor/executor.rs (run_job_regular / run_job_pty).
  • No env_clear() is called, so children DO inherit the supervisor parent env by default. The added vars are only context secrets + the job spec's env map.
  • The bug therefore reproduces when hero_proc_server itself is launched without PATH_ROOT / HERO_SOCKET_DIR etc. in its own environment (e.g. via screen/daemon mode, without a login shell that sources ~/hero/cfg/env/*.env). Children then also lack them.

Picking option (B) — persist-and-load, matches the existing forgejo.env / secrets.env pattern and survives supervisor restart:

  • At hero_proc_server startup, before child processes can spawn, read ~/hero/cfg/env/*.env and inject any export KEY=VALUE lines into std::env (without overriding values already present — the user's shell still wins).
  • Children then inherit those vars automatically through the existing fork path. No change to the spawn code needed.

Will push once cargo check is clean.

Starting work on this. Branch: `issue-109-path-root-env` (off `development`). Investigation summary: - `hero_proc_server` spawns child processes via `tokio::process::Command` in `crates/hero_proc_server/src/supervisor/executor.rs` (`run_job_regular` / `run_job_pty`). - No `env_clear()` is called, so children DO inherit the supervisor parent env by default. The added vars are only context secrets + the job spec's `env` map. - The bug therefore reproduces when **`hero_proc_server` itself is launched without `PATH_ROOT` / `HERO_SOCKET_DIR` etc.** in its own environment (e.g. via screen/daemon mode, without a login shell that sources `~/hero/cfg/env/*.env`). Children then also lack them. Picking option **(B)** — persist-and-load, matches the existing `forgejo.env` / `secrets.env` pattern and survives supervisor restart: - At `hero_proc_server` startup, before child processes can spawn, read `~/hero/cfg/env/*.env` and inject any `export KEY=VALUE` lines into `std::env` (without overriding values already present — the user's shell still wins). - Children then inherit those vars automatically through the existing fork path. No change to the spawn code needed. Will push once `cargo check` is clean.
Author
Owner

Implemented in branch issue-109-path-root-env (commit 72849b8).

Root cause: hero_proc_server spawns children via tokio::process::Command without env_clear(), so children inherit the supervisor env. When the supervisor itself is launched without HERO_* vars in its environment (screen, systemd, non-login shell), children panic on missing PATH_ROOT / HERO_SOCKET_DIR.

Fix: New hero_proc_server::env_load runs at startup, scans ~/hero/cfg/env/*.env, parses minimal shell-style env files (supports export K=V, comments, quoted values), and calls std::env::set_var for each entry — only if the key is not already set, so explicit shell overrides still win. Existing fork path needs no changes; children inherit naturally.

  • HERO_CFG_ENV_DIR overrides the dir for tests.
  • set_var runs before tokio spawns threads (2024-edition safety contract).
  • Unit tests cover the parser and precedence.

Diff: 3 files / +284 lines (crates/hero_proc_server/src/env_load.rs, lib.rs, main.rs). Branch pushed; ready for review.

Implemented in branch `issue-109-path-root-env` (commit 72849b8). **Root cause:** `hero_proc_server` spawns children via `tokio::process::Command` without `env_clear()`, so children inherit the supervisor env. When the supervisor itself is launched without `HERO_*` vars in its environment (screen, systemd, non-login shell), children panic on missing `PATH_ROOT` / `HERO_SOCKET_DIR`. **Fix:** New `hero_proc_server::env_load` runs at startup, scans `~/hero/cfg/env/*.env`, parses minimal shell-style env files (supports `export K=V`, comments, quoted values), and calls `std::env::set_var` for each entry — **only if the key is not already set**, so explicit shell overrides still win. Existing fork path needs no changes; children inherit naturally. - `HERO_CFG_ENV_DIR` overrides the dir for tests. - `set_var` runs before tokio spawns threads (2024-edition safety contract). - Unit tests cover the parser and precedence. Diff: 3 files / +284 lines (`crates/hero_proc_server/src/env_load.rs`, `lib.rs`, `main.rs`). Branch pushed; ready for review.
timur closed this issue 2026-05-20 05:55:14 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_proc#109
No description provided.