> ## Documentation Index
> Fetch the complete documentation index at: https://exosphere-auto-translate-docs-20260624-1149.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# カスタムポリシー

> JavaScriptで独自のポリシーを作成 — 規約の強制、ドリフトの防止、障害の検出、外部システムとの連携

カスタムポリシーを使うと、あらゆるエージェントの動作に対してルールを記述できます。プロジェクト規約の強制、ドリフトの防止、破壊的操作のゲート処理、スタックしたエージェントの検出、Slackや承認ワークフローとの連携など、さまざまな用途に対応しています。組み込みポリシーと同じフックイベントシステムと `allow`、`deny`、`instruct` の判定を使用します。

***

## クイックサンプル

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

customPolicies.add({
  name: "no-production-writes",
  description: "Block writes to paths containing 'production'",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Write" && ctx.toolName !== "Edit") return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("production")) {
      return deny("Writes to production paths are blocked");
    }
    return allow();
  },
});
```

インストール:

```bash theme={null}
failproofai policies --install --custom ./my-policies.js
```

***

## カスタムポリシーの2つの読み込み方法

### オプション1: 規約ベース（推奨）

`*policies.{js,mjs,ts}` ファイルを `.failproofai/policies/` に配置するだけで自動的に読み込まれます。フラグや設定変更は不要です。gitフックと同じ仕組みで、ファイルを置くだけで動作します。

```
# プロジェクトレベル — gitにコミットしてチームで共有
.failproofai/policies/security-policies.mjs
.failproofai/policies/workflow-policies.mjs

# ユーザーレベル — 個人用、すべてのプロジェクトに適用
~/.failproofai/policies/my-policies.mjs
```

**動作の仕組み:**

* プロジェクトとユーザーの両ディレクトリがスキャンされます（和集合 — スコープ優先ではありません）
* ファイルは各ディレクトリ内でアルファベット順に読み込まれます。順序を制御するには `01-`、`02-` などのプレフィックスを付けてください
* `*policies.{js,mjs,ts}` にマッチするファイルのみ読み込まれ、それ以外は無視されます
* 各ファイルは独立して読み込まれます（ファイル単位でフェイルオープン）
* 明示的な `--custom` や組み込みポリシーと共存できます

<Tip>
  規約ポリシーは、組織の品質基準を構築する最も簡単な方法です。`.failproofai/policies/` をgitにコミットすれば、開発者ごとのセットアップなしにすべてのチームメンバーが同じルールを自動的に適用できます。新しい障害パターンを発見したらポリシーを追加してプッシュするだけで、継続的に改善される生きた品質基準が積み上がっていきます。
</Tip>

### オプション2: 明示的なファイルパス

```bash theme={null}
# カスタムポリシーファイルを指定してインストール
failproofai policies --install --custom ./my-policies.js

# ポリシーファイルのパスを変更
failproofai policies --install --custom ./new-policies.js

