Files
esh-pfi-infrastructure/persistent-memory.d/2026-09-15-svos-miranda-plugin-validation.md
T
vh 868b56642c docs(memory): svos-dev fixed the roster check; disabled_toolsets deleted from config
svos-dev landed c9d2a96 - build_miranda_roster now returns an empty disabled list
unconditionally and the startup line no longer names the key. The 28-name list is
removed from ~/.hermes/config.yaml rather than left commented, since a paste-ready
array behind a hash is what a future session uncomments; a short warning stands in
its place.

Their mechanism is better than mine and replaces it in the record.
_get_platform_tools resolves platform_toolsets first and applies global suppression
last, so subtracting 28 names from a one-element platform set is a no-op by
resolution order - not merely 'adds no safety on top'. That holds for any future
platform; the measurement only established the single case.

And the endpoint already carried the answer. _handle_toolsets computes each row's
enabled as membership in the per-platform set, so verified live: 29 rows with
svos_miranda the only one reporting enabled=True. A check reading that field rather
than counting rows was correct all along, against a config that never needed the key.
2026-09-15 02:14:09 -07:00

7.7 KiB

svos_miranda Hermes plugin — validation pass (2026-09-15)

svos-dev asked infra-ops to run hermes plugins validate → doctor → compat on /home/lkraven/development/svos/hermes_plugin/ and report before enabling. Hermes Agent v0.21.1 (2026.9.7), local b88e6776, on nh3-dev.

The blocker (found, fixed by svos-dev at c964e64)

Three absolute intra-package imports — from hermes_plugin._vendored, .forward, .jwt — pinned the package to its source directory name. The documented install renames it to svos_miranda, and Hermes loads directory plugins under the hermes_plugins.<dir> namespace; in neither case does a top-level hermes_plugin exist. Fix: three relative imports.

⚠ The harness hid this from three different readers. My first validate passed the import only because my cwd was the SVOS repo root. svos-dev's test suite imports hermes_plugin.* from that same root, and their editable install resolves the name from anywhere on the box — it only reproduced for them once sys.path was stripped. Same class as feedback_filters_that_silently_narrow_the_window: the instrument carried the result.

⚠ Two of the three commands CANNOT pass this plugin, ever

Neither is fixable from the plugin side. Both are now documented in its README.

  • validate — two independent causes. Its RecordingContext.get_config (hermes_cli/plugin_validate.py:219-222) returns the default for every key, ignoring config.yaml entirely, so dispatch_key is always "". And its register_tool returns None, which the plugin's INV-P6 guard correctly reads as a name collision — so even with a key supplied it raises on the first tool.
  • doctor — runs register() under a temp HERMES_HOME with sockets blocked, so no config exists there either.

Tool-level gotchas worth remembering

  • ⚠ hermes plugins doctor exits 0 even when it prints ERROR. Needs --ci.
  • ⚠ hermes plugins compat <nonexistent-path> prints ✓ and exits 0. A typo'd path reads as a pass. (The instrument itself is sound — verified with a throwaway plugin importing a real deprecated path, which it flagged with file:line, exit 1.)
  • ⚠ doctor's sandbox registry starts EMPTY — 0 entries, no built-ins. So doctor cannot detect tool-name collisions at all. validate's separate static "built-in tool collisions" check is what covers that.
  • The real PluginContext.register_tool (hermes_cli/plugins.py:449-491) returns a truthy PluginRegistration on success — confirmed against the live runtime.

Roster verified another way

Since neither command can supply config, a probe mirroring validate's context but returning real settings and a truthy handle gave: 8 tools with repo_read_enabled: true, 7 with false or omitted, names matching plugin.yaml exactly, zero hooks/middleware/commands. All nine settings-validation controls (quoted booleans, "90 s", zero/negative timeouts, empty/whitespace strings) raise errors naming their own key.

A false finding I caught on myself

A probe registering read_file got back a PluginRegistration instead of the expected refusal — which looked like the plugin's collision reading was wrong. It was not: doctor's sandbox holds no built-ins, so nothing was claimed and my positive case was not positive. Reported as untested rather than as a finding.

