Hermes Agentのスキルはbundleでまとめて読む|同じslashはbundleが勝つ

同じ名前のスキルを置いても、/lab-ship は bundle でした。resolve_bundle_command_key("lab-ship") は /lab-ship を返し、スキル名の lab-review は None でした。
bundle はスキルを新たに入れません。skill-bundles の YAML が、すでに置いてあるスキルを 1 つの slash へ束ねます。2026 年 9 月 21 日、Hermes Agent v0.21.0 の一時 home で確認しました。本番の home は使っていません。
前回のリポ境界から、呼び方の束ねへ進む
前回の「Hermes Agentのリポ内スキルはtrustしてから読む」では、リポ内スキルをいつ索引へ載せるかを実測しました。今回は、すでに読めるスキルを、毎回並べて叩かない方法を見ます。
| 時点 | 確認できる範囲 |
|---|---|
| 前回完了時 | リポ内スキルはパス付き trust のあとだけ索引へ載ります |
| 今回開始時 | 複数スキルを毎回 slash で並べる以外の呼び方が未確認です |
| 今回完了後 | create、欠落のスキップ、同名スキルとの衝突、空 YAML の無視を区別できます |
なぜ束ねるのかだけ知りたい場合は次の節まで読めば足ります。コマンドから進みたい場合は「一時環境を用意する」へ飛びます。起動メッセージの中身だけ見る場合は「起動時に載る文面」へ進みます。
なぜ毎回 slash を並べないのか
公式 docs は、先頭でスキルを最大 5 つまで並べられる、と書いています。毎回 /lab-review /lab-pr と打つと、順番も漏れもその場の記憶に依存します。
bundle は別名です。YAML 1 枚が slash 名になります。中のスキルは、プロファイルの skills/ か外部 directory に、先に実体が必要です。無い名前は、作った時点では止まりません。呼び出したときに飛ばします。
私は次の置き方にしています。
毎回使う事実 → Memory
単体の作業手順 → Skill
いつも同時に使う手順 → Bundle(YAML の別名)
リポだけの手順 → リポ内スキル(前回の trust)
公式は、bundle が prompt cache を壊さない、とも書いています。system prompt を書き換えず、そのターンのユーザーメッセージへ本文を載せます。私はここを、スキル本体を増やす場所だとは見ていません。
用語を揃える
| 用語 | この回での意味 |
|---|---|
| bundle | 複数スキルを 1 つの slash に束ねる YAML です |
| slash | CLI や gateway で使う /名前 です |
skill-bundles | YAML を置く directory です。home 直下です |
instruction | 束ねたスキルの前に載せる、使い方の一文です |
| 欠落 | YAML にあるが、実体が無いスキル名です |
| 衝突 | bundle とスキルが同じ slug になることです |
.no-bundled-skills | 同梱スキルを流し込まない印です |
呼び出したあとに何が起きるか
/lab-ship
│
├─ skill-bundles/lab-ship.yaml を読む
├─ 同じ slug のスキルがあっても bundle が勝つ
└─ skills を順に解決する
│
├─ 実体がある → 本文を 1 通のユーザーメッセージへ載せる
└─ 実体がない → 飛ばす。bundle 自体は失敗しない
create の表示は、YAML に書いた件数です。実体の有無は見ていません。実体は起動時に解決します。
一時環境を用意する
本番の Hermes home は使いません。同名の directory がある場合は上書きせず止めます。
LAB=/tmp/hibanas-skill-bundles-lab-20260921
[ ! -e "$LAB" ] || {
printf 'already exists: %s\n' "$LAB"
exit 1
}
mkdir -p "$LAB/skills"
export HERMES_HOME="$LAB"
touch "$LAB/.no-bundled-skills"
今回の実機は Hermes Agent v0.21.0 (2026.8.31) でした。version を先に読みます。
hermes --version
先頭は次のとおりでした。
Hermes Agent v0.21.0 (2026.8.31) · upstream baf7ceea · local 1068df60 (+1 carried commit)
空の一覧は終了コード 0 です。YAML が無いだけです。
hermes bundles list
No bundles installed yet. Create one with:
hermes bundles create <name> --skill skill1 --skill skill2
Bundles directory: /tmp/hibanas-skill-bundles-lab-20260921/skill-bundles
.no-bundled-skills が無いと、空の home でも同梱スキルが流れ込みます。検査では手元の 2 件だけを見るため、印を先に置きます。
束ねる前にスキル実体を置く
bundle は実体を作りません。先に 2 件置きます。
mkdir -p "$LAB/skills/lab-review" "$LAB/skills/lab-pr"
cat > "$LAB/skills/lab-review/SKILL.md" <<'EOF'
---
name: lab-review
description: Use when reviewing a small lab change before a pull request.
---
# Lab review
Read the diff and list defects.
EOF
cat > "$LAB/skills/lab-pr/SKILL.md" <<'EOF'
---
name: lab-pr
description: Use when opening a lab pull request after review is done.
---
# Lab PR
Open a pull request with the reviewed change.
EOF
hermes skills list
表の本体は次の 2 行でした。hub は 0、builtin は 0、local は 2 です。
│ lab-pr │ │ local │ local │ enabled │
│ lab-review │ │ local │ local │ enabled │
説明は 60 文字以内です。前回の新規作成と同じ制約です。
bundle を 1 枚作る
hermes bundles create lab-ship \
--skill lab-review \
--skill lab-pr \
--description 'Lab review then open a pull request.' \
--instruction 'Review first. Open the pull request only after review.'
Created bundle:
/tmp/hibanas-skill-bundles-lab-20260921/skill-bundles/lab-ship.yaml
Invoke with: /lab-ship (loads 2 skills)
実機の Created bundle: のあとは改行です。パスは次の行に出ます。終了コードは 0 です。
hermes bundles list
hermes bundles show lab-ship
一覧は 1 件、Skills 列は 2、説明は create で渡した文面です。show の本体は次のとおりでした。
/lab-ship lab-ship
Lab review then open a pull request.
File: /tmp/hibanas-skill-bundles-lab-20260921/skill-bundles/lab-ship.yaml
Skills (2):
- lab-review
- lab-pr
Instruction:
Review first. Open the pull request only after review.
YAML は 163 バイトでした。中身は次のとおりです。
name: lab-ship
skills:
- lab-review
- lab-pr
description: Lab review then open a pull request.
instruction: Review first. Open the pull request only after review.
対話セッションでは /lab-ship で呼びます。今回は CLI と Python で、同じ解決を見ます。
無いスキルは作った時点では止まらない
hermes bundles create lab-gap \
--skill lab-review \
--skill lab-missing \
--description 'Includes a skill that is not installed.'
ここでも loads 2 skills と出ます。終了コードは 0 です。YAML は 102 バイトで、lab-missing が残ります。show も Skills (2) です。
実体の解決は起動時です。Install directory は hermes --version の該当行を使います。ユーザー名付きの絶対パスはコマンドへ埋めません。
install_dir=$(hermes --version | awk -F': ' '/^Install directory:/{print $2}')
"$install_dir/venv/bin/python" - <<'PY'
import os
os.environ["HERMES_HOME"] = "/tmp/hibanas-skill-bundles-lab-20260921"
from agent.skill_bundles import build_bundle_invocation_message
msg, loaded, missing = build_bundle_invocation_message(
"/lab-gap", user_instruction="check the gap"
)
print("loaded", loaded)
print("missing", missing)
print("msg_len", len(msg))
print("HEAD")
print("\n".join(msg.splitlines()[:8]))
PY
loaded ['lab-review']
missing ['lab-missing']
msg_len 710
HEAD
[IMPORTANT: The user has invoked the "lab-gap" skill bundle, loading 1 skills together. Treat every skill below as active guidance for this turn.]
Bundle: lab-gap
Skills loaded: lab-review
Skills missing (skipped): lab-missing
User instruction: check the gap
create は 2 件、起動は 1 件です。飛ばした名前はメッセージに残ります。bundle 自体は落ちません。私は、未導入の名前を YAML に残したまま運用しません。show の件数と、起動時の loaded を別物として見ます。
同じ slug なら bundle が勝つ
mkdir -p "$LAB/skills/lab-ship"
cat > "$LAB/skills/lab-ship/SKILL.md" <<'EOF'
---
name: lab-ship
description: Use when shipping a lab change without loading a bundle.
---
# Lab ship skill
This is a skill with the same slug as the bundle.
EOF
hermes skills list
local は 3 件になります。lab-ship スキルも enabled です。bundle 側は変わりません。
"$install_dir/venv/bin/python" - <<'PY'
import os
os.environ["HERMES_HOME"] = "/tmp/hibanas-skill-bundles-lab-20260921"
from agent.skill_bundles import resolve_bundle_command_key
print("resolve lab-ship", resolve_bundle_command_key("lab-ship"))
print("resolve /lab-ship", resolve_bundle_command_key("/lab-ship"))
print("resolve lab-review", resolve_bundle_command_key("lab-review"))
PY
resolve lab-ship /lab-ship
resolve /lab-ship None
resolve lab-review None
引数は先頭スラッシュ無しです。/lab-ship を渡すと None になります。スキル名の lab-review も None です。公式 docs の「bundle が個別スキルに勝つ」は、この戻り値と一致します。同じ slash をスキル用に残したい場合は、bundle 名を変えます。
起動時に載る文面
同じ関数へ、存在する 2 件の bundle を渡します。
"$install_dir/venv/bin/python" - <<'PY'
import os
os.environ["HERMES_HOME"] = "/tmp/hibanas-skill-bundles-lab-20260921"
from agent.skill_bundles import build_bundle_invocation_message
msg, loaded, missing = build_bundle_invocation_message(
"/lab-ship", user_instruction="refactor the auth middleware"
)
print("loaded", loaded)
print("missing", missing)
print("msg_len", len(msg))
print("HEAD")
print("\n".join(msg.splitlines()[:12]))
PY
loaded ['lab-review', 'lab-pr']
missing []
msg_len 1224
HEAD
[IMPORTANT: The user has invoked the "lab-ship" skill bundle, loading 2 skills together. Treat every skill below as active guidance for this turn.]
Bundle: lab-ship
Skills loaded: lab-review, lab-pr
Bundle instruction: Review first. Open the pull request only after review.
User instruction: refactor the auth middleware
1224 文字のあとに、各スキルの SKILL.md がそのまま続きます。instruction はスキル本文より前です。ユーザーの続きの文は User instruction です。system prompt 側は触りません。
キーは resolve が返す /lab-ship です。slug の lab-ship を build_bundle_invocation_message へ渡すと、戻り値は None でした。
既存名は —force が無いと止まる
ここから先は、失敗する CLI だけ見たい場合の節です。
hermes bundles create lab-ship --skill lab-review
echo "dup_exit=$?"
hermes bundles show no-such
echo "show_missing_exit=$?"
Bundle already exists at
/tmp/hibanas-skill-bundles-lab-20260921/skill-bundles/lab-ship.yaml
Pass --force to overwrite.
重複の終了コードは 1 です。Created bundle: と同様、パスの前で改行されます。
Bundle 'no-such' not found.
無い名前の show も終了コード 1 です。空の list が 0 なことと混ぜないでください。
上書きするときだけ --force を付けます。今回の検査では、元の 2 件へ戻してから測っています。
空の skills は一覧に出ない
手書き YAML の落ち方だけ見たい場合の節です。
cat > "$LAB/skill-bundles/lab-empty.yaml" <<'EOF'
name: lab-empty
skills: []
description: empty skills list
EOF
hermes bundles reload
hermes bundles show lab-empty
echo "show_empty_exit=$?"
reload は No changes. 2 bundle(s) loaded. でした。show は Bundle 'lab-empty' not found. で終了コード 1 です。ファイルは 58 バイト残ります。
venv の Python で build_bundle_invocation_message を読むと、先に次の 1 行が出ます。
Bundle /tmp/hibanas-skill-bundles-lab-20260921/skill-bundles/lab-empty.yaml has no skills list; skipping
空配列は、壊れた YAML としては扱いません。索引から外します。私は空の skills を置きません。
一時環境を片付ける
今回作ったパスだけを消します。別のパスなら止めます。
case "$LAB" in
/tmp/hibanas-skill-bundles-lab-20260921)
test -f "$LAB/skill-bundles/lab-ship.yaml"
;;
*)
printf 'unexpected LAB path\n' >&2
exit 1
;;
esac
rm -rf -- "$LAB"
unset HERMES_HOME
test ! -e "$LAB" && printf 'cleanup: OK\n'
この cleanup は記事用の一時 home 向けです。本番 home では実行しません。
私は、同時に使う手順だけを bundle へ置きます。slash 名はスキルと被らせません。YAML の件数と、起動時の loaded がずれたら、欠落を先に直します。
よくあるエラー
| 症状 | 原因 | 対応 |
|---|---|---|
create が loads 2 skills なのに 1 件しか載らない | create は YAML の件数だけを数えるためです | 起動時の loaded と missing を見ます |
| 同じ slash でスキル単体が呼ばれない | 同じ slug では bundle が勝つためです | bundle 名を変えます |
resolve が None | 先頭スラッシュ付き、またはスキル名を渡しているためです | slug だけを渡します |
| 既存名の create が 1 で終わる | --force が無いためです | 別名にするか、上書きするときだけ --force を付けます |
| 空 YAML が一覧に出ない | skills が空だと索引から外れるためです | 1 件以上の実名を書きます |
| 本番の bundle が増える | HERMES_HOME を向けていないためです | 検査は一時 directory で行い、本番 home は使いません |
出典
| 資料 | 確認した内容 |
|---|---|
| Hermes Agent Skills System | bundle の場所、YAML、欠落は致命ではないこと、同名では bundle が勝つこと、prompt cache を壊さないこと |
| Agent Skills 仕様 | SKILL.md の公開形式 |
| 一時directoryの実測 | YAML 163 バイトと 102 バイト、起動メッセージ 1224 文字と 710 文字、空 YAML 58 バイト、重複 create の終了コード 1 |
