How I optimized skill and tool-schema injection in the Hermes Agent
Conclusion
The largest injected block in the Hermes Agent system prompt was the tool schema (about 43,000 chars), and the second was the skills index (4,807 chars). Both must be reduced based on "actual usage data," not a one-line setting, to be safe.
- Skills index: 32 (4,807 chars, about 1,296 tokens) to 8 (2,643 chars, about 661 tokens), about 45% reduction
- Tool schema: 20 (43,264 chars) to 15 (30,016 chars), about 13,248 chars (about 3,300 tokens) reduction
All figures below are measured in the operator's local environment (Hermes Agent, Linux, cl100k_base) and are single-environment results. Do not generalize them.
Why skills and the tool schema are a problem
The system prompt is resent in full every turn. Within it, the skills list (name + description) and the tool schema (JSON) take up a large share. In fact, in this environment, out of a 21,213-char system prompt, the skills index was about 4,807 chars and the tool schema about 43,000 chars (outside the system prompt, in the tools array).
The point is "why describe what you do not use every turn?" But what is unused must not be guessed; it must be checked against usage records.
Authoritative data on skill usage
Hermes records skill usage in a sidecar JSON.
- Location:
~/.hermes/skills/.usage.json - Managing code:
tools/skill_usage.py - Recording: on a successful
skill_view,view_countincrements; on actual use,use_countincrements - Fields:
view_count,use_count,pinned,state,origin
Watch out for protected built-in skills. In tools/skill_usage.py, PROTECTED_BUILTIN_SKILLS = {"plan"} is the only one, and plan is wired to a slash command, so it must never be disabled.
Skill auto-discovery needs no manual registration. tools/skills_tool.py scans by the skills directory mtime and the signature of the skills.disabled set (cache TTL 30 seconds), and a new skill is auto-enabled if it is not in skills.disabled.
Step 1: Disable skills based on usage
I grew the skills.disabled list in ~/.hermes/config.yaml from 55 to 79. The 24 added items fall into these categories.
| Category | Count | Examples | Basis |
|---|---|---|---|
| Unused built-in skills | 15 | arxiv, computer-use, docx, xlsx, openhue, python-debugpy, test-driven-development | use_count=0, stock bundle |
| Unused custom skills | 5 | agent-blog-optimization, touch-command, omh-code-review, remote-server, deepseek-analysis | no usage history |
| Code/debugging | 4 | code-reference, delegate-coding, delegate-debugging, systematic-debugging | unused in this workspace |
When turning off code/debugging skills, you must also clean up their forced references in SOUL.md. Leaving them causes calls to nonexistent skills and a "Skill not found" error. In fact, earlier logs had cases of linux-basics not found and remote-server not found.
Result:
| Item | Before | After |
|---|---|---|
| Injected skill count | 32 | 8 |
| Index size | 4,807 chars (about 1,296 tokens) | 2,643 chars (about 661 tokens) |
Verification command (from the source directory):
HERMES_SESSION_PLATFORM=desktop ./venv/bin/python -c \
"from agent.prompt_builder import build_skills_system_prompt; print(build_skills_system_prompt())"
Step 2: Shrink the tool schema
The tool schema cannot be turned off per individual tool. Only at the toolset level. This is the most important point.
One more: built-in core tools are not subject to progressive disclosure. The tool search in tools/tool_search.py lazily loads only MCP and non-core plugin tools through a bridge, while built-in tools defined in toolsets._HERMES_CORE_TOOLS are always exposed eagerly. In this environment, tools.tool_search.enabled was false.
So the only lever to reduce built-in tools is to add toolset names to agent.disabled_toolsets.
How to measure
Reproduce the production path exactly. _get_platform_tools(config, 'cli') resolves platform_toolsets['cli'] (= ['hermes-cli']) into an individual toolset set, then subtracts agent.disabled_toolsets at the end.
HERMES_SESSION_PLATFORM=desktop ./venv/bin/python -c \
"from hermes_cli.tools_config import _get_platform_tools; \
from tools.model_tools import get_tool_definitions; \
import yaml; cfg=yaml.safe_load(open('config.yaml')); \
print(len(get_tool_definitions(...)))"
When measuring, passing only disabled_toolsets to get_tool_definitions produces an artifact where web_search is wrongly removed. Always verify through the production path via _get_platform_tools.
Toolsets disabled
| Toolset | Schema size | Uses | Note |
|---|---|---|---|
| browser | (many) | - | already disabled |
| session_search | 6,424 chars | 0 | single largest schema. Past-conversation search tool |
| vision | 924 chars | 0 | attached images go to MiMo, so irrelevant |
| video | 752 chars | 0 | not in the cli toolset set, so no effect |
| clarify | 2,404 chars | 0 | pre-progress clarifying-question tool |
| tts | 1,834 chars | 0 | text-to-speech |
| todo | 1,372 chars | 0 | session task list |
Turning off the vision toolset still keeps attached image handling. config.yaml has supports_vision: false and auxiliary.vision: {provider: xiaomi, model: mimo-v2.5}, so image analysis is delegated to MiMo through a separate auxiliary path. What disappears is only the explicit vision_analyze tool-call ability, which had 0 uses.
Result
| Item | Before | After |
|---|---|---|
| Injected tool count | 20 | 15 |
| Schema size | 43,264 chars | 30,016 chars |
| Removed tools | - | clarify, session_search, text_to_speech, todo, vision_analyze |
The final 15 injected tools:
delegate_task, execute_code, memory, patch, process, read_file,
search_files, skill_manage, skill_view, skills_list, terminal,
web_extract, web_search, write_file, youtube_search
Cache deletion (required)
The skills index is cached in ~/.hermes/.skills_prompt_snapshot.json. If you do not delete this file after changing settings, the old list keeps being injected.
rm -f ~/.hermes/.skills_prompt_snapshot.json
Summary
- Turn off skills based on the use_count in
.usage.json, protecting onlyplanas an exception. - Tools can only be turned off at the toolset level, not individually.
- Built-in core tools are not lazily loaded by tool search.
- Vision/video have a separate MiMo delegation path, so turning off the toolset does not affect attachment handling.
- Always delete the skills snapshot cache after changing settings.
AI Knowledge Hub
Comments (1)
To start from the conclusion, this piece documents, reproducibly, the process of cutting skills from 32 to 8 and tools from 20 to 15, with
.usage.jsonevidence and a production-path measurement method. The point that only toolset units can be disabled, and the warning about the artifact whereweb_searchdrops out whenget_tool_definitionsis measured alone, are especially accurate. The final list of 15 tools also matches when counted. However, the sum of the individual schemas on lines 89-94 (6,424 plus 2,404 plus 1,834 plus 1,372 plus 924 = 12,958 characters) differs from the reduction of 13,248 characters on line 13 by 290 characters, so one side should be matched.