> ## 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 ではなく、`QoderAgentOptions` に配置される設定の集合です。通常、まず今回のセッションでモデルが使用できるツールを決め、次にそれらのツールがどのような条件で実行可能かを決め、最後に必要に応じてランタイム承認、動的ルール更新、settings、hooks を接続します。

```python theme={null}
from qoder_agent_sdk import QoderAgentOptions, query


async for message in query(
    prompt="Inspect the repository and summarize risky changes.",
    options=QoderAgentOptions(
        cwd="/path/to/project",
        tools=["Read", "Grep", "Bash"],
        allowed_tools=["Read", "Grep"],
        disallowed_tools=["Bash"],
        permission_mode="default",
    ),
):
    print(message)
```

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

<div id="機能概要" />

## 機能概要

`query()` の権限関連 options は大きく 4 つに分類されます。1 つ目はデフォルトポリシーを決定するもので、計画モード、編集の自動許可、対話的な確認の禁止などです。2 つ目はツール範囲とツールルールを決定します。3 つ目はホストアプリケーションをランタイム承認に参加させます。4 つ目はより高度な settings、hooks、MCP ツールポリシーに使用されます。

| 解決したい課題                 | 推奨エントリ                               | 説明                                            |
| ----------------------- | ------------------------------------ | --------------------------------------------- |
| セッションのデフォルト権限動作を設定      | `permission_mode`                    | 明示的なルールに該当しない場合のツール呼び出しの処理方法を決定               |
| 権限チェックのスキップを明示的に確認      | `allow_dangerously_skip_permissions` | `bypassPermissions` または `yolo` と組み合わせて使用      |
| 今回のセッションで参照可能なツールを制限    | `tools`                              | 含まれていないツールは利用可能ツールとしてモデルに提供されない               |
| 一部のツールを事前承認             | `allowed_tools`                      | マッチ後は通常、承認確認に入らない                             |
| 一部のツールを禁止               | `disallowed_tools`                   | マッチ後は拒否、allow より優先                            |
| ホストアプリケーションによるツール呼び出し承認 | `can_use_tool`                       | SDK ホストがランタイムで allow または deny を返す             |
| 承認を外部の prompt tool に委任  | `permission_prompt_tool_name`        | 実行環境が既に permission prompt tool を提供しているシーンに適する |
| 承認後に現在のセッションのルールを更新     | `PermissionUpdate`                   | 「今回許可」または「このセッションで常に許可」によく使われる                |
| cwd 外のディレクトリへのアクセスを許可   | `add_dirs`                           | 今回のセッションでアクセス可能なディレクトリ範囲を拡張                   |
| settings から権限ルールを設定     | `settings`                           | セッション開始時に静的な権限設定を提供するのに適する                    |
| ライフサイクルでインターセプトまたは監査    | `hooks`                              | 高度なインターセプト、監査、アラートに適する                        |
| MCP server にツールポリシーを宣言  | MCP tool policy                      | MCP server 設定でツールレベルの allow/ask/deny を宣言      |

一般的な選択方法：

* モデルにコードを読ませるだけで、変更を許可しない場合：`tools` を設定し、`allowed_tools` で `Read`、`Grep` を事前承認、`disallowed_tools` で `Write`、`Edit`、`Bash` を禁止。
* モデルに先に計画を出力させ、実際の変更を行わせない場合：`permission_mode="plan"` を使用。
* 安全な編集を自動的に通過させたい場合：`permission_mode="acceptEdits"` または `"auto"` を使用。
* 独自の UI で承認ダイアログを表示したい場合：`can_use_tool` を使用。
* ユーザーに「このセッションで常に許可」を選択させたい場合：`can_use_tool` の allow 結果に `updated_permissions` を返す。
* 完全に対話的確認を行わず、事前承認されていないものを直接拒否したい場合：`permission_mode="dontAsk"` を使用。
* monorepo 外の共有ディレクトリにアクセスしたい場合：`add_dirs` を使用。

