Unify the scattered per-plugin trust gates into one declared, diffable
capability model with an install/update-time consent flow. Consent +
audit over host API surfaces — explicitly NOT a sandbox.
New module hermes_cli/plugin_capabilities.py:
- Canonical CAPABILITY_REGISTRY mapping each capability id 1:1 to an
EXISTING enforcing gate (no capability minted without a surface):
tools.override -> allow_tool_override
llm.provider_override -> llm.allow_provider_override
llm.model_override -> llm.allow_model_override
llm.agent_id_override -> llm.allow_agent_id_override
llm.profile_override -> llm.allow_profile_override
llm.task_override -> llm.allow_task_override
- plugin_capability_granted(plugin_id, capability): canonical check —
granted set OR deprecated legacy allow_* key; fail closed on unknown
ids and any unreadable/corrupt consent state; emits checked_by audit
log lines on every decision.
- record_consent() persists plugins.entries.<id>.granted_capabilities +
capabilities_consent {hash, granted_at} and mirrors grants into the
legacy keys so existing enforcement sites keep working unchanged.
- capability_set_hash / pending_capabilities / declared_set_changed
power the update-time re-consent diff.
Wiring:
- plugin.yaml manifest field `capabilities:` parsed into
PluginManifest.capabilities (unknown ids dropped with a warning).
- hermes plugins install: consent screen (one Y/n) when the manifest
declares capabilities; non-interactive installs proceed with
capabilities ungranted (fail closed).
- hermes plugins update: when the new version declares capabilities the
granted set lacks (hash diff), the additions are surfaced and require
re-consent — an update can never silently widen access.
- hermes plugins enable: consent screen replaces the standalone
tool-override prompt for capability-declaring plugins.
- hermes plugins capabilities [<id>]: declared vs granted per plugin,
flags grants held via deprecated legacy keys.
- PluginContext.has_capability() probing API so plugins degrade
gracefully; _tool_override_allowed migrated to the canonical
plugin_capability_granted path (reference migration; legacy
allow_tool_override still honored).
Tests: tests/hermes_cli/test_plugin_capabilities.py (38 tests) —
declaration parsing, consent grant/persist, update re-consent on added
capability, fail-closed on missing/corrupt state, legacy-gate backward
compat, consent CLI flow (grant / decline / non-interactive).
Docs: user-guide plugins.md consent section (with explicit not-a-sandbox
warning) + developer-guide plugin authoring capability note.
Salvages the intent of PR #37976 (@coygeek — require renewed review
before plugin updates), scoped to capability diffs.
Part of #64182.