Hermes Agentのcron権限を3層で止める|承認・運用契約・外部保護を分ける

Hermes Agentのcron権限を3層で止める|承認・運用契約・外部保護を分ける

git push origin mainは、危険コマンド承認が止めてくれるはずです。そう考えて検査すると、結果はallowでした。一方、rm -rf /hardline-denyです。

git push origin main  → allow
rm -rf /              → hardline-deny

不具合ではありません。Hermes Agent の承認機構は、壊れやすいコマンドを止める安全装置です。ジョブによる main への push が妥当かという、業務上の権限までは判断しません。

私は無人の AI エージェントに、1 個の万能な安全装置を期待しない方がよいと考えています。コマンド承認、ジョブの運用契約、外部サービスの保護を分けると、どの壁が何を止めるのか説明できます。

前回の実行監査から、実行前の権限制御へ

前回はhermes cron runsを使い、cron の実行がcompletedfailedunknownのどれで終わったかを追いました。今回は、その手前にある「実行してよい操作」を扱います。

前回完了時今回完了後
実行後の状態を台帳で読めます実行前に3つの保護境界を置けます
unknownの後に副作用を照合します副作用そのものを外部側でも拒否できます
再実行の可否を人が判断しますcronが無人でも禁止操作を機械的に止められます
成否と通知を分けて確認します安全性と業務上の権限を分けて確認します

承認モードの違いを把握済みなら、「3 層の構成」まで飛ばせます。設定前の検査だけ試したい場合は、「実行せずに判定する」から読めます。

なぜ承認だけでは足りないのか

Hermes Agent v0.20.6 の承認機構は、危険なパターンを検出します。再帰削除、ディスクへの書き込み、/etc/の変更、外部スクリプトの直接実行などが対象です。

でも、同じコマンドでも業務上の意味は変わります。git push origin mainは、個人の検証リポジトリでは普通の操作です。レビュー必須の本番リポジトリでは禁止したい操作です。コマンドの文字列だけでは、この違いを判定できません。

cron の実行時、人は画面の前にいません。公式設定のapprovals.cron_modeは、危険コマンドの承認が必要になった場合の動作を決めます。選択肢はdenyapproveです。デフォルト値のdenyは堅実です。ただし、危険パターンに分類されない操作には承認要求が発生しません。

だから、承認は「破壊的か」を見る層に限定します。「この仕事に許された変更か」はジョブの契約で決めます。「契約を破っても通らないか」は GitHub など外部サービスで強制します。

用語を揃える

用語ここでの意味
dangerous commandHermes Agentが危険パターンとして承認対象にするコマンドです
hardline blocklist設定や--yoloでも解除できない、組み込みの拒否規則です
approvals.deny利用者が追加する拒否規則です。大文字と小文字を区別しないglobで照合します
cron_modecronで承認待ちが発生したとき、拒否か自動承認かを決めます
運用契約対象リポジトリ、ブランチ、ファイル、公開条件などをジョブへ明記した規則です
外部保護branch protectionやGitHub Environmentなど、エージェントの外側で強制する規則です
fail-closed判断できない場合に、許可ではなく拒否を選ぶ動作です

3層の構成

cronのプロンプト


[第1層: Hermesの承認]
危険パターン / approvals.deny / hardline blocklist


[第2層: ジョブの運用契約]
workdir / 対象branch / draft固定 / diff検査 / 禁止操作


[第3層: 外部サービスの保護]
branch protection / required review / Environment secrets


許可された副作用だけが残る

第 1 層は広く使える安全装置です。第 2 層は仕事ごとに変わります。第 3 層は、エージェント自身が判断を誤っても越えにくい壁です。

私は第 2 層を文章だけで終わらせず、コマンドでも確認します。たとえば記事生成なら、作業前に clean な worktree を要求します。commit 前には差分が新規記事 1 件と画像 1 件だけかを見ます。生成時はdraft: trueを検査し、mainへ直接 push しません。

ただし、その規則もエージェントの文脈内にあります。最終防衛線にはなりません。GitHub 側で main への直接 push を拒否し、レビュー済み PR だけを受け入れる設定が必要です。

実行せずに判定する

hermes approvals testは、実際の承認ガードへコマンドを通し、判定だけを返します。コマンドの実行、承認プロンプト、設定の保存は行いません。

hermes approvals test --json -- "git status --porcelain"

2026 年 8 月 30 日にローカル backend で実行すると、次の結果でした。

{
  "command": "git status --porcelain",
  "env_type": "local",
  "verdict": "allow",
  "exit_code": 0,
  "rule": null,
  "detail": "no guard matched; would run without a prompt",
  "normalized_variants": [
    "git status --porcelain"
  ]
}

次に、運用上は朝稿ジョブへ許可しない操作を検査します。

hermes approvals test --json -- "git push origin main"

実測では、こちらもallowでした。

{
  "command": "git push origin main",
  "env_type": "local",
  "verdict": "allow",
  "exit_code": 0,
  "rule": null,
  "detail": "no guard matched; would run without a prompt",
  "normalized_variants": [
    "git push origin main"
  ]
}

この出力から分かるのは、承認規則に一致しないことだけです。main への push が業務上承認された、という意味ではありません。

最後に、解除できない拒否を確認します。

