Skip to content

feat(fleet): route domain plugins to core scripts via bin/hermit-run - #661

Merged
gtapps merged 3 commits into
mainfrom
feat/shared-logic-bin-path
Jul 25, 2026
Merged

feat(fleet): route domain plugins to core scripts via bin/hermit-run#661
gtapps merged 3 commits into
mainfrom
feat/shared-logic-bin-path

Conversation

@gtapps

@gtapps gtapps commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

Installed domain plugins can't reach core's versioned cache dir from their own ${CLAUDE_PLUGIN_ROOT}, so HA's ha-morning-brief had re-implemented core's micro-proposal writer as two inline bun -e blocks and the domain-brainstorm skills told the model to hunt for core's plugin root at runtime. This routes those call sites through the project-resident .claude-code-hermit/bin/hermit-run — a static, layout-independent path — and hardens that dispatcher so it's safe as a cross-plugin entry point. It also folds in three adjacent fixes surfaced while scoping the work.

Changes

Shared-logic path (core + HA/dev/fitness)

  • bin/hermit-run: validate HERMIT_PLUGIN_ROOT by manifest name; collect all marketplace-scan matches and fail loud on ambiguity instead of taking glob order. No claude CLI dependency (cron/systemd watchdog boot paths).
  • hermit-exec.sh: reject a script name containing / or .., so the new permission globs can't reach a .ts outside core's scripts/.
  • micro-proposal.ts: new brief-cycle verb ages the whole queue in one call (re-nudge count-1, expire count-2+, record expiries, one atomic write, JSON verdict). Both briefs and HA's morning brief now drive the lifecycle through it; targeted resolve/nudge semantics are unchanged.
  • Two word-boundary Bash(.claude-code-hermit/bin/hermit-run <script> *) allow entries (synced across apply-settings.ts and hatch Step 8).
  • domain-brainstorm (dev/fitness/HA): read the metrics report via bin/hermit-run; a kill-criteria breach now escalates to the operator rather than instructing the skill to self-retire (the shared segment can't attribute noise to one skill).

Permission ownership (core)

  • hermit-evolve Step 8 delegates the permission merge to apply-settings.ts <file> allow instead of a hand-enumerated prose list that had drifted to 15 of 28 entries and instructed a Write rule the writer strips. apply-settings's allow op now prints each newly-added entry for the run report. Fixes a live bug: the old Edit-based merge is denied under the strict hook profile.

Scope precedence (core)

  • evolve-plan.ts applies local > project precedence when a sibling is installed at both scopes, matching resolve-siblings.ts; the leak-guard test is inverted accordingly.

Dedupe guards

  • dev-hermit's triplicated findHermitDir collapses to one scripts/lib/find-hermit-dir.ts.
  • A root tests/cross-plugin/automode-env.behavior.test.ts fixture matrix guards the three automode-env.ts copies (including a previously-untested invalid-JSON refusal), run by a new path-scoped test-cross-plugin.yml workflow so it never blocks unrelated releases.

Test plan

  • All seven plugin suites pass (scripts/test-all.sh), bunx tsc --noEmit clean.
  • New tests/hermit-run.test.ts (9) covers resolver env/scan/ambiguity + hermit-exec traversal rejection; brief-cycle cases added to scripts.test.ts; evolve leak-guard flipped; new evolve permission-delegation contract in contracts.test.ts; root cross-plugin behavior test (16).
  • Grep gates clean: no bun -e left in ha-morning-brief, no "cannot reach it" in domain-brainstorm, hatch call-path claim updated.
  • Red-check: perturbing one automode-env copy turns the guard red; reverted.

Domain plugins (HA/dev/fitness) now depend on the core version shipping this; required_core_version is synced at release time via /fleet-release.

gtapps and others added 3 commits July 25, 2026 16:20
Installed domain plugins can't reach core's versioned cache dir from their
own ${CLAUDE_PLUGIN_ROOT}, so HA's ha-morning-brief re-implemented core's
micro-proposal writer inline and the domain-brainstorm skills told the model
to hunt for core's root. Route them through the project-resident bin/hermit-run
instead: harden its resolver (validate the env root by manifest, fail loud on
marketplace ambiguity) and add a hermit-exec.sh name guard so the new permission
globs can't reach a script outside core's scripts/. Add a micro-proposal.ts
brief-cycle verb so both briefs age the queue in one call, and move the
per-entry lifecycle into core's writer.

Also: hermit-evolve Step 8 now delegates the permission merge to apply-settings
allow (the hand-list had drifted and was denied under the strict hook profile);
evolve sibling resolution applies local > project precedence; dev's triplicated
findHermitDir collapses to one lib; and a root behavior test plus a path-scoped
workflow guard the three automode-env copies.
Both brief skills render "MP-YYYYMMDD-N (tier N): <question>" and are now
told never to re-read the queue file, so the verdict is their only source
for the tier — without it every morning brief rendered a wrong or missing
tier. HA's Output Format block also still keyed its two "Awaiting decision"
lines on the raw follow_up_count, which step 9a no longer exposes for fresh
entries; relabelled to the `new`/`renudged` verdict keys.
@gtapps
gtapps merged commit 77d9a30 into main Jul 25, 2026
9 checks passed
@gtapps
gtapps deleted the feat/shared-logic-bin-path branch July 25, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant