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 を接続します。
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、承認システム、リスク管理サービスに委ねることができます。
クイックスタート:ホストアプリケーションによるツール呼び出し承認
ツール呼び出しを独自の承認ロジックに接続する場合は、canUseTool を使用します。SDK はランタイムでツール名、ツール入力パラメータ、および表示可能な承認情報をコールバックに渡します。コールバックが allow を返すとツールは実行を続け、deny を返すとツールは拒否されます。
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 を返すことで、ランタイムが承認結果と今回のツール呼び出しを正確に対応付けることができます。
デフォルトポリシーの制御:permissionMode
permissionMode はセッションのデフォルト権限ポリシーを決定します。「今回のセッション全体がどのモードか」を表現するのに適しています(例:先に計画、編集の自動受け入れ、確認なしの直接拒否、制御環境での権限チェックのスキップ)。
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 オブジェクトを使用できます:
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 を渡すことを要求し、呼び出し側が誤って通常のセッションを権限チェックスキップのセッションに変えてしまうのを防ぎます。
query({
prompt: 'Run the trusted local maintenance task.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
permissionMode: 'bypassPermissions',
allowDangerouslySkipPermissions: true,
},
});
ツール制御は「モデルがどのツールを参照でき、どのツールがデフォルトで許可または禁止か」という問題に答えます。この3つのフィールドは一緒に使用されることが多いですが、意味が異なります。
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 です。
query({
prompt: 'Read order 1001.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: server },
allowedTools: ['mcp__orders__read_order'],
},
});
canUseTool はホストアプリケーションが承認に参加する必要があるシーンに適しています。例えば、権限リクエストを独自の UI に表示してユーザーに「1回許可」「このセッションで常に許可」「拒否」を選択させたい場合や、企業のリスク管理サービスを呼び出してコマンドが実行可能かを判断したい場合です。
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 のシグネチャは以下の通りです:
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 を返すとツールの実行が継続されます:
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
updatedInput はツールが最終的に受け取るパラメータです。そのまま返すこともできますし、承認通過後にパラメータを変更することもできます。例えば、クエリにテナント ID を追加したり、パスを安全なディレクトリに書き換えたり、許可されないフィールドを削除したりできます。
deny を返すとツールは拒否されます:
return {
behavior: 'deny',
message: 'This command is not allowed in the current workspace.',
toolUseID: options.toolUseID,
};
deny.message は必須で、拒否理由の一部となり、モデル、ログ、またはホストアプリケーションに表示されます。SDK が CLI からの承認リクエストを受け取ったが canUseTool が設定されていない場合、エラーを返し、デフォルトでは許可しません。
権限システムがツール呼び出しを直接拒否した場合、メッセージストリームに構造化された権限拒否メッセージが表示されることがあります:
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 状態を更新したり、監査ログを書き込んだりできます。
セッション内での権限更新:PermissionUpdate
PermissionUpdate は1回の承認後に現在のセッション内の権限ルールを更新するために使用します。最も一般的なシーンは、ユーザーが承認 UI で「このセッションで常に許可」を選択する場合です。この場合、ランタイムが提供する suggestions をそのまま返すことも、明示的なルールを自分で構築することもできます。
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,
};
}
ルールを直接構築することもできます:
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 | ディレクトリ承認の削除 |
動的権限更新は現在のセッションに書き込むことを推奨します:
session は現在の query セッションの後続の権限チェックにのみ影響します。ローカル、プロジェクト、またはユーザーレベルの設定に永続化する必要がある場合は、単一のツール承認コールバック内の動的更新に依存するのではなく、settings 管理フローを優先的に使用してください。
追加ディレクトリへのアクセス:additionalDirectories
デフォルトでは、セッションは cwd を主要な作業ディレクトリとします。モデルが cwd 外のディレクトリを読み取りまたは変更する必要がある場合は、明示的に additionalDirectories を渡す必要があります。
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 を通じてディレクトリ承認を調整することもできます:
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
updatedPermissions: [
{
type: 'addDirectories',
destination: 'session',
directories: ['/repo/packages/shared'],
},
],
};
ディレクトリ承認は権限境界の一部です。広範囲のディレクトリを汎用デフォルト値として additionalDirectories に追加しないでください。より安全なアプローチは、タスクの必要に応じて最小限のディレクトリセットを追加することです。
permissionPromptToolName は権限リクエストを実行環境の permission prompt tool に委任するために使用します。SDK ホスト内で canUseTool を実装する代わりに使用します。既存の外部承認ツール、リモート実行環境、または統一権限ゲートウェイがあるシーンに適しています。
query({
prompt: 'Run the task.',
options: {
auth: accessTokenFromEnv(),
permissionPromptToolName: 'mcp__permission_server__approve',
},
});
使用時の注意点:
permissionPromptToolName は現在の実行環境が認識できる prompt tool 名である必要があります。
permissionPromptToolName と canUseTool は排他的であり、同時に渡すことはできません。
- SDK ホスト自体が承認を決定する場合は、
canUseTool を優先的に使用してください。
permission prompt tool は以下の入力を受け取ります:
type PermissionPromptToolInput = {
tool_name: string;
input: Record<string, unknown>;
tool_use_id?: string;
};
権限結果を返す必要があります:
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 は拒否後に現在のエージェントフローを中断することを示します。
settings による権限ルールの提供
settings はセッション開始前に静的権限設定を提供するのに適しています。canUseTool よりも「このプロジェクトでデフォルトで何を許可し、何を拒否し、追加ディレクトリは何か」を表現するのに適しています。
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 のようなモードは、明確に信頼された環境でのみ使用すべきです。
hooks による高度なインターセプトと監査
hooks は SDK hooks 体系に既に接続しており、ツールのライフサイクルでより細かな制御を行いたい場合に適しています。canUseTool と比較して、hooks は横断的なロジック(監査、アラート、統一インターセプト、拒否理由の記録など)により適しています。
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 は以下を返すことができます:
{
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'allow' | 'deny' | 'ask' | 'defer',
permissionDecisionReason?: string,
updatedInput?: Record<string, unknown>,
},
}
PermissionRequest はツール承認に類似した権限結果を返すことができます:
{
hookSpecificOutput: {
hookEventName: 'PermissionRequest',
decision: {
behavior: 'deny',
message: 'Denied by policy.',
},
},
}
PermissionDenied は通常、結果を観察するために使用し、ツールの通過は担当しません。入力には拒否されたツール名、ツール入力パラメータ、ツール呼び出し ID、拒否理由が含まれます。
権限ポリシーが特定の MCP server に自然に属する場合、MCP server config にツールレベルの permission policy を直接宣言することもできます。これによりポリシーが MCP server 設定に付随し、グローバルな allowedTools や disallowedTools に分散することを防ぎます。
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 ツール呼び出しにマッピングします。