chore(ops): Phase 24 — hero_proc lifecycle integration (selfstart + nu_service module + canonical UDS paths) #9

Open
opened 2026-05-06 17:47:09 +00:00 by mik-tf · 1 comment
Owner

Why

hero_assistance is engineering-complete on the v1 peer-to-peer mycelium architecture (per #1 closure). To deploy onto a Hero OS box managed by hero_proc, the service needs lifecycle integration:

  • --start/--stop CLI on _server and _ui per hero_proc_service_selfstart skill
  • scripts/service_hero_assistance.nu lifecycle module per nu_service skill
  • Canonical UDS paths under ~/hero/var/sockets/hero_assistance_*/
  • Configuration via hero_proc secrets (THEME, ADMIN_SECRETS) per hero_proc_meta skill

Today the server binds dual TCP+UDS per D-07 but the UDS path is socket-dir-relative, not canonical. _ui doesn't bind UDS at all. No nu_service module. No hero_proc registration.

What

A. hero_proc selfstart on _server + _ui

Per hero_proc_service_selfstart skill (CLI binary owns lifecycle for both actions):

  • hero_assistance CLI gains --start / --stop flags
  • Registers two hero_proc actions: hero_assistance_server + hero_assistance_ui
  • _server binds:
    • UDS at ~/hero/var/sockets/hero_assistance_server/rpc.sock (canonical)
    • Mycelium TCP per existing D-07 / D-08 (preserved unchanged)
  • _ui binds:
    • UDS at ~/hero/var/sockets/hero_assistance_ui/ui.sock (canonical)
    • Optional TCP for direct browser access (current dev mode)
  • Both daemons run plain foreground when invoked without flags

B. scripts/service_hero_assistance.nu

Per nu_service skill. Provides service_hero_assistance {install,start,stop,status}. Mirrors existing service_proxy.nu / service_claude.nu pattern.

C. hero_proc secrets via hero_proc_meta

Read at startup, NOT from env vars or config files:

  • THEME — defaults to "dark" (used by both _ui SPA and Phase 25 admin dashboard)
  • ADMIN_SECRETS — IP whitelist for admin dashboard (Phase 25 dependency)
  • Optional MYCELIUM_BIND — overrides D-08 broad-bind if customer policy needs targeted binding

D. buildenv.sh updates

  • BINARIES: list all 4 bins (hero_assistance, hero_assistance_server, hero_assistance_ui, hero_assistance_app)

Acceptance

  • hero_assistance --start registers both actions and brings up server + ui
  • hero_assistance --stop cleanly unregisters and stops
  • service_hero_assistance install builds + installs binaries to ~/hero/bin/
  • service_hero_assistance start/stop/status works end-to-end
  • hero_proc service list shows both actions running
  • UDS sockets at canonical paths
  • THEME read from hero_proc secrets at startup
  • D-04 / D-07 / D-08 / D-20 invariants preserved (mycelium TCP + per-recipient /events filter unchanged)
  • All 225 existing native tests pass; no regressions

Files to touch

  • crates/hero_assistance/src/main.rs — CLI lifecycle
  • crates/hero_assistance_server/src/main.rs — UDS path canonicalization, secrets read
  • crates/hero_assistance_ui/src/main.rs — UDS bind, secrets read
  • scripts/service_hero_assistance.nu — NEW
  • buildenv.sh — BINARIES expansion

Out of scope

  • Admin dashboard UI (Phase 25)
  • Customer SPA island integration (Phase 26)
  • hero_demo registration (Phase 27)

References

  • Skill hero_proc_service_selfstart
  • Skill nu_service
  • Skill hero_proc_meta
  • Skill hero_sockets
## Why hero_assistance is engineering-complete on the v1 peer-to-peer mycelium architecture (per #1 closure). To deploy onto a Hero OS box managed by `hero_proc`, the service needs lifecycle integration: - `--start`/`--stop` CLI on `_server` and `_ui` per `hero_proc_service_selfstart` skill - `scripts/service_hero_assistance.nu` lifecycle module per `nu_service` skill - Canonical UDS paths under `~/hero/var/sockets/hero_assistance_*/` - Configuration via `hero_proc` secrets (THEME, ADMIN_SECRETS) per `hero_proc_meta` skill Today the server binds dual TCP+UDS per D-07 but the UDS path is socket-dir-relative, not canonical. `_ui` doesn't bind UDS at all. No `nu_service` module. No hero_proc registration. ## What ### A. `hero_proc` selfstart on `_server` + `_ui` Per `hero_proc_service_selfstart` skill (CLI binary owns lifecycle for both actions): - `hero_assistance` CLI gains `--start` / `--stop` flags - Registers two hero_proc actions: `hero_assistance_server` + `hero_assistance_ui` - `_server` binds: - UDS at `~/hero/var/sockets/hero_assistance_server/rpc.sock` (canonical) - Mycelium TCP per existing D-07 / D-08 (preserved unchanged) - `_ui` binds: - UDS at `~/hero/var/sockets/hero_assistance_ui/ui.sock` (canonical) - Optional TCP for direct browser access (current dev mode) - Both daemons run plain foreground when invoked without flags ### B. `scripts/service_hero_assistance.nu` Per `nu_service` skill. Provides `service_hero_assistance {install,start,stop,status}`. Mirrors existing `service_proxy.nu` / `service_claude.nu` pattern. ### C. `hero_proc` secrets via `hero_proc_meta` Read at startup, NOT from env vars or config files: - `THEME` — defaults to `"dark"` (used by both _ui SPA and Phase 25 admin dashboard) - `ADMIN_SECRETS` — IP whitelist for admin dashboard (Phase 25 dependency) - Optional `MYCELIUM_BIND` — overrides D-08 broad-bind if customer policy needs targeted binding ### D. `buildenv.sh` updates - `BINARIES`: list all 4 bins (`hero_assistance`, `hero_assistance_server`, `hero_assistance_ui`, `hero_assistance_app`) ## Acceptance - [ ] `hero_assistance --start` registers both actions and brings up server + ui - [ ] `hero_assistance --stop` cleanly unregisters and stops - [ ] `service_hero_assistance install` builds + installs binaries to `~/hero/bin/` - [ ] `service_hero_assistance start/stop/status` works end-to-end - [ ] `hero_proc service list` shows both actions running - [ ] UDS sockets at canonical paths - [ ] THEME read from hero_proc secrets at startup - [ ] D-04 / D-07 / D-08 / D-20 invariants preserved (mycelium TCP + per-recipient `/events` filter unchanged) - [ ] All 225 existing native tests pass; no regressions ## Files to touch - `crates/hero_assistance/src/main.rs` — CLI lifecycle - `crates/hero_assistance_server/src/main.rs` — UDS path canonicalization, secrets read - `crates/hero_assistance_ui/src/main.rs` — UDS bind, secrets read - `scripts/service_hero_assistance.nu` — NEW - `buildenv.sh` — BINARIES expansion ## Out of scope - Admin dashboard UI (Phase 25) - Customer SPA island integration (Phase 26) - hero_demo registration (Phase 27) ## References - Skill `hero_proc_service_selfstart` - Skill `nu_service` - Skill `hero_proc_meta` - Skill `hero_sockets`
Author
Owner

Phase 24 part A landed (s43) + body reconciliation

What landed in s43

Phase 24 part A — additive, no behaviour change to existing code paths:

  • crates/hero_assistance_ui/src/admin_secrets.rs — canonical module from hero_ui_whitelists skill, dropped in verbatim. SECRET_KEY="ADMIN_SECRETS" + SECRET_CONTEXT="core"; reads from hero_proc; fail-open on supervisor-down (HeroProcUnreachable.permits() → true) and on missing/all-invalid secret (NotSet / Allow(empty_vec) → true).
  • scripts/service_assistance.nu — canonical nu_service module per the nu_service skill (short name strips hero_ prefix per the skill rule — service_assistance.nu, NOT service_hero_assistance.nu). Action specs transcribed verbatim from crates/hero_assistance/src/main.rs::build_service_definition so service_assistance starthero_assistance --start.
  • 5 phase24 unit tests on admin_secrets: parse_csv whitespace/empty/invalid, fail-open on supervisor unreachable, fail-open on secret-unset, blocks non-whitelisted IP, permits whitelisted IP.

Test posture: 248 → 253 native passing (+5 phase24 unit tests on _ui lib). Documented phase10_multi_project_merged_stream_tags_by_project_id flake reproduced under concurrent load, passes in isolation as always (transient since s12). No regression.

Body reconciliation — four discoveries from codebase confirmation

The issue body needs amendment based on what's actually in the codebase as of s43:

  1. Lifecycle CLI is already done (commit ≤ s38). crates/hero_assistance/src/main.rs already has --start / --stop, self_start / self_stop, full ServiceBuilder + ActionBuilder for both daemons, kill_other socket lists, health_checks, retry policies, and restart_service. No changes needed to the manager binary in this phase.

  2. Singular UDS dir is canonical — not per-binary. The body says:

    "_server binds: UDS at ~/hero/var/sockets/hero_assistance_server/rpc.sock"
    "_ui binds: UDS at ~/hero/var/sockets/hero_assistance_ui/ui.sock"

    But the hero_sockets skill is explicit: multi-binary services share one directory named after the service, not the binary. Current code already uses ~/hero/var/sockets/hero_assistance/{rpc,events,ui}.sock — singular, matching the skill. No path migration needed.

  3. nu_service file naming — per nu_service skill, short name strips hero_ prefix. File is scripts/service_assistance.nu, not scripts/service_hero_assistance.nu. The skill is unambiguous: hero_proxyservice_proxy.nu, hero_dbservice_db.nu, etc.

  4. ADMIN_SECRETS framing — the body lists ADMIN_SECRETS under "C. hero_proc secrets via hero_proc_meta" as a "Phase 25 dependency". In reality it was deferred FROM Phase 25 part 2c (s42) TO Phase 24, per the s42 closure note. The IP whitelist is in scope here — admin_secrets.rs has shipped (this session); the hard TCP gate that consumes it is part B (see below).

Phase 24 part B — remaining work (next session, ~0.5 session)

  • Hard TCP gate before HTTP router in _ui/src/main.rs — currently _ui binds UDS only, so the gate has nowhere to live until a TCP listener is added. Either (a) add an optional --tcp <addr> flag to _ui and wire state.admin_list.read().await.permits(ip) into the accept loop per the skill pattern; or (b) defer to Phase 26 (customer SPA island) where direct browser-over-TCP becomes a real consumer.
  • End-to-end exercise of D-23 admin gate under --auth-mode=hero (real hero_proc identity, not just dev-mode-bypass).
  • THEME secret bootstrap — currently no consumer exists in _ui or _server (admin SPA ThemePreference enum exists but is never populated from a hero_proc secret). Adding speculative reads is axiom-growth per the project's design principles; defer to whichever phase adds the consumer (likely Phase 26 island work or a Phase 25 follow-up).

Files to touch (24a, this session)

  • NEW: crates/hero_assistance_ui/src/admin_secrets.rs
  • NEW: scripts/service_assistance.nu
  • EDIT: crates/hero_assistance_ui/src/lib.rs (re-export module)
  • EDIT: crates/hero_assistance_ui/Cargo.toml (add hero_rpc_openrpc with transport feature)

Acceptance status

  • hero_assistance --start registers both actions and brings up server + ui (already in place pre-s43)
  • hero_assistance --stop cleanly unregisters and stops (already in place pre-s43)
  • service_assistance install/start/stop/status available via scripts/service_assistance.nu (s43)
  • UDS sockets at canonical paths (singular hero_assistance/ directory, matching skill — was already correct)
  • D-04 / D-07 / D-08 / D-20 invariants preserved (no source change to identity / mycelium / dispatcher / events-TCP)
  • All 248 existing native tests pass; +5 phase24 admin_secrets unit tests (_ui lib)
  • Part B: hard TCP gate wiring (deferred — no _ui TCP listener exists)
  • Part B: live D-23 admin gate exercise under --auth-mode=hero
  • Out of scope this issue: THEME secret bootstrap (no consumer; defer to Phase 26)
## Phase 24 part A landed (s43) + body reconciliation ### What landed in s43 Phase 24 part A — additive, no behaviour change to existing code paths: - **`crates/hero_assistance_ui/src/admin_secrets.rs`** — canonical module from `hero_ui_whitelists` skill, dropped in verbatim. `SECRET_KEY="ADMIN_SECRETS"` + `SECRET_CONTEXT="core"`; reads from hero_proc; fail-open on supervisor-down (`HeroProcUnreachable.permits()` → true) and on missing/all-invalid secret (`NotSet` / `Allow(empty_vec)` → true). - **`scripts/service_assistance.nu`** — canonical nu_service module per the `nu_service` skill (short name strips `hero_` prefix per the skill rule — `service_assistance.nu`, NOT `service_hero_assistance.nu`). Action specs transcribed verbatim from `crates/hero_assistance/src/main.rs::build_service_definition` so `service_assistance start` ≡ `hero_assistance --start`. - **5 phase24 unit tests** on `admin_secrets`: parse_csv whitespace/empty/invalid, fail-open on supervisor unreachable, fail-open on secret-unset, blocks non-whitelisted IP, permits whitelisted IP. Test posture: 248 → 253 native passing (+5 phase24 unit tests on `_ui` lib). Documented `phase10_multi_project_merged_stream_tags_by_project_id` flake reproduced under concurrent load, passes in isolation as always (transient since s12). No regression. ### Body reconciliation — four discoveries from codebase confirmation The issue body needs amendment based on what's actually in the codebase as of s43: 1. **Lifecycle CLI is already done** (commit ≤ s38). `crates/hero_assistance/src/main.rs` already has `--start` / `--stop`, `self_start` / `self_stop`, full `ServiceBuilder` + `ActionBuilder` for both daemons, kill_other socket lists, health_checks, retry policies, and `restart_service`. No changes needed to the manager binary in this phase. 2. **Singular UDS dir is canonical** — not per-binary. The body says: > "_server binds: UDS at `~/hero/var/sockets/hero_assistance_server/rpc.sock`" > "_ui binds: UDS at `~/hero/var/sockets/hero_assistance_ui/ui.sock`" But the `hero_sockets` skill is explicit: multi-binary services share **one** directory named after the **service**, not the binary. Current code already uses `~/hero/var/sockets/hero_assistance/{rpc,events,ui}.sock` — singular, matching the skill. No path migration needed. 3. **nu_service file naming** — per `nu_service` skill, short name strips `hero_` prefix. File is `scripts/service_assistance.nu`, not `scripts/service_hero_assistance.nu`. The skill is unambiguous: `hero_proxy` → `service_proxy.nu`, `hero_db` → `service_db.nu`, etc. 4. **ADMIN_SECRETS framing** — the body lists ADMIN_SECRETS under "C. hero_proc secrets via hero_proc_meta" as a "Phase 25 dependency". In reality it was deferred FROM Phase 25 part 2c (s42) TO Phase 24, per the s42 closure note. The IP whitelist is in scope here — `admin_secrets.rs` has shipped (this session); the hard TCP gate that consumes it is part B (see below). ### Phase 24 part B — remaining work (next session, ~0.5 session) - **Hard TCP gate before HTTP router** in `_ui/src/main.rs` — currently `_ui` binds **UDS only**, so the gate has nowhere to live until a TCP listener is added. Either (a) add an optional `--tcp <addr>` flag to `_ui` and wire `state.admin_list.read().await.permits(ip)` into the accept loop per the skill pattern; or (b) defer to Phase 26 (customer SPA island) where direct browser-over-TCP becomes a real consumer. - **End-to-end exercise of D-23 admin gate** under `--auth-mode=hero` (real hero_proc identity, not just dev-mode-bypass). - **THEME secret bootstrap** — currently no consumer exists in `_ui` or `_server` (admin SPA `ThemePreference` enum exists but is never populated from a hero_proc secret). Adding speculative reads is axiom-growth per the project's design principles; defer to whichever phase adds the consumer (likely Phase 26 island work or a Phase 25 follow-up). ### Files to touch (24a, this session) - NEW: `crates/hero_assistance_ui/src/admin_secrets.rs` - NEW: `scripts/service_assistance.nu` - EDIT: `crates/hero_assistance_ui/src/lib.rs` (re-export module) - EDIT: `crates/hero_assistance_ui/Cargo.toml` (add `hero_rpc_openrpc` with `transport` feature) ### Acceptance status - [x] `hero_assistance --start` registers both actions and brings up server + ui (already in place pre-s43) - [x] `hero_assistance --stop` cleanly unregisters and stops (already in place pre-s43) - [x] `service_assistance install/start/stop/status` available via `scripts/service_assistance.nu` (s43) - [x] UDS sockets at canonical paths (singular `hero_assistance/` directory, matching skill — was already correct) - [x] D-04 / D-07 / D-08 / D-20 invariants preserved (no source change to identity / mycelium / dispatcher / events-TCP) - [x] All 248 existing native tests pass; +5 phase24 admin_secrets unit tests (`_ui` lib) - [ ] **Part B**: hard TCP gate wiring (deferred — no `_ui` TCP listener exists) - [ ] **Part B**: live D-23 admin gate exercise under `--auth-mode=hero` - [ ] **Out of scope this issue**: THEME secret bootstrap (no consumer; defer to Phase 26)
Sign in to join this conversation.
No labels
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_assistance#9
No description provided.