後続の例では権限設定に焦点を絞るため、メッセージのトラバーサルコードは省略しますが、実際の使用時には `query()` から返される非同期メッセージストリームを引き続き消費する必要があります。Python SDK はデフォルトでローカルの `qodercli` ログイン状態を使用できますが、アプリケーションが明示的な認証を必要とする場合は、`QoderAgentOptions.auth` に独自の認証設定を渡せます。

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

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

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

```python theme={null}
from typing import Any

from qoder_agent_sdk import create_sdk_mcp_server, query, tool
from qoder_agent_sdk.types import (
    PermissionResultAllow,
    PermissionResultDeny,
    QoderAgentOptions,
    ToolPermissionContext,
)


@tool("read_order", "Read an order by ID.", {"order_id": str})
async def read_order(args: dict[str, Any]) -> dict[str, Any]:
    return {"content": [{"type": "text", "text": f"order:{args['order_id']}"}]}


server = create_sdk_mcp_server(name="orders", tools=[read_order])


async def can_use_tool(
    tool_name: str,
    input_data: dict[str, Any],
    context: ToolPermissionContext,
):
    if tool_name != "mcp__orders__read_order":
        return PermissionResultDeny(
            message="Only order reads are allowed in this workflow."
        )

    return PermissionResultAllow(updated_input=input_data)


async for _ in query(
    prompt="Read order 1001.",
    options=QoderAgentOptions(
        mcp_servers={"orders": server},
        permission_mode="default",
        can_use_tool=can_use_tool,
    ),
):
    pass
```

この例では、`read_order` は SDK MCP ツールです。モデルがこれを呼び出す際、完全なツール名は `mcp__orders__read_order` になります。`can_use_tool` はこのツールのみ実行を許可し、元の入力パラメータを `updated_input` として返します。

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

## デフォルトポリシーの制御：permission\_mode

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

```python theme={null}
QoderAgentOptions(
    cwd="/path/to/project",
    permission_mode="plan",
)
```

`plan` モードはモデルに先に計画を出力させるのに適しており、デフォルトでは実際の変更を行いません。

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

同一セッション内でモードを切り替える必要がある場合は、`QoderSDKClient` を使用できます：

```python theme={null}
from qoder_agent_sdk import QoderSDKClient


async with QoderSDKClient(
    options=QoderAgentOptions(
        cwd="/path/to/project",
        permission_mode="plan",
    )
) as client:
    await client.set_permission_mode("default")
```

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

```python theme={null}
QoderAgentOptions(
    cwd="/path/to/project",
    permission_mode="bypassPermissions",
    allow_dangerously_skip_permissions=True,
)
```

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

## ツール範囲の制御：tools、allowed\_tools、disallowed\_tools

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

```python theme={null}
QoderAgentOptions(
    cwd="/path/to/project",
    tools=["Read", "Grep", "Bash"],
    allowed_tools=["Read", "Grep"],
    disallowed_tools=["Bash"],
)
```

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

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

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

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

```python theme={null}
QoderAgentOptions(
    mcp_servers={"orders": server},
    allowed_tools=["mcp__orders__read_order"],
)
```

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

<div id="canusetool" />

<div id="can-use-tool" />

<div id="can_use_tool" />

## ランタイム承認：can\_use\_tool

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

```python theme={null}
async def can_use_tool(
    tool_name: str,
    input_data: dict[str, Any],
    context: ToolPermissionContext,
):
    show_approval_dialog(
        title=context.title or tool_name,
        description=context.description,
        input_data=input_data,
    )

    approved = await wait_for_user_approval(context.signal)

    if not approved:
        return PermissionResultDeny(message="Rejected by user.")

    return PermissionResultAllow(updated_input=input_data)


QoderAgentOptions(
    cwd="/path/to/project",
    permission_mode="default",
    can_use_tool=can_use_tool,
)
```

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

```python theme={null}
CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext],
    Awaitable[PermissionResult],
]
```

主要フィールドの説明：

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

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

```python theme={null}
return PermissionResultAllow(updated_input=input_data)
```

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

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

```python theme={null}
return PermissionResultDeny(
    message="This command is not allowed in the current workspace."
)
```

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

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

```python theme={null}
from qoder_agent_sdk import SDKPermissionDeniedMessage


if isinstance(message, SDKPermissionDeniedMessage):
    print(
        message.tool_name,
        message.tool_use_id,
        message.message,
        message.decision_reason,
        message.decision_reason_type,
    )
```

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

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

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

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

```python theme={null}
async def can_use_tool(
    tool_name: str,
    input_data: dict[str, Any],
    context: ToolPermissionContext,
):
    decision = await show_approval_dialog(
        tool_name=tool_name,
        suggestions=context.suggestions,
    )

    if decision == "always-allow-this-session":
        return PermissionResultAllow(
            updated_input=input_data,
            updated_permissions=context.suggestions,
        )

    if decision == "allow-once":
        return PermissionResultAllow(updated_input=input_data)

    return PermissionResultDeny(message="Rejected by user.")
```

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

```python theme={null}
from qoder_agent_sdk.types import PermissionRuleValue, PermissionUpdate


return PermissionResultAllow(
    updated_input=input_data,
    updated_permissions=[
        PermissionUpdate(
            type="addRules",
            behavior="allow",
            destination="session",
            rules=[PermissionRuleValue(tool_name="mcp__orders__read_order")],
        )
    ],
)
```

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

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

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

```python theme={null}
destination = "session"
```

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

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

## 追加ディレクトリへのアクセス：add\_dirs

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

```python theme={null}
QoderAgentOptions(
    cwd="/repo/app",
    add_dirs=["/repo/packages/shared"],
)
```

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

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

```python theme={null}
return PermissionResultAllow(
    updated_input=input_data,
    updated_permissions=[
        PermissionUpdate(
            type="addDirectories",
            destination="session",
            directories=["/repo/packages/shared"],
        )
    ],
)
```

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

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

## 外部承認ツール：permission\_prompt\_tool\_name

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

```python theme={null}
QoderAgentOptions(
    permission_prompt_tool_name="mcp__permission_server__approve",
)
```

使用時の注意点は 3 つあります：

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

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

```python theme={null}
{
    "tool_name": "mcp__orders__read_order",
    "input": {"order_id": "1001"},
    "tool_use_id": "toolu_...",
}
```

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

```python theme={null}
{
    "behavior": "allow",
    "updatedInput": {"order_id": "1001"},
    "updatedPermissions": [],
    "toolUseID": "toolu_...",
}

{
    "behavior": "deny",
    "message": "Denied by policy.",
    "interrupt": True,
    "toolUseID": "toolu_...",
}
```

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

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

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

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

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

```python theme={null}
QoderAgentOptions(
    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-による高度なインターセプトと監査" />

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

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

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

```python theme={null}
from qoder_agent_sdk import HookMatcher


async def pre_tool_use_hook(inp, tool_use_id, context):
    return {
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason": "Shell commands are disabled here.",
        }
    }


QoderAgentOptions(
    cwd="/path/to/project",
    hooks={
        "PreToolUse": [
            HookMatcher(matcher="Bash", hooks=[pre_tool_use_hook]),
        ],
    },
)
```

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

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

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

```python theme={null}
{
    "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "deny",
        "permissionDecisionReason": "...",
        "updatedInput": {},
    }
}
```

その中で `permissionDecision` は `"allow"`、`"deny"`、`"ask"`、`"defer"` を取り得ます。

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

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

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

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

<div id="mcptoolpolicy" />

## MCP Tool Policy

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

```python theme={null}
import os


QoderAgentOptions(
    mcp_servers={
        "repo_tools": {
            "type": "http",
            "url": os.environ["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 ツール呼び出しにマッピングします。
