SuperAPI AI Directory

hermes-config-optmzr

Office & productivity

View repository

Updated 10-16 09:18

About this skill

Hermes Configuration Optimization

Optimize the Hermes configuration to reduce token consumption and improve Chinese trigger efficiency.

Optimization Process

1. Back up the current configuration

cp -r ~/.hermes/routing ~/.hermes/routing-backup-$(date +%Y%m%d-%H%M%S)

2. Routing file consolidation

Check for duplicates:

  • unified-index.md and skill-index.md typically overlap by 30-40%
  • Delete unified-index.md and unified-index.json

Streamline skill-router.md:

  • Remove line number markers (such as 28|, 29|)
  • Merge similar trigger words
  • Use a more compact format
  • Goal: compress from 13KB+ to 6-8KB

Verify:

ls -la ~/.hermes/routing/*.md
du -sh ~/.hermes/routing/*.md

3. Chinese localization of trigger words

Identify pure English trigger words:

# 找出只有英文触发词的 skill
import re
pattern = r'\|\s*`([^`]+)`\s*\|[^|]*\|[^|]*\|\s*([^|]+)\s*\|'
# 检查是否有中文字符
has_chinese = bool(re.search(r'[\u4e00-\u9fff]', triggers))

Add Chinese equivalent words:

  • findmy → 查找设备, 定位, 找手机
  • codex → 代码生成, AI编程, 代码代理
  • excalidraw → 手绘图, 流程图, 白板
  • github-auth → GitHub认证, gh登录, git凭据

Three-file synchronized update process(when adding a new skill or adding Chinese trigger words to an existing skill):

  1. skill-index.json — primary data source. Use a Python script to batch update the triggers array, deduplicate and sort, then write back.
  2. skill-router.md — routing table. Update the trigger word list in the corresponding category section.
  3. skill-index.md — table index. Update the trigger word column in the corresponding category table.

Complete process for batch adding Chinese trigger words:

import json

# 1. 读取 skill-index.json
with open('~/.hermes/routing/skill-index.json', 'r') as f:
    skills = json.load(f)

# 2. 检查哪些 skills 没有中文触发词
no_chinese = []
for skill in skills:
    triggers = skill.get('triggers', [])
    has_cn = any(any('\u4e00' <= c <= '\u9fff' for c in t) for t in triggers)
    if not has_cn:
        no_chinese.append(skill['name'])

print(f"没有中文触发词的 skills ({len(no_chinese)}):")
for s in sorted(no_chinese):
    print(f"  - {s}")

# 3. 定义中文触发词映射
chinese_triggers = {
    'apple-notes': ['苹果备忘录', '备忘录', 'Apple备忘录', '笔记'],
    'apple-rmndrs': ['苹果提醒', '提醒事项', 'Apple提醒', '待办'],
    # ... 为每个 skill 添加
}

# 4. 批量更新
for skill in skills:
    if skill['name'] in chinese_triggers:
        existing_triggers = skill.get('triggers', [])
        new_triggers = chinese_triggers[skill['name']]
        all_triggers = list(set(existing_triggers + new_triggers))
        skill['triggers'] = sorted(all_triggers)

# 5. 写回
with open('~/.hermes/routing/skill-index.json', 'w') as f:
    json.dump(skills, f, indent=2, ensure_ascii=False)

Key pitfalls:

  • Skill names in skill-index.json must match exactly; first use a script to check which skills exist and which are missing
  • Missing skills need a complete entry added first (name/category/grade/priority/security_review/supersedes/triggers/description)
  • The skill-index.md table row format is inconsistent (some start with | and some start with ||); when patching, include enough context to avoid multiple matches
  • MCP-type skills such as open-computer-use are classified under mcp category, not apple or red-teaming
  • After batch updating, skill-router.md and skill-index.md need to be updated in sync
  • Finally, remember to commit to the git repo

4. Compression threshold and context window calibration

Core finding (2026-04-27): Hermes's auto-compress trigger point looks at 主模型 context_length × compression.threshold, not at auxiliary.compression.extra_body.context_window。

Determination formula:

  • Trigger threshold = max(int(model.context_length * compression.threshold), 64000)
  • Example:model.context_length: 2000000 and compression.threshold: 0.5 → approximately 1000000 tokens before compress is triggered

Correct way to change it:

  1. First look at compression.threshold(the common default is 0.5)
  2. Then look at the actual context source of the main model:
    • model.context_length
    • or custom_providers[].models[<exact model name>].context_length
  3. If the current model name has an alias/suffix (such as gpt-5.4(xhigh)),custom_providers.models must write theexact same namekey; writing only gpt-5.4 is not stable enough
  4. When the custom endpoint /models is inaccurate or missing, directly write the integer in model.context_length to avoid Hermes falling back to an incorrect default value

Do not confuse:

  • auxiliary.compression.extra_body.context_window: only affects the summary model request body parameters
  • auxiliary.compression.context_length: only used for auxiliary compression model feasibility check/override
  • What truly determines when auto-compress happens is still the main model's context_length

5. Memory compression (architecture chain format)

Core finding (2026-04-24): flat entries → architecture chain, one tree-shaped dependency replaces 10+ scattered entries.

Architecture chain template:

元:[核心行为规则]→[次级规则]→[三级规则]
├─红线:[不可做]
├─重试:[失败策略]
├─[领域A]链:[约束]→[执行]→[验证]
└─[领域B]链:[约束]→[执行]→[验证]

Example:

元:长忆从严→直做勿问→效驱>轮询→全量不挑。
├─红线:勿删cron/自动化,清前确认存废。
├─重试:始后败不重(断线除外),败即弃。
├─cron链:模型驱→禁脚本→deliver=feishu→冲突必解→sniper参数分离不与长驻争。
├─Hansa链:只收不挪(无FluxA权)→cron走MCP→状态机→答题agent推理。
└─Quest链:禁Twitter/X→禁视频→Medium/Dev.to/gist可。

USER.md optimization:

  • 10+ flat entries → 1 architecture chain
  • Classical Chinese compression, each entry ≤20 characters
  • Store only hard rules; delete project details

MEMORY.md optimization:

  • Keep only cross-project stable technical facts
  • Delete all project details → belongs in repo docs / session_search
  • Goal: < 500 bytes

5. Skills cleanup

# 1. 查大小排序
du -sh ~/.hermes/skills/* | sort -rh | head -20

# 2. 统计每个目录 skill 数
for d in ~/.hermes/skills/*/; do
  count=$(find "$d" -name "SKILL.md" | wc -l)
  size=$(du -sh "$d" | cut -f1)
  echo "$count skills, $size: $(basename $d)"