# 設定からカスタムポリシーのパスを削除
failproofai policies --uninstall --custom
```

解決された絶対パスは `policies-config.json` の `customPoliciesPath` に保存されます。ファイルはフックイベントのたびに新たに読み込まれ、イベント間でのキャッシュはありません。

### 両方を組み合わせて使う

規約ポリシーと明示的な `--custom` ファイルは共存できます。読み込み順序:

1. 明示的な `customPoliciesPath` ファイル（設定されている場合）
2. プロジェクト規約ファイル（`{cwd}/.failproofai/policies/`、アルファベット順）
3. ユーザー規約ファイル（`~/.failproofai/policies/`、アルファベット順）

***

## API

### インポート

```js theme={null}
import { customPolicies, allow, deny, instruct } from "failproofai";
```

### `customPolicies.add(hook)`

ポリシーを登録します。1つのファイルに複数のポリシーを定義する場合は、必要なだけ呼び出せます。

```ts theme={null}
customPolicies.add({
  name: string;                         // 必須 - 一意の識別子
  description?: string;                 // `failproofai policies` の出力に表示
  match?: { events?: HookEventType[] }; // イベントタイプでフィルタ。省略すると全イベントにマッチ
  fn: (ctx: PolicyContext) => PolicyResult | Promise<PolicyResult>;
});
```

### 判定ヘルパー

| 関数                  | 効果               | 使いどころ                       |
| ------------------- | ---------------- | --------------------------- |
| `allow()`           | 操作をサイレントで許可      | アクションが安全でメッセージが不要な場合        |
| `deny(message)`     | 操作をブロック          | エージェントがこのアクションを実行すべきでない場合   |
| `instruct(message)` | ブロックせずにコンテキストを追加 | エージェントが正しい方向に進むための追加情報を渡す場合 |

`deny(message)` — メッセージは `"Blocked by failproofai:"` というプレフィックスが付いて Claude に表示されます。1つでも `deny` が返されると、それ以降の評価は短絡されます。

`instruct(message)` — メッセージは現在のツール呼び出しに対する Claude のコンテキストに追記されます。すべての `instruct` メッセージは蓄積されてまとめて配信されます。

<Tip>
  `deny` や `instruct` のメッセージに追加のガイダンスを付け加えるには、`policyParams` の `hint` フィールドを使います — コードの変更は不要です。カスタム（`custom/`）、プロジェクト規約（`.failproofai-project/`）、ユーザー規約（`.failproofai-user/`）ポリシーでも機能します。詳細は [設定 → hint](/ja/configuration#hint-cross-cutting) を参照してください。
</Tip>

### 情報提供用の allow メッセージ

`allow(message)` は操作を許可しつつ、Claude へ情報メッセージを送信します。メッセージはフックハンドラーの stdout レスポンスの `additionalContext` として配信されます — `instruct` と同じ仕組みですが、意味的には異なります: 警告ではなくステータス更新です。

| 関数               | 効果                      | 使いどころ                               |
| ---------------- | ----------------------- | ----------------------------------- |
| `allow(message)` | 許可しつつ Claude にコンテキストを送信 | チェックが通過したことの確認、またはチェックがスキップされた理由の説明 |

ユースケース:

* **ステータス確認:** `allow("All CI checks passed.")` — すべて正常であることを Claude に伝える
* **フェイルオープンの説明:** `allow("GitHub CLI not installed, skipping CI check.")` — チェックがスキップされた理由を Claude に伝え、完全なコンテキストを提供する
* **複数メッセージの蓄積:** 複数のポリシーがそれぞれ `allow(message)` を返した場合、すべてのメッセージが改行で結合されてまとめて配信される

```js theme={null}
customPolicies.add({
  name: "confirm-branch-status",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    const cwd = ctx.session?.cwd;
    if (!cwd) return allow("No working directory, skipping branch check.");

    // ... ブランチのステータスを確認 ...
    if (allPushed) {
      return allow("Branch is up to date with remote.");
    }
    return deny("Unpushed changes detected.");
  },
});
```

### `PolicyContext` フィールド

| フィールド       | 型                                      | 説明                                                       |
| ----------- | -------------------------------------- | -------------------------------------------------------- |
| `eventType` | `string`                               | `"PreToolUse"`、`"PostToolUse"`、`"Notification"`、`"Stop"` |
| `toolName`  | `string \| undefined`                  | 呼び出されるツール（例: `"Bash"`、`"Write"`、`"Read"`）                |
| `toolInput` | `Record<string, unknown> \| undefined` | ツールの入力パラメータ                                              |
| `payload`   | `Record<string, unknown>`              | Claude Code からの生のイベントペイロード                               |
| `session`   | `SessionMetadata \| undefined`         | セッションコンテキスト（下記参照）                                        |

### `SessionMetadata` フィールド

| フィールド            | 型        | 説明                            |
| ---------------- | -------- | ----------------------------- |
| `sessionId`      | `string` | Claude Code セッション識別子          |
| `cwd`            | `string` | Claude Code セッションの作業ディレクトリ    |
| `transcriptPath` | `string` | セッションの JSONL トランスクリプトファイルへのパス |

### イベントタイプ

| イベント           | 発火タイミング             | `toolInput` の内容                                                                                                             |
| -------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `PreToolUse`   | Claude がツールを実行する前   | ツールの入力（例: Bash の場合 `{ command: "..." }`）                                                                                    |
| `PostToolUse`  | ツールの実行完了後           | ツールの入力 + `tool_result`（出力）                                                                                                  |
| `Notification` | Claude が通知を送信するとき   | `{ message: "...", notification_type: "idle" \| "permission_prompt" \| ... }` — フックは常に `allow()` を返す必要があり、通知をブロックすることはできません |
| `Stop`         | Claude セッションが終了するとき | 空                                                                                                                           |

***

## 評価順序

ポリシーは以下の順序で評価されます:

1. 組み込みポリシー（定義順）
2. `customPoliciesPath` からの明示的なカスタムポリシー（`.add()` の呼び出し順）
3. プロジェクトの `.failproofai/policies/` からの規約ポリシー（ファイルはアルファベット順、ファイル内は `.add()` の呼び出し順）
4. ユーザーの `~/.failproofai/policies/` からの規約ポリシー（ファイルはアルファベット順、ファイル内は `.add()` の呼び出し順）

<Note>
  最初の `deny` はそれ以降のすべてのポリシーを短絡します。すべての `instruct` メッセージは蓄積されてまとめて配信されます。
</Note>

***

## 推移的なインポート

カスタムポリシーファイルは相対パスを使ってローカルモジュールをインポートできます:

```js theme={null}
// my-policies.js
import { isBlockedPath } from "./utils.js";
import { checkApproval } from "./approval-client.js";

