diff --git a/AGENTS.md b/AGENTS.md index d8ba934c521..da9f903eefb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -513,6 +513,17 @@ generic plugin surface (new hook, new ctx method) — never hardcode plugin-specific logic into core. PR #5295 removed 95 lines of hardcoded honcho argparse from `main.py` for exactly this reason. +**No new in-tree memory providers (policy, May 2026):** the set of +built-in memory providers under `plugins/memory/` is closed. New memory +backends must ship as **standalone plugin repos** that users install +into `~/.hermes/plugins/` (or via pip entry points) — they implement +the same `MemoryProvider` ABC, register through the same discovery +path, and integrate via `hermes memory setup` / `post_setup()` without +landing in this tree. PRs that add a new directory under +`plugins/memory/` will be closed with a pointer to publish the +provider as its own repo. Existing in-tree providers stay; bug fixes +to them are welcome. + ### Model-provider plugins (`plugins/model-providers//`) Every inference backend (openrouter, anthropic, gmi, deepseek, nvidia, …) @@ -580,6 +591,86 @@ during setup, injected at load time). Top-level `tags:` and `category:` are also accepted and mirrored from `metadata.hermes.*` by the loader. +### Skill authoring standards (HARDLINE) + +Every new or modernized skill — bundled, optional, or contributed — +must meet these standards before merge. Reviewers reject PRs that +violate them. + +1. **`description` ≤ 60 characters, one sentence, ends with a period.** + Long descriptions bloat skill listings and dilute the model's + attention when many skills are loaded. State the capability, not + the implementation. No marketing words ("powerful", + "comprehensive", "seamless", "advanced"). Don't repeat the skill + name. Verify with: + ```python + import re, pathlib + m = re.search(r'^description: (.*)$', + pathlib.Path('skills///SKILL.md').read_text(), + re.MULTILINE) + assert len(m.group(1)) <= 60, len(m.group(1)) + ``` + +2. **Tools referenced in SKILL.md prose must be native Hermes tools or + MCP servers the skill explicitly expects.** When the skill needs a + capability, point at the proper tool by name in backticks + (`` `terminal` ``, `` `web_extract` ``, `` `read_file` ``, + `` `patch` ``, `` `search_files` ``, `` `vision_analyze` ``, + `` `browser_navigate` ``, `` `delegate_task` ``, etc.). Do NOT + name shell utilities the agent already has wrapped — `grep` → + `search_files`, `cat`/`head`/`tail` → `read_file`, `sed`/`awk` → + `patch`, `find`/`ls` → `search_files target='files'`. If the skill + depends on an MCP server, name the MCP server and document the + expected setup in `## Prerequisites`. Anything else (third-party + CLIs, shell pipelines, etc.) is fair game inside script files but + should not be the headline interaction surface in the prose. + +3. **`platforms:` gating audited against actual script imports.** + Skills that use POSIX-only primitives (`fcntl`, `termios`, + `os.setsid`, `os.kill(pid, 0)` for liveness, `/proc`, `/tmp` + hardcoded, `signal.SIGKILL`, bash heredocs, `osascript`, `apt`, + `systemctl`) must declare their supported platforms. Default + posture: try to fix it cross-platform first — `tempfile.gettempdir`, + `pathlib.Path`, `psutil.pid_exists`, Python-level filtering instead + of `grep`. Gate to a narrower set only when the dependency is + genuinely platform-bound. + +4. **`author` credits the human contributor first.** For external + contributions, the contributor's real name + GitHub handle goes + first; "Hermes Agent" is the secondary collaborator. If the + contributor's commit shows "Hermes Agent" as author (because they + used Hermes to draft the skill), replace it with their actual name + — credit the human, not the tool. + +5. **SKILL.md body uses the modern section order.** `# Skill` + title, 2-3 sentence intro stating what it does and doesn't do, + `## When to Use`, `## Prerequisites`, `## How to Run`, + `## Quick Reference`, `## Procedure`, `## Pitfalls`, + `## Verification`. Target ~200 lines for a complex skill, + ~100 lines for a simple one. Cut redundant intro fluff, marketing + prose, and re-explanations of env vars already in + `## Prerequisites`. + +6. **Scripts go in `scripts/`, references in `references/`, + templates in `templates/`.** Don't expect the model to inline-write + parsers, XML walkers, or non-trivial logic every call — ship a + helper script. Reference it from SKILL.md by path relative to the + skill directory. + +7. **Tests live at `tests/skills/test__skill.py`** and use only + stdlib + pytest + `unittest.mock`. No live network calls. Run via + `scripts/run_tests.sh tests/skills/test__skill.py -q`. + +8. **`.env.example` additions are isolated to a clearly delimited + block.** Don't touch the surrounding file — contributor-supplied + `.env.example` versions are usually stale and edits outside the + skill's own block must be dropped during salvage. + +The full salvage / modernization checklist for external skill PRs +lives in the `hermes-agent-dev` skill at +`references/new-skill-pr-salvage.md` — load it before polishing +contributor skill PRs. + --- ## Toolsets diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 56f0c8ff016..4bbc3c67c70 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,24 @@ If your skill is specialized, community-contributed, or niche, it's better suite --- +## Memory Providers: Ship as a Standalone Plugin + +**We are no longer accepting new memory providers into this repo.** The set of built-in providers under `plugins/memory/` (honcho, mem0, supermemory, byterover, hindsight, holographic, openviking, retaindb) is closed. If you want to add a new memory backend, publish it as a **standalone plugin repo** that users install into `~/.hermes/plugins/` (or via a pip entry point). + +Standalone memory plugins: + +- Implement the same `MemoryProvider` ABC (`agent/memory_provider.py`) — `sync_turn`, `prefetch`, `shutdown`, and optionally `post_setup(hermes_home, config)` for setup-wizard integration +- Use the same discovery system — `discover_memory_providers()` picks them up from user/project plugin directories and pip entry points +- Integrate with `hermes memory setup` via `post_setup()` — no need to touch core code +- Can register their own CLI subcommands via `register_cli(subparser)` in a `cli.py` file +- Get all the same lifecycle hooks and config plumbing as in-tree providers + +PRs that add a new directory under `plugins/memory/` will be closed with a pointer to publish the provider as its own repo. Existing in-tree providers stay; bug fixes to them are welcome. + +This isn't a quality bar — it's a coupling-and-maintenance decision. Memory providers are the most common plugin type and they shouldn't all live in this tree. + +--- + ## Development Setup ### Prerequisites @@ -461,6 +479,58 @@ Gateway and messaging sessions never collect secrets in-band; they instruct the See `skills/gifs/gif-search/` and `skills/email/himalaya/` for examples. +### Skill authoring standards (HARDLINE) + +Every new or modernized skill — bundled, optional, or contributed — must meet these standards before merge. Reviewers reject PRs that violate them. + +1. **`description` ≤ 60 characters, one sentence, ends with a period.** Long descriptions bloat the skill listing UI and dilute the model's attention when many skills are loaded. State the capability, not the implementation. No marketing words ("powerful", "comprehensive", "seamless", "advanced"). Don't repeat the skill name. Verify with: + ```python + import re, pathlib + m = re.search(r'^description: (.*)$', + pathlib.Path('skills///SKILL.md').read_text(), + re.MULTILINE) + assert len(m.group(1)) <= 60, len(m.group(1)) + ``` + + Good: `Search arXiv papers by keyword, author, category, or ID.` + Bad: `A powerful and comprehensive skill that allows the agent to search arXiv for relevant academic papers using various criteria including keywords, authors, and categories.` + +2. **Tools referenced in SKILL.md prose must be native Hermes tools or MCP servers the skill explicitly expects.** When the skill needs a capability, point at the proper tool by name in backticks: `` `terminal` ``, `` `web_extract` ``, `` `web_search` ``, `` `read_file` ``, `` `write_file` ``, `` `patch` ``, `` `search_files` ``, `` `vision_analyze` ``, `` `browser_navigate` ``, `` `delegate_task` ``, `` `image_generate` ``, `` `text_to_speech` ``, `` `cronjob` ``, `` `memory` ``, `` `skill_view` ``, `` `todo` ``, `` `execute_code` ``. + + Do NOT name shell utilities the agent already has wrapped: + + | Don't say | Say | + |---|---| + | `grep`, `rg` | `search_files` | + | `cat`, `head`, `tail` | `read_file` | + | `sed`, `awk` | `patch` | + | `find`, `ls` | `search_files` (with `target='files'`) | + | `curl` for content extraction | `web_extract` | + | `echo > file`, `cat < Skill` title, 2-3 sentence intro stating what it does and what it doesn't do, then: + - `## When to Use` — trigger conditions + - `## Prerequisites` — env vars, install steps, MCP setup, API key sourcing + - `## How to Run` — canonical invocation through the `terminal` tool + - `## Quick Reference` — flat command/API reference + - `## Procedure` — numbered steps with copy-paste commands + - `## Pitfalls` — known limits, rate limits, things that look broken but aren't + - `## Verification` — single command that proves the skill works + + Target ~200 lines for a complex skill, ~100 lines for a simple one. Cut redundant intro fluff, marketing prose, and re-explanations of env vars already documented in `## Prerequisites`. + +6. **Scripts go in `scripts/`, references in `references/`, templates in `templates/`.** Don't expect the model to inline-write parsers, XML walkers, or non-trivial logic every call — ship a helper script. Reference scripts from SKILL.md by path relative to the skill directory. + +7. **Tests live at `tests/skills/test__skill.py`** and use only stdlib + pytest + `unittest.mock`. No live network calls. Run via `scripts/run_tests.sh tests/skills/test__skill.py -q`. Must pass under the hermetic CI env (no API keys leaking through). Use `monkeypatch` and `tmp_path` for any env-var or filesystem dependencies. + +8. **`.env.example` additions are isolated to a clearly delimited block.** Don't touch the surrounding file — contributor-supplied `.env.example` versions are usually stale, and edits outside the skill's own block will be dropped during salvage. Comment all values with `#` (it's documentation, not live config). + ### Skill guidelines - **No external dependencies unless absolutely necessary.** Prefer stdlib Python, curl, and existing Hermes tools (`web_extract`, `terminal`, `read_file`).