done | sort -t, -k1 -rn

Deletion criteria:

  • Auto-installed large packages (>1M and >10 skills, never manually loaded)
  • Cloned repos (containing .git directory)
  • Empty directories (0 skills)
  • Domains the user will not use

Boundary confirmation before deletion (2026-04-25 retrospective):

  • First list an inventory by "functional domain," then delete; do not misjudge "has duplicates" as "all can be deleted."
  • Tools like OpenChronicle can only be benchmarked against the same functional domain: timeline memory / activity replay / session retrieval / personal behavior archiving.
  • Do not casually delete cross-domain productivity skills (such as coding agents like codex / opencode / claude-code) unless the user explicitly includes that domain in the cleanup scope.
  • When the user says "kill the feature library/conflicting items," interpret it by default as: only delete conflicting items in the same function as the target tool; it is not a global deduplication and massive cleanup.
  • Before destructive deletion, first provide a "list to be deleted + reasons for keeping"; when the scope is unconfirmed, prefer only adding routing and do not delete.

6. Routing reference cleanup (must be done after deleting skills)

⚠️ skill-index.json top level is an array [{skill}, ...], not a dict {"skills": [...]}

Python cleanup (sed is unreliable for multi-line sections):

import json, re

# skill-index.json
data = json.load(open('skill-index.json'))
data = [s for s in data if s.get('category') not in deleted_cats
        and s.get('name') not in deleted_skills]
json.dump(data, open('skill-index.json', 'w'), indent=2)

# skill-index.md — 删除 section + table rows
content = open('skill-index.md').read()
for cat in deleted_cats:
    pattern = rf'## {re.escape(cat)}\n.*?(?=\n## |\Z)'
    content = re.sub(pattern, '', content, flags=re.DOTALL)
for skill in deleted_skills:
    lines = content.split('\n')
    content = '\n'.join(l for l in lines if skill not in l)
open('skill-index.md', 'w').write(content)

# skill-router.md — 删除对应行
lines = open('skill-router.md').readlines()
lines = [l for l in lines if not any(s in l for s in deleted_skills)]
open('skill-router.md', 'w').writelines(lines)

Verification:

grep -c "DELETED_SKILL" skill-router.md skill-index.md
# 期望:0

Expected benefits

Optimization item Before optimization After optimization Savings
routing file 90KB+ 50-60KB 30-40%
skill-router.md 13KB 6-8KB 50%+
English trigger words 30+ <15 50%+
USER.md 1900 bytes 1200 bytes 37%

Token savings: about 2000-3000 tokens per conversation

Verification steps

  1. Check file size
  2. Verify trigger word matching
  3. Test routing functionality
  4. Monitor token usage

Risks and Pitfalls

  • Deleting unified-index.md may cause some routes to fail
  • Added Chinese trigger words may not be used by the user
  • Backups are needed for rollback
  • After deleting skills, routing references must be cleaned up in sync(skill-router.md, skill-index.md, skill-index.json)
  • skill-index.json is an array, not a dict: top level [{...}], not {"skills": [...]}
  • sed is unreliable for multi-line sections: use Python regex to clean skill-index.md
  • Use write_file for MEMORY.md, use the memory() tool for the user profile: two independent systems
  • First take the current state of repo/AGENTS as authoritative: the actual landing point of routing must be verified on site; do not treat ~/.hermes/hermes-agent/routing/、~/.hermes/routing/, project-internal .hermes/routing/ as one of them as always true. If the current task already has a project-internal .hermes/routing/, prioritize updating its official file; do not first write the official routing to /tmp/* and then stop there.
  • memory replace requires an exact match of old_text: Multiple entries cannot be replaced at once; they must be removed one by one and then new entries added
  • The architecture chain format is superior to a flat list: A tree-like dependency relationship saves more tokens than 10+ loose entries and is logically clearer
  • When modifying config.yaml , first read the exact context before patching: containing api_key、base_url, inline map (such as providers: {}) YAML is very prone to accidentally affecting adjacent keys due to fuzzy matching; do not directly replace based on redacted fragments or memory