customPolicies.add({
  name: "approval-gate",
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const approved = await checkApproval(ctx.toolInput?.command, ctx.session?.sessionId);
    return approved ? allow() : deny("Approval required for this command");
  },
});
```

エントリファイルから到達可能なすべての相対インポートが解決されます。これは `from "failproofai"` インポートを実際の dist パスに書き換え、ESM 互換性を確保するために一時的な `.mjs` ファイルを作成することで実装されています。

***

## イベントタイプのフィルタリング

`match.events` を使って、ポリシーが発火するタイミングを限定できます:

```js theme={null}
customPolicies.add({
  name: "require-summary-on-stop",
  match: { events: ["Stop"] },
  fn: async (ctx) => {
    // セッション終了時のみ発火
    // ctx.session.transcriptPath にセッションの全ログが含まれる
    return allow();
  },
});
```

`match` を完全に省略すると、すべてのイベントタイプで発火します。

***

## エラー処理と障害モード

カスタムポリシーは**フェイルオープン**です。エラーが発生しても組み込みポリシーをブロックしたり、フックハンドラーをクラッシュさせたりすることはありません。

| 障害                        | 動作                                                   |
| ------------------------- | ---------------------------------------------------- |
| `customPoliciesPath` が未設定 | 明示的なカスタムポリシーは実行されず、規約ポリシーと組み込みポリシーは通常通り継続            |
| ファイルが見つからない               | `~/.failproofai/hook.log` に警告を記録し、組み込みポリシーは継続        |
| 構文/インポートエラー（明示的）          | `~/.failproofai/hook.log` にエラーを記録し、明示的なカスタムポリシーをスキップ |
| 構文/インポートエラー（規約）           | エラーを記録し、そのファイルをスキップ。他の規約ファイルは引き続き読み込まれる              |
| `fn` が実行時に例外をスロー          | エラーを記録し、そのフックを `allow` として扱い、他のフックは継続                |
| `fn` が10秒以上かかる            | タイムアウトを記録し、`allow` として扱う                             |
| 規約ディレクトリが存在しない            | 規約ポリシーは実行されず、エラーなし                                   |

<Tip>
  カスタムポリシーのエラーをデバッグするには、ログファイルを監視してください:

  ```bash theme={null}
  tail -f ~/.failproofai/hook.log
  ```
</Tip>

***

## 全サンプル: 複数ポリシー

```js theme={null}
// my-policies.js
import { customPolicies, allow, deny, instruct } from "failproofai";

// エージェントが secrets/ ディレクトリに書き込まないようにする
customPolicies.add({
  name: "block-secrets-dir",
  description: "Prevent agent from writing to secrets/ directory",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (!["Write", "Edit"].includes(ctx.toolName ?? "")) return allow();
    const path = ctx.toolInput?.file_path ?? "";
    if (path.includes("secrets/")) return deny("Writing to secrets/ is not permitted");
    return allow();
  },
});

// エージェントを正しい方向に維持: コミット前にテストを確認
customPolicies.add({
  name: "remind-test-before-commit",
  description: "Keep the agent on track: verify tests pass before committing",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    if (/git\s+commit/.test(cmd)) {
      return instruct("Verify all tests pass before committing. Run `bun test` if you haven't already.");
    }
    return allow();
  },
});

// フリーズ期間中の計画外の依存関係変更を防ぐ
customPolicies.add({
  name: "dependency-freeze",
  description: "Prevent unplanned dependency changes during freeze period",
  match: { events: ["PreToolUse"] },
  fn: async (ctx) => {
    if (ctx.toolName !== "Bash") return allow();
    const cmd = ctx.toolInput?.command ?? "";
    const isInstall = /^(npm install|yarn add|bun add|pnpm add)\s+\S/.test(cmd);
    if (isInstall && process.env.DEPENDENCY_FREEZE === "1") {
      return deny("Package installs are frozen. Unset DEPENDENCY_FREEZE to allow.");
    }
    return allow();
  },
});

export { customPolicies };
```

***

## サンプル集

`examples/` ディレクトリにはすぐに使えるポリシーファイルが含まれています:

| ファイル                                                 | 内容                                                   |
| ---------------------------------------------------- | ---------------------------------------------------- |
| `examples/policies-basic.js`                         | 一般的なエージェント障害モードをカバーする5つのスターターポリシー                    |
| `examples/policies-advanced/index.js`                | 高度なパターン: 推移的なインポート、非同期呼び出し、出力のスクラビング、セッション終了フック      |
| `examples/convention-policies/security-policies.mjs` | 規約ベースのセキュリティポリシー（.env ファイルへの書き込みのブロック、git 履歴の書き換え防止） |
| `examples/convention-policies/workflow-policies.mjs` | 規約ベースのワークフローポリシー（テストリマインダー、ファイル書き込みの監査）              |

### 明示的なファイルサンプルの使い方

```bash theme={null}
failproofai policies --install --custom ./examples/policies-basic.js
```

### 規約ベースのサンプルの使い方

```bash theme={null}
# プロジェクトレベルにコピー
mkdir -p .failproofai/policies
cp examples/convention-policies/*.mjs .failproofai/policies/

# またはユーザーレベルにコピー
mkdir -p ~/.failproofai/policies
cp examples/convention-policies/*.mjs ~/.failproofai/policies/
```

インストールコマンドは不要です。次のフックイベント時に自動的にファイルが読み込まれます。
