Hermes Agentのリポ内スキルはtrustしてから読む|cloneしただけでは載らない

作業 directory は Git の中なのに、hermes skills trust は Not inside a git checkout と返しました。終了コードは 0 です。パスを省略したためです。この実行では TERMINAL_CWD がホームを指し、find_project_root() は None でした。
リポに置いた SKILL.md は、clone しただけでは索引へ入りません。skills.trusted_project_dirs に root を入れてから、その checkout で始まったセッションだけが読みます。
2026 年 9 月 20 日、Hermes Agent v0.21.0 の一時 home と一時 Git リポで確認しました。スキル本文は 411 バイト、説明は 40 文字でした。本番の home は使っていません。
前回の手順の置き場から、リポの境界へ進む
前回の「Hermes Agentの手順はスキルへ残す」では、作業手順を Memory へ置かず、スキルへ残しました。今回は、そのスキルをリポへ vendoring したときに、誰のセッションへ載るかを実測します。
| 時点 | 確認できる範囲 |
|---|---|
| 前回完了時 | 手順はスキルへ残し、手書きは adopt と pin で区別できます |
| 今回開始時 | リポ内の .hermes/skills が、いつ索引へ載るかが未確認です |
| 今回完了後 | パス付き trust、untrust、TERMINAL_CWD、list に出ない点を区別できます |
プロファイルへ置く手順だけ知りたい場合は前回へ戻ります。なぜ clone しただけでは読まないのかだけ知りたい場合は次の節まで読めば足ります。cron から使う場合は「非対話は workdir を見る」へ進みます。
なぜ clone しただけでは読まないのか
スキルは手順書です。エージェントは本文を、該当した仕事の手順として辿ります。任意の clone から自動で読むと、他人が置いた SKILL.md を、自分の運用手順として飲んでしまいます。公式 docs も、ここを prompt-injection の入口として扱っています。
私は次の分岐で扱います。
毎回使う事実 → Memory
自分の作業手順 → プロファイルの skills/
このリポだけの手順 → <root>/.hermes/skills/ または .agents/skills/
読む許可 → hermes skills trust(root を記録)
git pull のあとの中身 → スキャン。dangerous は索引から外す
許可はリポ単位です。中身は pull のたびに変わります。trust したあとも、Hub と同じ scanner が各 SKILL.md を見ます。verdict が dangerous のものは索引、skills_list、slash から外れます。caution は載ります。scanner が落ちた場合は閉じます。キャッシュは Hermes home 側で、リポ内には書きません。
用語を揃える
| 用語 | この回での意味 |
|---|---|
| project skill | Git root 配下の .hermes/skills または .agents/skills にあるスキルです |
| Git root | .git がある最も近い祖先です。directory でも worktree のファイルでも足ります |
| trust | その root を skills.trusted_project_dirs へ入れる操作です |
| untrust | その記録を外す操作です |
TERMINAL_CWD | 表面の作業 directory です。cron の workdir もここから解決します |
[project] | 索引で、リポ由来だと分かる印です |
| 優先順位 | project、プロファイル、external_dirs の順です。同名は project が勝ちます |
| quarantine | dangerous 判定で、そのスキルだけ索引から外すことです |
| curator | エージェントが作ったスキルの手入れです。リポ所有のスキルは対象外です |
どこを見て、何を載せるか
セッション開始
│
├─ TERMINAL_CWD があれば、そこから git root を探す
└─ 無ければプロセスの cwd から探す
│
▼
git root が trusted_project_dirs にある
│
├─ ない → 索引へ載せない。件数だけの通知
└─ ある → .hermes/skills と .agents/skills を読む
│
├─ dangerous → そのスキルだけ外す
└─ それ以外 → 索引へ [project] 付きで載せる
ホームそのものが Git の checkout でも、project にはしません。dotfiles をホームに置くと、すべての会話がリポ扱いになります。
一時環境を用意する
本番の Hermes home は使いません。同名の directory がある場合は上書きせず止めます。
LAB=/tmp/hibanas-project-skills-trust-lab-20260920
REPO=/tmp/hibanas-project-skills-repo-20260920
[ ! -e "$LAB" ] || {
printf 'already exists: %s\n' "$LAB"
exit 1
}
[ ! -e "$REPO" ] || {
printf 'already exists: %s\n' "$REPO"
exit 1
}
mkdir -p "$LAB" "$REPO/.hermes/skills/ops/lab-repo-deploy"
git -C "$REPO" init -q
printf '# lab\n' > "$REPO/README.md"
git -C "$REPO" add README.md
git -C "$REPO" -c [email protected] -c user.name=lab commit -qm 'init'
touch "$LAB/.no-bundled-skills"
export HERMES_HOME="$LAB"
今回の実機は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)
.no-bundled-skillsが無いと、空の home でも同梱スキルが流れ込みます。検査では 1 件だけを見るため、印を先に置きます。
検査用のスキルを置く
説明は 40 文字です。本番のデプロイ手順ではありません。
cat > "$REPO/.hermes/skills/ops/lab-repo-deploy/SKILL.md" <<'EOF'
---
name: lab-repo-deploy
description: Deploy the lab repo after a green check.
---
# Lab repo deploy
## When to Use
Use after CI is green in this repository.
## Procedure
1. Read the latest CI log.
2. Deploy the lab target only.
3. Confirm the health endpoint returns 200.
## Pitfalls
- Do not deploy production.
- Do not copy this procedure into MEMORY.md.
## Verification
Health check returns HTTP 200.
EOF
ファイルは 411 バイトでした。
パスを省略すると、cwd だけでは足りない
cd してからパスなしで trust しても、この実行では Git の checkout ではないと返りました。
hermes skills trust
Not inside a git checkout. Run from a project directory or pass the project root path explicitly.
終了コードは 0 です。失敗に見えて、プロセスは止まっていません。find_project_root() は start を省略すると、プロセスの cwd より TERMINAL_CWD を先に見ます。このジョブでは TERMINAL_CWD がホームを指していました。ホームは project にしないので、結果は None です。
非対話の cron も同じ解決です。スケジューラの cwd がリポの外でも、ジョブの workdir が trusted な root なら載ります。workdir が未設定、または未許可のリポなら、1 件も載せません。プロンプトは出ません。自動では許可しません。
パスを渡して許可する
hermes skills trust "$REPO"
Trusted: /tmp/hibanas-project-skills-repo-20260920
1 project skill(s) will load in sessions started inside this repo (they take precedence over same-named profile skills).
同じパスをもう一度渡すと、件数は変わらず既許可と出ます。
Already trusted: /tmp/hibanas-project-skills-repo-20260920
1 project skill(s) will load in sessions started inside this repo (they take precedence over same-named profile skills).
記録先は一時 home の config.yaml でした。本番の設定には、今回の REPO は入っていません。
skills:
trusted_project_dirs:
- /tmp/hibanas-project-skills-repo-20260920
外すときはパスを付けます。
hermes skills untrust "$REPO"
Untrusted: /tmp/hibanas-project-skills-repo-20260920
Project skills from this repo will no longer load.
list には出ない
trust の前後で、installed の一覧は 0 件のままでした。
hermes skills list --source all
0 hub-installed, 0 builtin, 0 local — 0 enabled, 0 disabled
project skill は Hub やプロファイルへインストールした行ではありません。その checkout で始まったセッションの索引へ、[project] 付きで載ります。一覧が空でも、許可は別です。
許可の有無を Python で見る
Install directory は hermes --version の該当行を使います。ユーザー名付きの絶対パスはコマンドへ埋めません。
install_dir=$(hermes --version | awk -F': ' '/^Install directory:/{print $2}')
PYTHONPATH="$install_dir" TERMINAL_CWD="$REPO" python3 - <<'PY'
import os
from agent.skill_utils import (
_external_dirs_cache_clear,
find_project_root,
get_project_skills_dirs,
get_untrusted_project_skills_root,
)
_external_dirs_cache_clear()
print("find_project_root", find_project_root())
print("untrusted_notice", get_untrusted_project_skills_root())
print("project_dirs", get_project_skills_dirs())
PY
untrust のあとは次のとおりでした。
find_project_root /tmp/hibanas-project-skills-repo-20260920
untrusted_notice (PosixPath('/tmp/hibanas-project-skills-repo-20260920'), 1)
project_dirs []
notice の 1 は、載っていないスキルの件数です。dirs は空です。対話セッションなら、ここで件数だけの通知が出ます。中身はまだ読みません。
trust し直したあとは次のとおりでした。
find_project_root /tmp/hibanas-project-skills-repo-20260920
untrusted_notice None
project_dirs [PosixPath('/tmp/hibanas-project-skills-repo-20260920/.hermes/skills')]
正しい SKILL.md を渡すと、隔離は False でした。同じパスは is_external_skill_path が True です。リポ所有として扱い、curator は触れません。新しいスキルの作成先も、プロファイル側のままです。
存在しないパスを scanner に渡すと、今回は FileNotFoundError のあと fail-closed で隔離 True になりました。検査では実在する SKILL.md だけを渡します。
一時環境を片付ける
今回作ったパスだけを消します。別のパスなら止めます。
case "$LAB" in
/tmp/hibanas-project-skills-trust-lab-20260920)
test -f "$REPO/.hermes/skills/ops/lab-repo-deploy/SKILL.md"
;;
*)
printf 'unexpected LAB path\n' >&2
exit 1
;;
esac
case "$REPO" in
/tmp/hibanas-project-skills-repo-20260920)
;;
*)
printf 'unexpected REPO path\n' >&2
exit 1
;;
esac
hermes skills untrust "$REPO"
rm -rf -- "$LAB" "$REPO"
unset HERMES_HOME
test ! -e "$LAB" && test ! -e "$REPO" && printf 'cleanup: OK\n'
この cleanup は記事用の一時 home と一時リポ向けです。本番 home では実行しません。
私は、リポ固有の手順だけを .hermes/skills へ置きます。読む前にパス付きで trust します。cron では workdir をその root に合わせます。一覧が空なことを、未配置だとは見なしません。
よくあるエラー
| 症状 | 原因 | 対応 |
|---|---|---|
| Git の中なのに checkout ではないと出る | パス省略時は TERMINAL_CWD を先に見るためです | root を引数で渡します |
| 終了コードが 0 のまま許可されない | パス省略の失敗は非 0 にしません | 出力の文面を見ます |
skills list が 0 件 | project skill は installed 行ではないためです | trust の件数と Python の dirs を見ます |
| trust しても cron で載らない | ジョブの workdir が root ではないためです | workdir を checkout へ合わせます |
| 存在しないパスが隔離される | scanner 失敗は閉じるためです | 実在する SKILL.md だけを渡します |
| 本番の許可リストが変わる | HERMES_HOME を向けていないためです | 検査は一時 directory で行い、本番 home は使いません |
出典
| 資料 | 確認した内容 |
|---|---|
| Hermes Agent Skills System | project skill の場所、trust、優先順位、隔離、非対話の workdir |
| Hermes Agent Curator | リポ所有のスキルは手入れ対象外 |
| Agent Skills 仕様 | SKILL.md の公開形式 |
| 一時directoryの実測 | 説明 40 文字、本文 411 バイト、パス省略の文面、trust 1 件、untrust、list 0 件、notice 1 件 |