✅ LIVE 2026-09-15 02:10 — gateway restarted, plugin registered

GET /v1/toolsets = 29 rows including svos_miranda. An api_server session resolves to exactly 8 tools, write-klass absent. Operator's default session verified intact at 46 tools after the restart (memory / read_file / write_file / terminal / web_search / browser_exec all present) — the whole point of the ruling.

✅ RESOLVED — svos-dev fixed it at c9d2a96; the key is DELETED from config. Their reading is better than mine and is the one to keep: _get_platform_tools resolves platform_toolsets[<key>] FIRST and applies the global suppression LAST, so subtracting 28 names from a one-element platform set is a no-op by resolution order — not merely "adds no safety". That generalises to any future platform; my measurement only established the single case.

⭐ And the endpoint already carried the answer: gateway/platforms/api_server.py:: _handle_toolsets computes each row's enabled as name in _get_platform_tools(config, "api_server"). Verified live — 29 rows, and svos_miranda is the ONLY row with enabled=True. A check reading enabled rather than counting rows was always correct. SVOS's build_miranda_roster now returns an empty disabled list unconditionally and its startup line no longer names the key.

⚠ The 28-name list was removed, not commented — a paste-ready array behind a # is what a future session uncomments. A short warning comment stands in its place.

⚠ agent.disabled_toolsets stays OFF permanently — operator: "i dont want the tools disabled everywhere." So SVOS must stop verifying against the global /v1/toolsets before it restarts: it will see 29 and refuse. Options put to svos-dev: (1) verify the api_server surface instead — recommended; (3) relax to "svos_miranda present AND write-klass five absent", which also survives any unrelated plugin landing on this host. Option 2 (accept the fleet-wide cost) is ruled out.

ENABLED in config 2026-09-15 (operator-directed)

Installed to ~/.hermes/plugins/svos_miranda; plugins.enabled, the settings block (dispatch key pulled from the vault, verified byte-equal), and platform_toolsets.api_server: [svos_miranda] all set. Config backed up to config.yaml.bak-20260915-svos-miranda-enable; diffed against it, only the intended non-comment lines changed. hermes plugins list → svos_miranda enabled 0.1.0 user.

Gateway restarted 02:10:17 PDT — PID 3107822 → 3901622, confirmed by observing the change rather than assuming it.

⚠⚠ agent.disabled_toolsets is GLOBAL — it would have cost 26 tools fleet-wide

svos-dev's install instructions specify agent.disabled_toolsets = <the 28 rows minus svos_miranda>. That key is not scoped to api_server. It is a strict end-of-pipeline subtraction applied to every session on every platform (model_tools.py:216 "subtracted after enabling", applied :332; cli.py:2743 reads the same key for the CLI).

Measured, not derived:

default session WITHOUT the line : 46 tools
default session WITH    the line : 20 tools
lost 26: memory, read_file, write_file, patch, search_files, terminal,
         process_manage, web_search, web_extract, browser_exec, execute_code,
         computer_use, delegate_task, vision_analyze, video_analyze,
         session_search, skills_*, todo_list, text_to_speech, image_generate, ha_*

⭐ And it is not needed for the security property. Measured: enabled_toolsets=['svos_miranda'], disabled_toolsets=None resolves to exactly the 8 svos_miranda tools. platform_toolsets.api_server: [svos_miranda] already scopes Miranda correctly on its own; the global subtraction adds no safety on top.

The only thing it buys is satisfying SVOS's startup roster check, which reads the GLOBAL GET /v1/toolsets to verify a PER-PLATFORM property. Raised with svos-dev with three options (verify against the api_server surface; accept the cost with explicit operator sign-off; or relax the check to "svos_miranda present, write-klass five absent"). Left commented out in the config with the measurement inline, so an incidental Hermes restart cannot gut the operator's assistant.

⚠ Minor: stt appears in /v1/toolsets's 28 rows but resolving it logs Unknown toolset: stt — an exact-set comparison pinned to that endpoint can fail for reasons unrelated to the plugin.