hermes approvals test --json -- "rm -rf /"
{
  "command": "rm -rf /",
  "env_type": "local",
  "verdict": "hardline-deny",
  "exit_code": 3,
  "rule": "recursive delete of root filesystem",
  "detail": "matches the hardline blocklist (never bypassable, blocked even under --yolo / approvals.mode=off)",
  "normalized_variants": [
    "rm -rf /"
  ]
}

exit_codeは、許可が 0、承認要求が 2、拒否が 3 です。CI や設定監査へ組み込むときは、表示文字列ではなくこの終了コードを使えます。

第1層に「絶対に実行しない」を足す

組み込みの hardline blocklist は、root filesystem の削除などを止めます。組織固有の禁止操作はapprovals.denyへ追加できます。

approvals:
  mode: smart
  cron_mode: deny
  deny:
    - "git push origin main*"
    - "git push --force*"

approvals.denyは、--yoloapprovals.mode: offより先に適用されます。設定変更は即時に反映され、セッションの再起動は要りません。

パターンは必ず引用符で囲みます。先頭の*は、引用しないと YAML の別の意味として解釈されます。また、glob はコマンド全文に照合されます。許可したい形と拒否したい形をhermes approvals testで別々に検査します。

ここで deny を増やしすぎると、正しい保守作業まで止まります。全リポジトリで禁止する操作だけを置き、特定ジョブだけの禁止事項は第 2 層へ残します。

第2層はジョブを狭くする

cron ジョブには絶対パスの--workdirを設定できます。これにより、対象プロジェクトのAGENTS.mdなどが読み込まれ、file tool と terminal tool の作業ディレクトリも揃います。

hermes cron create "0 8 * * *" \
  "cleanなmainからcontent/YYYY-MM-DD-<slug>を作る。新規記事1件をdraft:trueでPRにし、mainへpushもmergeもしない" \
  --name "Morning draft" \
  --workdir /home/daisuke/gitrepos/hibanas-net \
  --deliver slack

hermes cron create --helpの実測では、--workdirは「absolute path」を受け取ります。存在しないパスや相対 path は作成時に拒否されます。

ジョブの契約には、少なくとも次を明記します。

  • 開始時の worktree が dirty なら、勝手に stash や reset をしません
  • 作業 branch の命名規則を固定します
  • 対象ファイルと件数を固定します
  • commit 前にgit diff --name-only main...HEADで範囲を確認します
  • push 先は現在の content branch だけにします
  • 公開、merge、main への push は別承認に分けます

自然言語だけでなく、差分検査を完了条件へ入れるのが要点です。「記事を書く」と「既存 draft へ触れていないことを証明する」を同じ仕事にします。

第3層で秘密とmainを遠ざける

GitHub の Environment は、required reviewers、許可 branch、environment secrets をまとめて扱えます。approval が必要な Environment では、reviewer が承認するまで job は environment secrets へアクセスできません。

公開 job だけが Environment を参照する形にすると、下書き生成 job へ公開用 secret を渡さずに済みます。AI エージェントが「公開しない」という契約を破っても、secret 自体を持っていなければ公開経路へ進めません。

main 側には branch protection を置きます。直接 push を拒否し、PR レビューや required checks を要求します。第 2 層の「main へ push しない」は意図です。第 3 層の branch protection は強制です。両方が必要です。

よくあるエラー

症状原因直し方
git push origin mainallowになる危険コマンドの分類と、業務上の権限を混同していますジョブ契約へ禁止を明記し、必要ならapprovals.denyとbranch protectionを追加します
cronが危険コマンドで止まるapprovals.cron_mode: denyがfail-closedで働いています自動承認へ変える前に、別の安全なコマンドや外部APIへ置き換えます
deny ruleが読み込まれない*を含むglobを引用せず、YAMLとして壊れていますpattern全体を引用し、hermes approvals testで確認します
deny ruleが通常作業まで止めるpatternが広すぎますコマンド全文に合う狭いglobへ変更します
Dockerでは同じ判定にならないisolated containerではcontainer自体が境界となり、危険コマンド検査が省略されますhost mountとsecret転送を見直し、外部保護を残します
ジョブにworkdirを付けたのに違う場所を触るprompt内で別パスへ移動できるためです対象パスと差分検査を契約へ入れ、外部側でも権限を限定します
下書きjobから公開できてしまう生成jobが公開用secretを持っています公開secretをreview必須のEnvironmentへ移し、生成jobから外します

今回の到達点

Hermes Agent の承認機構は、root filesystem の削除を確実に拒否しました。同じ検査で、git push origin mainは許可されました。この差から、承認機構の役割がはっきりします。

危険コマンド承認は、壊れやすい操作を止めます。運用契約は、そのジョブに許された仕事を狭くします。外部保護は、エージェントが契約を破った場合にも main や公開用 secret を守ります。

無人運転では「承認を厳しくする」だけでは足りません。何を守る壁かを分け、各層を単独で検査できる形にします。私は cron へ仕事を渡す前に、まずhermes approvals testで安全装置の守備範囲を測ります。その外側にある権限は、prompt ではなくサービス側でも閉じます。

一次情報

資料確認した内容
Hermes Agent Securityapprovals.modecron_mode、hardline blocklist、approvals.denyhermes approvals test、container backendでの扱い
Scheduled Tasks (Cron)cronのfresh セッション、--workdir、toolset、gatewayによる定期実行、jobの保存と実行履歴
Hermes Agent CLI Commandshermes cronhermes approvalsのCLI構成
GitHub Deployments and Environmentsrequired reviewers、deployment branch、Environment secretsが利用可能になる条件
この記事をシェア