Meu-Agent / plugins
AGENTS.md0 starsChanged 10 days agoMITView on GitHub
Applies on top of the root AGENTS.md. Authoring guide + canonical compat contract: website/docs/developer-guide/plugins/index.md. Per-kind guides: memory-provider-plugin.md, model-provider-plugin.md, context-engine-plugin.md, image-gen-provider-plugin.md, ... Plugins live in their own directory and work within the ABCs / hooks / ctx surface we provide. A plugin MUST NOT modify run_agent.py, cli.py, gateway/run.py, hermes_cli/main.py, etc. If it needs a capability the framework lacks, widen the generic plugin surface (new hook, new ctx method) and have the plugin use it — never hardcode plugin-specific logic into core…
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,439 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository57 other files it gives its agents.
- agent/AGENTS.mdAGENTS.md
- AGENTS.mdAGENTS.md
- cron/AGENTS.mdAGENTS.md
- gateway/AGENTS.mdAGENTS.md
- hermes_cli/AGENTS.mdAGENTS.md
- hermes_platform/AGENTS.mdAGENTS.md
- pm/AGENTS.mdAGENTS.md
- skills/AGENTS.mdAGENTS.md
- tests/AGENTS.mdAGENTS.md
- tools/AGENTS.mdAGENTS.md
- tui_gateway/AGENTS.mdAGENTS.md
- web/AGENTS.mdAGENTS.md
- apple-notesSkill
- apple-remindersSkill
- findmySkill
- imessageSkill
- claude-codeSkill
- codexSkill
- computer-useSkill
- hermes-agentSkill
- architecture-diagramSkill
- ascii-videoSkill
- baoyu-infographicSkill
- claude-designSkill
- humanizerSkill
- local-pngSkill
- manim-videoSkill
- p5jsSkill
- popular-web-designsSkill
- songwriting-and-ai-musicSkill
- sdlc-reviewSkill
- email-inbox-triageSkill
- himalayaSkill
- youtube-contentSkill
- obsidianSkill
- document-to-action-itemsSkill
- google-workspaceSkill
- mapsSkill
- meeting-action-itemsSkill
- microsoft-officeSkill
- pdfSkill
- product-price-monitorSkill
- teams-meeting-pipelineSkill
- weekly-review-planningSkill
- arxivSkill
- competitor-news-monitorSkill
- grounded-citationsSkill
- xurlSkill
- codebase-inspectionSkill
- dogfoodSkill
- githubSkill
- requesting-code-reviewSkill
- simplify-codeSkill
- spikeSkill
- systematic-debuggingSkill
- test-driven-developmentSkill
- blocked-page-recoverySkill
The file
We split this AGENTS.md into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 11
If it needs a capability the framework lacks, widen the generic plugin surface (new hook, new ctx method) and have the plugin use it — …
- Very specific: line 154
Never remove or rename PluginContext methods.
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
plugins/ — plugin kinds, compat contract, in-tree policy
Applies on top of the root AGENTS.md. Authoring guide + canonical compat contract:
website/docs/developer-guide/plugins/index.md. Per-kind guides: memory-provider-plugin.md,
model-provider-plugin.md, context-engine-plugin.md, image-gen-provider-plugin.md, ...
Plugins never touch core (Teknium, May 2026)
Plugins live in their own directory and work within the ABCs / hooks / ctx surface we provide.
A plugin MUST NOT modify run_agent.py, cli.py, gateway/run.py, hermes_cli/main.py, etc.
If it needs a capability the framework lacks, widen the generic plugin surface (new hook, new
ctx method) and have the plugin use it — never hardcode plugin-specific logic into core (PR #5295
removed 95 lines of hardcoded honcho argparse from main.py). Plugin setup goes through
hermes memory setup → provider.post_setup(hermes_home, config), never a parallel top-level
command. A hook with no concrete consumer is speculative infrastructure and is rejected (root).
What may live in this tree (policy)
- No new in-tree memory providers (May 2026).
plugins/memory/is closed (byterover, retaindb stay until their Oct 15 2026 removal). hindsight (Sep 2026), honcho, supermemory, mem0, openviking and holographic (Oct 2026) moved to the plugin catalog —plugin-catalog/<name>.yaml, auto-installed byhermes_cli/memory_provider_migration.pyfor homes still configured for them. Host-side code a catalog provider still relies on (thehoncho_host_blockconfig storage kind, profile clone / rename / update-sync hooks) resolves the provider's modules throughplugins.memory.import_provider_module, never aplugins.memory.<name>import. New backends ship as standalone repos implementing the sameMemoryProviderABC, discovered through the same path, integrated viahermes memory setup/post_setup(). - Other features that leave core (Home Assistant platform + toolset, Oct 2026 →
plugin-catalog/homeassistant.yaml; Spotify toolset →plugin-catalog/spotify.yaml; Singularity terminal backend →plugin-catalog/singularity.yaml) keep their names/config/env and get a row inhermes_cli/left_core_migration.py::LEFT_CORE(catalog plugin + read-only "this home uses it" predicate);hermes updateand agent/gateway start install the plugin for homes that used it. Installing and converting core-era state are separate steps: the toolset-scope conversion runs once per home and row (_left_core_scopedin config.yaml) even when the plugin is already there. The automatic install also happens once per home and row (_left_core_installed, written only once the plugin dir exists): a laterhermes plugins removesticks, a failed install retries. Core special cases becomePlatformEntryseams the plugin sets (trusted_inbound,display_tier,shared_env_prefixes), never a name check. A corehermes auth <name>login becomes the plugin's ownhermes <name>command (row fieldcli; the old spelling prints the new one), and a nested core command becomes a top-level plugin command (command+old_command:hermes mcp serve→hermes mcp-serve). A feature with no in-home signal (MCP clients live outside Hermes) gets anin_usethat is always False: hint only, never an automatic install. A built-in terminal backend leaves its name offBUILTIN_BACKEND_NAMESso the plugin can register it (row fieldterminal_backend: unknown-backend errors name the install command). A model provider that leaves core (GitHub Copilot →github-copilot) lists its ids and aliases (providers: unknown-provider errors name the install, runtime resolution installs it first for a home that uses it, models.dev never stands in), the env core kept profile-managed (profile_env), the executable/argv subset env writers refuse on every home (launch_env), and the hosts core served by host for any provider name (hosts: a route there is use; a request rejected there names the install);noticeadds a per-home sentence to every outcome (a credential source the plugin no longer reads). - No new third-party-product plugins (June 2026). Observability/metrics backends, vendor SaaS
connectors, analytics dashboards, paid-service tie-ins ship as standalone plugin repos
(
~/.hermes/plugins/or pip entry point) promoted in Discord#plugins-skills-and-skins. Reason: every absorbed product is our maintenance burden against a fast-moving core for a backend we don't own.kanban/,disk-cleanup/are precedent, not an invitation (Langfuse already moved out to the official catalog plugin). Closing such a PR is a coupling decision, not a quality judgment. - Reference/docs-companion plugins (
example-dashboard,strike-freedom-cockpit,plugin-llm-example,plugin-llm-async-example) live inhermes-example-plugins, not here.
Plugin catalog (plugin-catalog/, Sep 2026)
The ONLY discovery system for out-of-tree plugins. One YAML per entry, 40-hex SHA pin mandatory,
human-merged via PR (plugin-catalog/README.md = admission policy, mirrored word for word in
website/docs/developer-guide/plugins/catalog-submission.md with the submission guide; plugin-catalog-ci.yml clones
each changed entry at its pin and runs hermes plugins validate). removed.yaml is the kill list —
every install path (CLI, dashboard, TUI) refuses matches (repo URLs compared by canonical
host/owner/repo, so git@/ssh:///www. spellings match); only the CLI has a loud
--allow-removed, which is recorded on the install record and is the only thing that exempts an
installed plugin from the same check at update, enable and load (gate_manifest). Catalog
provenance lives on the installer-owned .install-metadata.json record (catalog block, sha =
checked-out commit), NEVER in the tree: the in-tree .hermes-catalog.json is a convenience copy the
Desktop reads for "Install here"; Python never trusts it (a repo can ship a forged one).
Code: hermes_cli/plugin_catalog.py (loader, live refresh from
/docs/api/plugin-catalog.json published by the docs build, in-tree fallback),
hermes_cli/plugins_cmd_catalog.py (resolution, .hermes-catalog.json provenance sidecar,
search/info/validate, re-pin on update, dashboard/TUI payloads). Never add a second name index:
bare names resolve through the catalog or error.
Plugin kinds and their discovery systems
| Kind | Where | Discovery | Notes | |
| General | plugins/<name>/, ~/.hermes/plugins/, ./.hermes/plugins/, pip entry points | PluginManager (hermes_cli/plugins.py), later-wins | register(ctx) registers hooks (pre_tool_call, post_tool_call, pre_llm_call, post_llm_call, on_session_start, on_session_end), tools (ctx.register_tool), CLI subcommands (ctx.register_cli_command — argparse tree wired into hermes at startup, no main.py change), language packs (provides_locales in the manifest auto-registers `locales/<lang>[.tui | .desktop].yamlviactx.register_locale_dir; manifest-only packs need no init.py; hermes_cli/plugin_validate_locales.py` validates them) |
| Memory provider | plugins/memory/<name>/ | plugins/memory/__init__.py: bundled → $HERMES_HOME/plugins/ → ./.hermes/plugins/ (opt-in HERMES_ENABLE_PROJECT_PLUGINS) → hermes_agent.memory_providers entry points; bundled-first | Activated by name via memory.provider, so a dropped-in dir must not shadow a shipped one (reverse of general later-wins). Enumerates without importing. Implements MemoryProvider ABC (agent/memory_provider.py), orchestrated by agent/memory_manager.py: sync_turn, prefetch, shutdown, optional post_setup. cli.py with register_cli(subparser) is wired by discover_plugin_cli_commands() — only for the ACTIVE provider, so hermes --help stays clean | |
| Model provider | plugins/model-providers/<name>/ | providers/__init__.py._discover_providers(), lazy, on first get_provider_profile()/list_providers(); bundled → $HERMES_HOME/plugins/model-providers/ → legacy providers/<name>.py | __init__.py calls providers.register_provider(ProviderProfile(...)) at load; last-writer-wins so a user plugin overrides a bundled profile. PluginManager records kind: model-provider manifests but does NOT import them (would double-instantiate); manifests without kind: are auto-coerced by source heuristic (register_provider + ProviderProfile) | |
| Context engine / image-gen / delegation / others | plugins/context_engine/, plugins/image_gen/, plugins/delegation/, ... | ABC + orchestrator + per-plugin directory | Plug into agent/context_engine.py, agent/image_gen_provider.py, agent/delegation_provider.py (plugins/delegation/default IS today's delegation routing) | |
| Platform adapters | plugins/platforms/<name>/adapter.py | gateway | Token-lock and scoped-secret rules in gateway/AGENTS.md (irc, feishu are canonical) |
Discovery timing pitfall: discover_plugins() runs only as a side effect of importing
model_tools.py. Code that reads plugin state without importing model_tools.py first must call
discover_plugins() explicitly (idempotent). Hooks are invoked from model_tools.py (pre/post
tool) and run_agent.py (lifecycle). A non-forced discover_plugins() short-circuits on _discovered: every
mid-run load path (install/enable/update on any surface, reload-plugins verb) runs
discover_plugins(force=True), and PluginManager.on_plugin_loaded fires from inside that sweep for the
newly loaded plugins with an activation summary (hermes_cli/plugins_activation.py: handlers live now;
tools/prompt next session; deferred.mcp_servers until mcp.reload). Never emit that event from an RPC. Auxiliary LLM calls (titling, compression, MoA, vision, ...)
fire pre_auxiliary_call/post_auxiliary_call from agent/auxiliary_hooks.py (payload = the
*_api_request shape + aux_task); they never fire the turn-scoped pre/post_api_request (#79733). When a plugin changes a default, add a migration guard keyed
on an "existing config" signal (_explicitly_configured) so existing users keep the old default.
Lifecycle hooks fire under the owning profile's scope, and the caller binds it.
on_session_start/on_session_end/sync_turn/shutdown are invoked from the turn (bound) AND
from eviction, shutdown, tui_gateway teardown and cron completion (bound by the caller via
_run_release_in_profile_scope, _session_profile_runtime_scope, _profile_cron_scope). One
process serves several profiles, so a provider never caches hermes_home from initialize() as
"the" home — key state by the home it is handed per call (hermes_home_key()) — and never reads
os.environ for credentials (agent.secret_scope.get_secret; a check_fn too). Background
work starts via agent.memory_provider.spawn_context_thread, never a bare threading.Thread,
or the worker runs with no scope and fails closed (or writes into the launch profile's tenant).
Platform plugins never mutate os.environ: YAML goes to PlatformConfig.extra through
_shared.apply_yaml_bridge, gates through platform_gate_env (gateway/AGENTS.md).
Plugin host boundary (plugins.isolation: host)
in_process (default) imports user plugins into Hermes. host runs every non-bundled plugin in a
per-profile host process (hermes_cli/plugin_host.py parent side, plugin_host_child.py child,
plugin_host_wire.py framed JSON protocol). The child hands plugins a RemotePluginContext; Hermes
registers proxies (tools, hooks, commands, provider objects as subclasses of the ABC it checks).
Invariants:
- Every user-code import path routes to the host or refuses — general plugins
(
plugins_loader), memory / context engine / cron providers (load_instance), model-provider profiles (plugin_host_profiles.py: credential-free extraction cached by file fingerprint, because discovery runs whilehermes_cli.config/authimport; overrides run by name in the host), dashboard APIs (ASGI bridge).plugins/plugin_loader.load_plugin_modulerefuses any other synthetic-namespace import. A new user-code loader MUST do the same. - What cannot cross is one table:
plugin_isolation.HOST_UNSUPPORTED_CTX_METHODS(live gateway / adapter objects). The runtime refusal and the static audit (plugin_isolation_audit.py, shown byhermes plugins validate/show) both read it;evals/plugin_isolation/audit_catalog.pyre-measures the catalog. - Values keep the provider ABC's declared types across the wire: JSON carries dicts, lists and
scalars, so
plugin_host_wire.restorerebuilds arguments (child) and results (parent) from the ABC's annotations (FetchResult,Path, enums, a returned engine as a proxy). A value a core consumer type-checks must be a dataclass annotated on the ABC method, or it arrives asRecord/Opaque. - A host never spawns a host (
HERMES_PLUGIN_HOST_PROCESS=1makesisolation_mode()in-process there) and must not start while a module import holds its lock (model-provider discovery is the known case). - The isolated party cannot opt out when an operator pins it:
isolation_mode()/host_launcher()read through the managed overlay (load_config_readonly), so/etc/hermes/config.yamlbeats the profile's own config. Never switch them to a raw user-config read. - Plugins stay tenant-unaware: no new API, same
ctx. Per-profile env comes fromserved_profile_child_env, so a host sees only its own profile's secrets.
Native plugin compatibility contract (summary — canonical text in the docs page)
Compatibility is a behavior contract, not a monolithic PLUGIN_API_VERSION, a manifest-wide
native api: match, or version literals on unrelated payloads. Documented surfaces stay additive:
- Hook payload data is added as keyword fields; callbacks are signature-inspected so old narrow
signatures receive only the fields they declare and
**kwargscallbacks get the full payload. - Never remove or rename
PluginContextmethods; new parameters are optional with defaults and keyword-only where possible. - Unknown native manifest fields are ignored.
- New provider methods get default implementations; optional callback kwargs are signature-inspected, not forwarded unconditionally.
- A local schema version exists only for a capability with a wire or persisted contract, and old state/config/session replay is preserved or migrated.
- Deprecations: once-per-process warning, documented replacement + migration note, ≥ 2 subsequent minor releases before removal.
- Compat tests load frozen plugins through the real discovery path and assert outcomes — never exact registry/catalog counts, source-reading tests, or "a global version literal changed".
Internal import paths are not API
PR #102117 moved internals into <stem>_<topic> siblings. The temporary compat layer that kept the
old import paths alive for external plugins was removed after its 2026-09-14 window; an old path now
raises ImportError, surfaced as the plugin's load error in hermes plugins list. Plugins build on
ctx and the documented ABCs. Never add re-export shims for an internal move. hermes_cli/plugin_compat.py
survives only as three inert stubs that already-running pre-removal updaters import.
Tests
tests/plugins/. Load through real discovery with a temp HERMES_HOME; assert behaviour (tool
registered, hook fired with expected kwargs), not counts. Opt-in telemetry rule applies to plugins
too: no attribution tag ships by default.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

