mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
feat(plugins): make all plugins opt-in by default
Plugins now require explicit consent to load. Discovery still finds every plugin — user-installed, bundled, and pip — so they all show up in `hermes plugins` and `/plugins`, but the loader only instantiates plugins whose name appears in `plugins.enabled` in config.yaml. This removes the previous ambient-execution risk where a newly-installed or bundled plugin could register hooks, tools, and commands on first run without the user opting in. The three-state model is now explicit: enabled — in plugins.enabled, loads on next session disabled — in plugins.disabled, never loads (wins over enabled) not enabled — discovered but never opted in (default for new installs) `hermes plugins install <repo>` prompts "Enable 'name' now? [y/N]" (defaults to no). New `--enable` / `--no-enable` flags skip the prompt for scripted installs. `hermes plugins enable/disable` manage both lists so a disabled plugin stays explicitly off even if something later adds it to enabled. Config migration (schema v20 → v21): existing user plugins already installed under ~/.hermes/plugins/ (minus anything in plugins.disabled) are auto-grandfathered into plugins.enabled so upgrades don't silently break working setups. Bundled plugins are NOT grandfathered — even existing users have to opt in explicitly. Also: HERMES_DISABLE_BUNDLED_PLUGINS env var removed (redundant with opt-in default), cmd_list now shows bundled + user plugins together with their three-state status, interactive UI tags bundled entries [bundled], docs updated across plugins.md and built-in-plugins.md. Validation: 442 plugin/config tests pass. E2E: fresh install discovers disk-cleanup but does not load it; `hermes plugins enable disk-cleanup` activates hooks; migration grandfathers existing user plugins correctly while leaving bundled plugins off.
This commit is contained in:
parent
a25c8c6a56
commit
70111eea24
10 changed files with 578 additions and 167 deletions
|
|
@ -24,23 +24,31 @@ On name collision, later sources win — a user plugin named `disk-cleanup` woul
|
|||
|
||||
`plugins/memory/` and `plugins/context_engine/` are deliberately excluded from bundled scanning. Those directories use their own discovery paths because memory providers and context engines are single-select providers configured through `hermes memory setup` / `context.engine` in config.
|
||||
|
||||
Bundled plugins respect the same disable mechanism as any other plugin:
|
||||
## Bundled plugins are opt-in
|
||||
|
||||
Bundled plugins ship disabled. Discovery finds them (they appear in `hermes plugins list` and the interactive `hermes plugins` UI), but none load until you explicitly enable them:
|
||||
|
||||
```bash
|
||||
hermes plugins enable disk-cleanup
|
||||
```
|
||||
|
||||
Or via `~/.hermes/config.yaml`:
|
||||
|
||||
```yaml
|
||||
# ~/.hermes/config.yaml
|
||||
plugins:
|
||||
disabled:
|
||||
enabled:
|
||||
- disk-cleanup
|
||||
```
|
||||
|
||||
Or suppress every bundled plugin at once with an env var:
|
||||
This is the same mechanism user-installed plugins use. Bundled plugins are never auto-enabled — not on fresh install, not for existing users upgrading to a newer Hermes. You always opt in explicitly.
|
||||
|
||||
To turn a bundled plugin off again:
|
||||
|
||||
```bash
|
||||
HERMES_DISABLE_BUNDLED_PLUGINS=1 hermes chat
|
||||
hermes plugins disable disk-cleanup
|
||||
# or: remove it from plugins.enabled in config.yaml
|
||||
```
|
||||
|
||||
The test suite sets `HERMES_DISABLE_BUNDLED_PLUGINS=1` in its hermetic fixture — tests that exercise bundled discovery clear it explicitly.
|
||||
|
||||
## Currently shipped
|
||||
|
||||
### disk-cleanup
|
||||
|
|
@ -87,14 +95,9 @@ Auto-tracks and removes ephemeral files created during sessions — test scripts
|
|||
|
||||
**Safety** — cleanup only ever touches paths under `HERMES_HOME` or `/tmp/hermes-*`. Windows mounts (`/mnt/c/...`) are rejected. Well-known top-level state dirs (`logs/`, `memories/`, `sessions/`, `cron/`, `cache/`, `skills/`, `plugins/`, `disk-cleanup/` itself) are never removed even when empty — a fresh install does not get gutted on first session end.
|
||||
|
||||
To turn it off without uninstalling:
|
||||
**Enabling:** `hermes plugins enable disk-cleanup` (or check the box in `hermes plugins`).
|
||||
|
||||
```yaml
|
||||
# ~/.hermes/config.yaml
|
||||
plugins:
|
||||
disabled:
|
||||
- disk-cleanup
|
||||
```
|
||||
**Disabling again:** `hermes plugins disable disk-cleanup`.
|
||||
|
||||
## Adding a bundled plugin
|
||||
|
||||
|
|
|
|||
|
|
@ -100,7 +100,34 @@ Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable
|
|||
| Project | `.hermes/plugins/` | Project-specific plugins (requires `HERMES_ENABLE_PROJECT_PLUGINS=true`) |
|
||||
| pip | `hermes_agent.plugins` entry_points | Distributed packages |
|
||||
|
||||
Later sources override earlier ones on name collision, so a user plugin with the same name as a bundled plugin replaces it. `HERMES_DISABLE_BUNDLED_PLUGINS=1` suppresses the bundled scan entirely.
|
||||
Later sources override earlier ones on name collision, so a user plugin with the same name as a bundled plugin replaces it.
|
||||
|
||||
## Plugins are opt-in
|
||||
|
||||
**Every plugin — user-installed, bundled, or pip — is disabled by default.** Discovery finds them (so they show up in `hermes plugins` and `/plugins`), but nothing loads until you add the plugin's name to `plugins.enabled` in `~/.hermes/config.yaml`. This stops anything with hooks or tools from running without your explicit consent.
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
enabled:
|
||||
- my-tool-plugin
|
||||
- disk-cleanup
|
||||
disabled: # optional deny-list — always wins if a name appears in both
|
||||
- noisy-plugin
|
||||
```
|
||||
|
||||
Three ways to flip state:
|
||||
|
||||
```bash
|
||||
hermes plugins # interactive toggle (space to check/uncheck)
|
||||
hermes plugins enable <name> # add to allow-list
|
||||
hermes plugins disable <name> # remove from allow-list + add to disabled
|
||||
```
|
||||
|
||||
After `hermes plugins install owner/repo`, you're asked `Enable 'name' now? [y/N]` — defaults to no. Skip the prompt for scripted installs with `--enable` or `--no-enable`.
|
||||
|
||||
### Migration for existing users
|
||||
|
||||
When you upgrade to a version of Hermes that has opt-in plugins (config schema v21+), any user plugins already installed under `~/.hermes/plugins/` that weren't already in `plugins.disabled` are **automatically grandfathered** into `plugins.enabled`. Your existing setup keeps working. Bundled plugins are NOT grandfathered — even existing users have to opt in explicitly.
|
||||
|
||||
## Available hooks
|
||||
|
||||
|
|
@ -130,13 +157,15 @@ Memory providers and context engines are **provider plugins** — only one of ea
|
|||
## Managing plugins
|
||||
|
||||
```bash
|
||||
hermes plugins # unified interactive UI
|
||||
hermes plugins list # table view with enabled/disabled status
|
||||
hermes plugins install user/repo # install from Git
|
||||
hermes plugins update my-plugin # pull latest
|
||||
hermes plugins remove my-plugin # uninstall
|
||||
hermes plugins enable my-plugin # re-enable a disabled plugin
|
||||
hermes plugins disable my-plugin # disable without removing
|
||||
hermes plugins # unified interactive UI
|
||||
hermes plugins list # table: enabled / disabled / not enabled
|
||||
hermes plugins install user/repo # install from Git, then prompt Enable? [y/N]
|
||||
hermes plugins install user/repo --enable # install AND enable (no prompt)
|
||||
hermes plugins install user/repo --no-enable # install but leave disabled (no prompt)
|
||||
hermes plugins update my-plugin # pull latest
|
||||
hermes plugins remove my-plugin # uninstall
|
||||
hermes plugins enable my-plugin # add to allow-list
|
||||
hermes plugins disable my-plugin # remove from allow-list + add to disabled
|
||||
```
|
||||
|
||||
### Interactive UI
|
||||
|
|
@ -150,14 +179,16 @@ Plugins
|
|||
General Plugins
|
||||
→ [✓] my-tool-plugin — Custom search tool
|
||||
[ ] webhook-notifier — Event hooks
|
||||
[ ] disk-cleanup — Auto-cleanup of ephemeral files [bundled]
|
||||
|
||||
Provider Plugins
|
||||
Memory Provider ▸ honcho
|
||||
Context Engine ▸ compressor
|
||||
```
|
||||
|
||||
- **General Plugins section** — checkboxes, toggle with SPACE
|
||||
- **General Plugins section** — checkboxes, toggle with SPACE. Checked = in `plugins.enabled`, unchecked = in `plugins.disabled` (explicit off).
|
||||
- **Provider Plugins section** — shows current selection. Press ENTER to drill into a radio picker where you choose one active provider.
|
||||
- Bundled plugins appear in the same list with a `[bundled]` tag.
|
||||
|
||||
Provider plugin selections are saved to `config.yaml`:
|
||||
|
||||
|
|
@ -169,15 +200,17 @@ context:
|
|||
engine: "compressor" # default built-in compressor
|
||||
```
|
||||
|
||||
### Disabling general plugins
|
||||
### Enabled vs. disabled vs. neither
|
||||
|
||||
Disabled plugins remain installed but are skipped during loading. The disabled list is stored in `config.yaml` under `plugins.disabled`:
|
||||
Plugins occupy one of three states:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
disabled:
|
||||
- my-noisy-plugin
|
||||
```
|
||||
| State | Meaning | In `plugins.enabled`? | In `plugins.disabled`? |
|
||||
|---|---|---|---|
|
||||
| `enabled` | Loaded on next session | Yes | No |
|
||||
| `disabled` | Explicitly off — won't load even if also in `enabled` | (irrelevant) | Yes |
|
||||
| `not enabled` | Discovered but never opted in | No | No |
|
||||
|
||||
The default for a newly-installed or bundled plugin is `not enabled`. `hermes plugins list` shows all three distinct states so you can tell what's been explicitly turned off vs. what's just waiting to be enabled.
|
||||
|
||||
In a running session, `/plugins` shows which plugins are currently loaded.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue