> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 権限制御

Qoder Agent SDK の権限制御機能は、1回の `query()` セッション内でモデルが何を実行できるかを管理します。モデルに見えるツールの制限、デフォルト認可ポリシーの設定、ツール実行前のホストアプリケーションによる承認、ユーザー承認後の新しいルールの適用などが可能です。

権限制御は単独の API ではなく、`query({ options })` に配置される設定の集合です。通常、まず今回のセッションでモデルが使用できるツールを決め、次にそれらのツールがどのような条件で実行可能かを決め、最後に必要に応じてランタイム承認、動的ルール更新、settings、hooks を接続します。

```typescript theme={null}
const messages = query({
  prompt: 'Inspect the repository and summarize risky changes.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    tools: ['Read', 'Grep', 'Bash'],
    allowedTools: ['Read', 'Grep'],
    disallowedTools: ['Bash'],
    permissionMode: 'default',
  },
});

for await (const message of messages) {
  console.log(message);
}
```

上記の例は一般的なポリシーを表現しています：モデルは `Read`、`Grep`、`Bash` を参照でき、そのうち `Read` と `Grep` は事前承認済み、`Bash` は実行禁止です。実際のプロジェクトでは、さらに `canUseTool` を追加して、事前承認されていない操作を独自のプロダクト UI、承認システム、リスク管理サービスに委ねることができます。

<div id="クイックスタートホストアプリケーションによるツール呼び出し承認" />

## クイックスタート：ホストアプリケーションによるツール呼び出し承認

ツール呼び出しを独自の承認ロジックに接続する場合は、`canUseTool` を使用します。SDK はランタイムでツール名、ツール入力パラメータ、および表示可能な承認情報をコールバックに渡します。コールバックが `allow` を返すとツールは実行を続け、`deny` を返すとツールは拒否されます。

```typescript theme={null}
const readOrder = tool(
  'read_order',
  'Read an order by ID.',
  { orderId: z.string() },
  async ({ orderId }) => ({
    content: [{ type: 'text', text: `order:${orderId}` }],
  }),
);

const server = createSdkMcpServer({
  name: 'orders',
  tools: [readOrder],
});

query({
  prompt: 'Read order 1001.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: { orders: server },
    permissionMode: 'default',
    async canUseTool(toolName, input, options) {
      if (toolName !== 'mcp__orders__read_order') {
        return {
          behavior: 'deny',
          message: 'Only order reads are allowed in this workflow.',
          toolUseID: options.toolUseID,
        };
      }

      return {
        behavior: 'allow',
        updatedInput: input,
        toolUseID: options.toolUseID,
      };
    },
  },
});
```

この例では、`read_order` は SDK MCP ツールです。モデルがこれを呼び出す際、完全なツール名は `mcp__orders__read_order` になります。`canUseTool` はこのツールのみ実行を許可し、元の入力パラメータを `updatedInput` として返します。`toolUseID` を返すことで、ランタイムが承認結果と今回のツール呼び出しを正確に対応付けることができます。

<div id="デフォルトポリシーの制御permissionmode" />

## デフォルトポリシーの制御：permissionMode

`permissionMode` はセッションのデフォルト権限ポリシーを決定します。「今回のセッション全体がどのモードか」を表現するのに適しています（例：先に計画、編集の自動受け入れ、確認なしの直接拒否、制御環境での権限チェックのスキップ）。

```typescript theme={null}
query({
  prompt: 'Plan the migration. Do not edit files yet.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'plan',
    planModeInstructions: 'Only produce a concise migration checklist.',
  },
});
```

`plan` モードはモデルに先に計画を出力させるのに適しています。`planModeInstructions` は計画モードのワークフロー説明を上書きし、モデルに必要な形式で計画を出力させることができます。

| モード                 | 動作                                                                              |
| ------------------- | ------------------------------------------------------------------------------- |
| `default`           | 標準権限動作。ツール呼び出しは tools、allow/deny ルール、動的承認、ランタイムポリシーに従って処理                       |
| `acceptEdits`       | ファイル編集操作を自動受け入れ。ワークスペースの変更が確認済みの場合に適する                                          |
| `bypassPermissions` | 権限チェックをスキップ。`allowDangerouslySkipPermissions: true` の同時設定が必須                    |
| `yolo`              | `bypassPermissions` の互換エイリアス。同様に `allowDangerouslySkipPermissions: true` の設定が必須 |
| `plan`              | 計画モード。実行計画の出力に適し、デフォルトでは実際の変更を行わない                                              |
| `dontAsk`           | 対話的確認を行わない。事前承認されていない、ルールで許可されていない操作は拒否される                                      |
| `auto`              | ランタイム機能により自動的に allow または deny を判断。安全なワークスペース内ファイル編集は自動通過の可能性あり                  |

同一セッション内でモードを切り替える必要がある場合は、返される `Query` オブジェクトを使用できます：

```typescript theme={null}
const q = query({
  prompt: 'Plan the change first.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'plan',
  },
});

await q.setPermissionMode('default');
```

`bypassPermissions` と `yolo` はどちらも高リスクモードです。SDK は明示的に `allowDangerouslySkipPermissions: true` を渡すことを要求し、呼び出し側が誤って通常のセッションを権限チェックスキップのセッションに変えてしまうのを防ぎます。

```typescript theme={null}
query({
  prompt: 'Run the trusted local maintenance task.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'bypassPermissions',
    allowDangerouslySkipPermissions: true,
  },
});
```

<div id="ツール範囲の制御toolsallowedtoolsdisallowedtools" />

## ツール範囲の制御：tools、allowedTools、disallowedTools

ツール制御は「モデルがどのツールを参照でき、どのツールがデフォルトで許可または禁止か」という問題に答えます。この3つのフィールドは一緒に使用されることが多いですが、意味が異なります。

```typescript theme={null}
query({
  prompt: 'Inspect the repo without modifying it.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    tools: ['Read', 'Grep', 'Bash'],
    allowedTools: ['Read', 'Grep'],
    disallowedTools: ['Bash'],
  },
});
```

この設定の意味：今回のセッションでは `Read`、`Grep`、`Bash` の3つのツールのみ提供され、`Read` と `Grep` は事前承認済み、`Bash` は禁止（モデルが呼び出そうとしても実行されない）。

| フィールド             | 役割                     | 適するシーン               |
| ----------------- | ---------------------- | -------------------- |
| `tools`           | 今回のセッションで利用可能なツール集合の制限 | モデルの能力境界を縮小          |
| `allowedTools`    | 許可ルールの追加               | 低リスクツールで繰り返し承認を不要にする |
| `disallowedTools` | 拒否ルールの追加               | 高リスクツールの明示的禁止        |

同じツールが allow と deny の両方にマッチする場合、deny が優先されます。これにより、より広い許可ルールによって禁止ルールがバイパスされることを防ぎます。

MCP ツールも完全なツール名でマッチします。例えば SDK MCP server 名が `orders`、ツール名が `read_order` の場合、完全なツール名は `mcp__orders__read_order` です。

```typescript theme={null}
query({
  prompt: 'Read order 1001.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: { orders: server },
    allowedTools: ['mcp__orders__read_order'],
  },
});
```

<div id="ランタイム承認canusetool" />

<div id="canusetool" />

## ランタイム承認：canUseTool

`canUseTool` はホストアプリケーションが承認に参加する必要があるシーンに適しています。例えば、権限リクエストを独自の UI に表示してユーザーに「1回許可」「このセッションで常に許可」「拒否」を選択させたい場合や、企業のリスク管理サービスを呼び出してコマンドが実行可能かを判断したい場合です。

```typescript theme={null}
query({
  prompt: 'Create a changelog file for this release.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    permissionMode: 'default',
    async canUseTool(toolName, input, options) {
      showApprovalDialog({
        title: options.title ?? toolName,
        description: options.description,
        input,
      });

      const approved = await waitForUserApproval(options.signal);

      if (!approved) {
        return {
          behavior: 'deny',
          message: 'Rejected by user.',
          toolUseID: options.toolUseID,
        };
      }

      return {
        behavior: 'allow',
        updatedInput: input,
        toolUseID: options.toolUseID,
      };
    },
  },
});
```

`canUseTool` のシグネチャは以下の通りです：

```typescript theme={null}
type CanUseTool = (
  toolName: string,
  input: Record<string, unknown>,
  options: {
    signal: AbortSignal;
    suggestions?: PermissionUpdate[];
    blockedPath?: string;
    decisionReason?: string;
    title?: string;
    displayName?: string;
    description?: string;
    toolUseID: string;
    agentID?: string;
  },
) => Promise<PermissionResult>;
```

主要フィールドの説明：

| フィールド                                           | 説明                                                  |
| ----------------------------------------------- | --------------------------------------------------- |
| `toolName`                                      | 完全なツール名（例: `Read`、`Bash`、`mcp__orders__read_order`） |
| `input`                                         | 今回のツール呼び出しの元のパラメータ                                  |
| `options.toolUseID`                             | 今回のツール呼び出し ID。承認結果を返す際に含めることを推奨                     |
| `options.signal`                                | 承認リクエストがキャンセルされると abort される。UI やリモート承認はこれを監視すべき     |
| `options.title` / `displayName` / `description` | ランタイムで生成された人間が読める文言。承認 UI に直接使用可能                   |
| `options.suggestions`                           | ランタイムが提案する権限更新。「このセッションで常に許可」に使用可能                  |
| `options.blockedPath`                           | パス関連の承認シーンにおける制限されたパス                               |
| `options.decisionReason`                        | ランタイムが提供する承認理由の説明。表示や監査に使用可能                        |
| `options.agentID`                               | サブエージェントがツール呼び出しを発行した際のエージェント ID                    |

`allow` を返すとツールの実行が継続されます：

```typescript theme={null}
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
};
```

`updatedInput` はツールが最終的に受け取るパラメータです。そのまま返すこともできますし、承認通過後にパラメータを変更することもできます。例えば、クエリにテナント ID を追加したり、パスを安全なディレクトリに書き換えたり、許可されないフィールドを削除したりできます。

`deny` を返すとツールは拒否されます：

```typescript theme={null}
return {
  behavior: 'deny',
  message: 'This command is not allowed in the current workspace.',
  toolUseID: options.toolUseID,
};
```

`deny.message` は必須で、拒否理由の一部となり、モデル、ログ、またはホストアプリケーションに表示されます。SDK が CLI からの承認リクエストを受け取ったが `canUseTool` が設定されていない場合、エラーを返し、デフォルトでは許可しません。

権限システムがツール呼び出しを直接拒否した場合、メッセージストリームに構造化された権限拒否メッセージが表示されることがあります：

```typescript theme={null}
type SDKPermissionDeniedMessage = {
  type: 'system';
  subtype: 'permission_denied';
  tool_name: string;
  tool_use_id?: string;
  message?: string;
  decision_reason?: string;
  decision_reason_type?: string;
};
```

このタイプのメッセージは `permissionMode: 'dontAsk'`、自動拒否、ルール拒否などのシーンでよく見られます。ホストアプリケーションはこれを使って UI 状態を更新したり、監査ログを書き込んだりできます。

<div id="セッション内での権限更新permissionupdate" />

## セッション内での権限更新：PermissionUpdate

`PermissionUpdate` は1回の承認後に現在のセッション内の権限ルールを更新するために使用します。最も一般的なシーンは、ユーザーが承認 UI で「このセッションで常に許可」を選択する場合です。この場合、ランタイムが提供する `suggestions` をそのまま返すことも、明示的なルールを自分で構築することもできます。

```typescript theme={null}
async function canUseTool(toolName, input, options) {
  const decision = await showApprovalDialog({
    toolName,
    suggestions: options.suggestions,
  });

  if (decision === 'always-allow-this-session') {
    return {
      behavior: 'allow',
      updatedInput: input,
      toolUseID: options.toolUseID,
      updatedPermissions: options.suggestions,
    };
  }

  if (decision === 'allow-once') {
    return {
      behavior: 'allow',
      updatedInput: input,
      toolUseID: options.toolUseID,
    };
  }

  return {
    behavior: 'deny',
    message: 'Rejected by user.',
    toolUseID: options.toolUseID,
  };
}
```

ルールを直接構築することもできます：

```typescript theme={null}
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
  updatedPermissions: [
    {
      type: 'addRules',
      behavior: 'allow',
      destination: 'session',
      rules: [{ toolName: 'mcp__orders__read_order' }],
    },
  ],
};
```

サポートされる更新タイプ：

| タイプ                 | 役割                    |
| ------------------- | --------------------- |
| `addRules`          | allow、ask、deny ルールの追加 |
| `replaceRules`      | ルールの置換                |
| `removeRules`       | ルールの削除                |
| `setMode`           | 権限モードの切り替え            |
| `addDirectories`    | アクセス許可ディレクトリの追加       |
| `removeDirectories` | ディレクトリ承認の削除           |

動的権限更新は現在のセッションに書き込むことを推奨します：

```typescript theme={null}
destination: 'session'
```

`session` は現在の query セッションの後続の権限チェックにのみ影響します。ローカル、プロジェクト、またはユーザーレベルの設定に永続化する必要がある場合は、単一のツール承認コールバック内の動的更新に依存するのではなく、settings 管理フローを優先的に使用してください。

<div id="追加ディレクトリへのアクセスadditionaldirectories" />

## 追加ディレクトリへのアクセス：additionalDirectories

デフォルトでは、セッションは `cwd` を主要な作業ディレクトリとします。モデルが `cwd` 外のディレクトリを読み取りまたは変更する必要がある場合は、明示的に `additionalDirectories` を渡す必要があります。

```typescript theme={null}
query({
  prompt: 'Inspect the app and the shared package.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/repo/app',
    additionalDirectories: ['/repo/packages/shared'],
  },
});
```

この設定は、セッションの主要作業ディレクトリが `/repo/app` であり、同時にモデルが `/repo/packages/shared` にアクセスすることを許可することを意味します。これは monorepo、クロスリポジトリデバッグ、共有ライブラリの調査などのシーンに適しています。

実行中に `PermissionUpdate` を通じてディレクトリ承認を調整することもできます：

```typescript theme={null}
return {
  behavior: 'allow',
  updatedInput: input,
  toolUseID: options.toolUseID,
  updatedPermissions: [
    {
      type: 'addDirectories',
      destination: 'session',
      directories: ['/repo/packages/shared'],
    },
  ],
};
```

ディレクトリ承認は権限境界の一部です。広範囲のディレクトリを汎用デフォルト値として `additionalDirectories` に追加しないでください。より安全なアプローチは、タスクの必要に応じて最小限のディレクトリセットを追加することです。

<div id="外部承認ツールpermissionprompttoolname" />

## 外部承認ツール：permissionPromptToolName

`permissionPromptToolName` は権限リクエストを実行環境の permission prompt tool に委任するために使用します。SDK ホスト内で `canUseTool` を実装する代わりに使用します。既存の外部承認ツール、リモート実行環境、または統一権限ゲートウェイがあるシーンに適しています。

```typescript theme={null}
query({
  prompt: 'Run the task.',
  options: {
    auth: accessTokenFromEnv(),
    permissionPromptToolName: 'mcp__permission_server__approve',
  },
});
```

使用時の注意点：

* `permissionPromptToolName` は現在の実行環境が認識できる prompt tool 名である必要があります。
* `permissionPromptToolName` と `canUseTool` は排他的であり、同時に渡すことはできません。
* SDK ホスト自体が承認を決定する場合は、`canUseTool` を優先的に使用してください。

permission prompt tool は以下の入力を受け取ります：

```typescript theme={null}
type PermissionPromptToolInput = {
  tool_name: string;
  input: Record<string, unknown>;
  tool_use_id?: string;
};
```

権限結果を返す必要があります：

```typescript theme={null}
type PermissionPromptToolOutput =
  | {
      behavior: 'allow';
      updatedInput: Record<string, unknown>;
      updatedPermissions?: PermissionUpdate[];
      toolUseID?: string;
    }
  | {
      behavior: 'deny';
      message: string;
      interrupt?: boolean;
      toolUseID?: string;
    };
```

`allow.updatedInput` はツール実行時に使用される最終的な入力パラメータです。元の入力パラメータを保持する場合は、受け取った `input` をそのまま返す必要があります。`deny.message` は必須です。`interrupt: true` は拒否後に現在のエージェントフローを中断することを示します。

<div id="settings-による権限ルールの提供" />

## settings による権限ルールの提供

`settings` はセッション開始前に静的権限設定を提供するのに適しています。`canUseTool` よりも「このプロジェクトでデフォルトで何を許可し、何を拒否し、追加ディレクトリは何か」を表現するのに適しています。

```typescript theme={null}
query({
  prompt: 'Inspect the project.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    settings: {
      permissions: {
        allow: ['Read', 'Grep'],
        deny: ['Bash'],
        ask: ['Write'],
        defaultMode: 'default',
        additionalDirectories: ['/path/to/shared-lib'],
      },
    },
  },
});
```

フィールドの説明：

| フィールド                                      | 説明                                  |
| ------------------------------------------ | ----------------------------------- |
| `permissions.allow`                        | 許可ルール                               |
| `permissions.deny`                         | 拒否ルール                               |
| `permissions.ask`                          | 常に確認ルール                             |
| `permissions.defaultMode`                  | デフォルト権限モード                          |
| `permissions.disableBypassPermissionsMode` | `'disable'` に設定すると権限チェックスキップモードを無効化 |
| `permissions.additionalDirectories`        | 追加アクセス可能ディレクトリ                      |

アプリケーションが settings のデフォルト権限モードを読み取って適用する場合、高リスクモードの実行前に独自のプロダクトレベルの確認を行うことを推奨します。`bypassPermissions`、`yolo` のようなモードは、明確に信頼された環境でのみ使用すべきです。

<div id="hooks-による高度なインターセプトと監査" />

## hooks による高度なインターセプトと監査

hooks は SDK hooks 体系に既に接続しており、ツールのライフサイクルでより細かな制御を行いたい場合に適しています。`canUseTool` と比較して、hooks は横断的なロジック（監査、アラート、統一インターセプト、拒否理由の記録など）により適しています。

```typescript theme={null}
query({
  prompt: 'Inspect the repo.',
  options: {
    auth: accessTokenFromEnv(),
    cwd: '/path/to/project',
    hooks: {
      PreToolUse: [
        {
          matcher: 'Bash',
          hooks: [
            async (input) => {
              return {
                hookSpecificOutput: {
                  hookEventName: 'PreToolUse',
                  permissionDecision: 'deny',
                  permissionDecisionReason: 'Shell commands are disabled here.',
                },
              };
            },
          ],
        },
      ],
    },
  },
});
```

権限関連の hook は主に3種類あります：

| Hook                | トリガータイミング | 一般的な用途                     |
| ------------------- | --------- | -------------------------- |
| `PreToolUse`        | ツール呼び出し前  | 事前の許可、拒否、確認要求、または後続フローへの委任 |
| `PermissionRequest` | 権限リクエスト時  | 通常の prompt 前に直接許可または拒否を返す  |
| `PermissionDenied`  | 権限拒否後     | 監査、アラート、拒否理由の記録            |

`PreToolUse` は以下を返すことができます：

```typescript theme={null}
{
  hookSpecificOutput: {
    hookEventName: 'PreToolUse',
    permissionDecision: 'allow' | 'deny' | 'ask' | 'defer',
    permissionDecisionReason?: string,
    updatedInput?: Record<string, unknown>,
  },
}
```

`PermissionRequest` はツール承認に類似した権限結果を返すことができます：

```typescript theme={null}
{
  hookSpecificOutput: {
    hookEventName: 'PermissionRequest',
    decision: {
      behavior: 'deny',
      message: 'Denied by policy.',
    },
  },
}
```

`PermissionDenied` は通常、結果を観察するために使用し、ツールの通過は担当しません。入力には拒否されたツール名、ツール入力パラメータ、ツール呼び出し ID、拒否理由が含まれます。

<div id="mcp-tool-policy" />

## MCP Tool Policy

権限ポリシーが特定の MCP server に自然に属する場合、MCP server config にツールレベルの permission policy を直接宣言することもできます。これによりポリシーが MCP server 設定に付随し、グローバルな `allowedTools` や `disallowedTools` に分散することを防ぎます。

```typescript theme={null}
query({
  prompt: 'Use repo tools.',
  options: {
    auth: accessTokenFromEnv(),
    mcpServers: {
      repo_tools: {
        type: 'http',
        url: process.env.REPO_TOOLS_MCP_URL!,
        tools: [
          { name: 'search', permission_policy: 'always_allow' },
          { name: 'write_file', permission_policy: 'always_ask' },
          { name: 'delete_file', permission_policy: 'always_deny' },
        ],
      },
    },
  },
});
```

ポリシーの意味：

| ポリシー           | 動作                |
| -------------- | ----------------- |
| `always_allow` | マッチするツールを直接許可     |
| `always_ask`   | マッチするツールは承認フローに入る |
| `always_deny`  | マッチするツールを直接拒否     |

`name` は MCP tool の元の名前でも完全なツール名でも指定できます（例: `mcp__repo_tools__search`）。実際のマッチング時、ランタイムはポリシー名を現在の MCP ツール呼び出しにマッピングします。
