機能エージェント

権限

エージェントが使えるツール、人による承認、エージェントを管理する人と認証情報の紐付け

エージェントの権限は 3 つの層からなる。プロファイルが定めるツールと権限モード、人が答える権限リクエスト、そしてエージェントを管理し認証情報の名前を紐付ける人である。

ツール: プロファイルが決める

セッションは、プロファイルの tools に含まれるツールだけを使う。プロファイルがブロックした組み込みツール (deny) は tools に入らない。それ以外のツールは権限リクエストなしで拒否され、モデルはエラーの tool_result を受け取る。何をブロックするかはプロファイルを選ぶにある。次のスクリプトは、ローカルプロファイルがブロックした WebFetch を呼び出す (ローカルプロファイルの deny は ["NotebookEdit","WebFetch","WebSearch"] である)。

created=$(curl -sS "$API/v1/sessions" \
  -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d "$(jq -nc --arg m 'GATE-SPEC {"id":"outside","steps":[{"tool":"WebFetch","input":{"url":"https://example.com","prompt":"summarize"}}],"final":"done"}' \
    '{profile_id: "claude-coding-local", repository_id: "sample-app", message: $m}')")
SID=$(echo "$created" | jq -r .session_id)
until [ "$(curl -sS "$API/v1/sessions/$SID/turns/1" -H "Authorization: Bearer $KEY" | jq -r .status)" = completed ]; do
  sleep 2
done
curl -sSN --max-time 5 "$API/v1/sessions/$SID/events" -H "Authorization: Bearer $KEY" \
  | awk '/^event: tool_result/ { getline; sub(/^data: /, ""); print }' \
  | jq -c '.data | {is_error, content}' || true
curl: (28) Operation timed out after 5006 milliseconds with 4482 bytes received
{"is_error":true,"content":"<tool_use_error>Error: No such tool available: WebFetch. WebFetch is disabled for this session, in subagents as well as here.</tool_use_error>"}

curl: (28) は --max-time がストリームを切断したものである。

リリースから作ったセッションはさらに狭く、そのリリースに固定されたツールだけを使う。カードの capabilities.tools (null ならリリース作成時にプロファイルがブロックしていないツールすべて) から forbidden を除いた一覧で、リリースのレスポンスの effective_tools.tools がその一覧である。カードに Read だけを書くと、セッションは Read だけを使い、ほかの組み込みツールは上と同じく拒否される。リリースなしで作ったセッションは、プロファイルのツールをすべて使う。

ブロックする場所は二つあり、範囲が違う。

プロファイルの denyカードの capabilities.forbidden
誰が決めるか運用担当者のプロファイルは owner、ワークスペースのプロファイルは owner・adminエージェント管理者
及ぶ範囲そのプロファイルのバージョンで動くすべてのセッションとリリースそのエージェントのリリースから作ったセッション
受け付ける名前組み込みツールの名前だけツールの名前
変更が効くのは新しいプロファイルのバージョン。そのバージョンで作ったリリースとセッションから新しいリリースから

カードはプロファイルがブロックしたツールを開けない。プロファイルがブロックしたツールをカードの capabilities.tools に書くと、リリースを作るときに拒否される。

以前は、カードの tools・forbidden はリリースに固定されるだけで実行には適用されなかった。現在は、それ以前に作ったリリースですでに進行中のセッションも、リリースのツールに絞られる。セッションの実行環境が再び起動したとき (最後のターンが終わってから入力なしで 30 分経ち、実行環境が停止したあとの次のメッセージ、または一時停止からの再開) に適用される。カードの tool_policy に書いた組み込みツールの値 (allow・ask・deny) はリリースに固定されるが、まだ実行には適用されない。実行前に確認するかどうかは、下の権限モードが決める。

カードの tool_policy では、組み込みツールの既定値は allow、MCP ツールの既定値は ask である。組み込みツールを実行前に人に確認させるのはこの値ではなく権限モードである。組み込みツールをまったく使わせないには、プロファイルの deny かカードの forbidden でブロックする。

権限モード

プロファイルの permission_mode が、ツールを実行する前に人へ尋ねるかどうかを決める。セッション詳細の runtime.permission_mode に表示される。

モード動作
defaultセッションのワークスペース内でのファイルの書き込み・編集、git と gh のすべてのコマンド、sed、作業スペース内の mkdir、bun・npm・pnpm・yarn の test と run は、尋ねずに実行する。&&・;・| でつないだコマンドは、すべての部分がこの範囲のときだけ通り、1 つでも外にあればコマンド全体が権限リクエストになる。ワークスペース外への書き込み (symlink と .. を解決したパスで判定)、秘密値・.git・.claude のパス、sed -i、ファイルを書いたりプログラムを実行したりする git --output・--ext-diff、別のリポジトリを指す git -C、git add -f、gh auth、curl などそれ以外のネットワークツールは、実行前に権限リクエストを作成する。git と gh はオプションに関係なく尋ねない。害を止めるのは権限リクエストではなく、ワークスペースのコンテナ分離、egress authorizer (push 先・トークン範囲)、GitHub のブランチ保護である。状態を変えない読み取り (ls、cat、grep、find など) は、ワークスペース内ならエンジン自身の規則で尋ねずに実行される。ワークスペース外のパスと find -exec・-delete はエンジンが尋ね、秘密値のファイル名 (.env、鍵、.git/config) が cat・head・tail・grep・rg の行にあるときはこの一覧が尋ねる。隠しファイルまで探す rg -u や --hidden も尋ねる。名前だけを見るため、cat .e* や grep -r は通ってしまう。ローカルプロファイルのモードである
acceptEdits, dontAskClaude Code の同名のモードで動き、default と同じワークスペースの事前許可と確認リストが加わる。このリストにある秘密値・.git・.claude のパスは acceptEdits でも尋ねる
planClaude Code の同名のモードで動く。事前許可はない
auto人の代わりにモデルの分類器が呼び出しごとに許可・拒否を決める。分類器を使えないときは拒否する。インストール設定なしで使える。例外として、組み込みの GitHub ツールのうち push、PR の書き込み、リポジトリの読み取りは分類器を通らず、サーバーが判定する(push 承認、release のツール一覧、セッションの grant)。レビュー送信と workflow は分類器を通る。プラットフォームは分類器に行動単位のルールを加える。下の許可のうち push・PR・リポジトリ読み取りは、この例外を受けられない古い worker でのみ分類器が見るルールである。許可: セッションの作業領域での commit と、プラットフォームの push フローによるセッション自身のリポジトリのセッション専用の作業ブランチ(agent/<session-id>)への push、そのブランチから PR を開くことと、このセッションが開いた PR のタイトル・本文の修正・コメント・クローズ・再オープン、許可されたリポジトリの一覧表示と読み取り用の追加。この許可に入らないもの: 既定・保護ブランチやプラットフォームが作っていないブランチへの push、force push、PR のマージ・承認、レビュー送信、このセッションが開いていない PR の修正・コメント・クローズ、ほかのリポジトリ(セッションに付けたものを含む)への push、秘密値。リポジトリ設定・ブランチ保護・webhook・deploy key・Actions secret の変更、GitHub 上のブランチ・リポジトリの削除、PR のマージはどの経路でも拒否寄りに扱う
bypassPermissions判定なしにすべての呼び出しを実行する。このモードのプロファイルは API に PLATFORM_ALLOW_UNATTENDED_PERMISSIONS=true がなければ除外され、ワークスペースプロファイルでは owner・admin だけが選べる

モードはカタログにのみ存在し、セッションのリクエストで変更することはできない。コンソールで新しく作るプロファイルは、ベースが許せば auto から始まる。すでに default で作ったプロファイルは自動では移さない。push と PR のツールは、最新の worker では plan を除くモードでエンジンが尋ねない(plan は従来どおりエンジンが尋ねる)。Bash などエンジンのツールまでエージェントが尋ねないようにするには、auto のバージョンを作り、エージェントの新しい release がそれを使うようにする。運用担当者のプロファイルなら、owner が詳細の新しいバージョンで権限モードを auto にして保存する。ワークスペースプロファイルはベースより広いモードを選べないので、ベースが auto を許すなら編集で auto を保存し、ベースが default なら auto を許すベース(上の auto の運用担当者のプロファイルのバージョンなど)の上に新しいワークスペースプロファイルを作る。すでに動いているセッションは元のモードのまま動く。push 承認はモードとは別である。auto モードでも、push 承認がオンか、付けたリポジトリの push ポリシーが ask なら、どのリポジトリへの push でも、push のたびに人に尋ねる。エージェントの GitHub タブを初めて保存するときは push 承認がオフの状態から始まるが、GitHub 設定のない release(この設定より前に作った release など)はオンとして読む。承認なしで自動 push するには、GitHub タブで push 前の人の承認 がオフになっていることを確かめて保存する。オフにしても、承認なしで進むのは、付けたリポジトリの push ポリシー(allow・ask・deny)も allow のときだけである。ポリシーが deny なら push 自体がブロックされ、それ以外では、どのリポジトリへの push も、このスイッチとそのポリシーのうち厳しいほうに従う。人の承認を受けるには、スイッチをオンにするか、ポリシーを ask にする。

承認: 人だけが行う

権限リクエストと質問に答えるには sessions:approve scope が必要である。worker 内のエージェントが持つ認証情報は /v1 で 401 になるため、自分で承認することはできない。エージェントキーも sessions:approve を持てるが、そのキーで開始したセッションのリクエストは承認できない。答え方は 承認待ちと再開 にある。

セッションを見られるからといって、そのセッションのリクエストに答えられるわけではない。権限リクエストと質問に答え、push・PR を承認するのは次の人だけである。

  • セッションを作った人(API キーが作ったセッションならそのキー)
  • そのセッションのエージェントの管理者
  • ワークスペースの owner・admin

共有でセッションを見ているだけの人が答えると 403 FORBIDDEN(reason_code: role)になり、リクエストは開いたまま残ってセッションは needs_input のままである。見られないセッションはこれまでどおり 404 である。GET /v1/sessions/{id}/pending-requests の answerable が、呼び出した人が答えられるかを示す。コンソールは false のとき、許可・拒否を理由とともに無効にして表示する。

エージェント管理者

エージェントを作成した人が、そのエージェントの管理者になる。管理者は member であっても、そのエージェントのカード修正、リリース、有効化、認証情報の紐付け、管理者の指定、エージェントキーの発行を行える。人やチームを管理者として追加でき、チームの場合はそのチームのメンバー全員が管理者になる。チームを新しく追加できるのは、チームを管理する owner・admin だけである。member のエージェント管理者はチームを追加できないが、追加済みのチームを外すことと、人の追加・削除はできる。

エージェントには常に担当チームが一つあり、変えることはできても空にはできない。担当チームのチーム管理者(lead)はそのエージェントの管理者で、メンバー(member)は管理しない。owner・admin でなければ、自分が所属するチームだけを担当チームに選べる。担当チームに決まったチームは、そのエージェントをアーカイブするか担当チームを移すまで削除できない。

チームのロールはコンソールのチーム画面で見る。メンバー表の チームのロール 列が チーム管理者(lead)と メンバー(member)を分け、所属チーム の一覧にも自分のロールが付く。owner・admin はメンバーの行の ロールを変更 でロールを選んで 保存 する(PATCH /v1/teams/{team_id}/members/{user_id} {"role"})。担当チームになっているチームを削除しようとすると、コンソールは削除せず、そのチームが担当チームのエージェントの名前とリンクを示す(409 TEAM_MANAGES_AGENTS)。先に各エージェントの担当チームを変える。

エージェントを見られる範囲は次のとおり。

誰が情報(名前・slug・説明・担当チーム・状態・有効なリリース)設定(カード・リリース・管理者・認証情報の紐付け・GitHub・Slack)の閲覧設定の変更
owner・admin読める読める変えられる
エージェント管理者(担当チームの lead を含む)読める読める変えられる
担当チームの member読める読めるできない(403)
それ以外の member読める(下の設定が none なら見えない)できない(403、設定が none なら 404)できない(403)

以前は、member は自分が管理しないエージェントを一覧で見られず、担当チームの member も設定を読めなかった。今はすべての member が GET /v1/agents・GET /v1/agents/counts でワークスペースのエージェントを探せ、担当チームの member は設定を読める。include=summary の要約(管理者・認証情報の紐付け)は、設定を読めるエージェントにだけ付く。エージェントの設定を変えた receipt も、設定を読める人だけが読める。

エージェントの外の member ができること

owner・admin、エージェント管理者、担当チームのメンバーをそのエージェントの内側と呼び、それ以外の member を外側と呼ぶ。外側の member がエージェントで何をできるかは、ワークスペースの設定二つが決める。変えられるのは owner・admin だけで(PATCH /v1/workspaces/{id}/agent-access)、変えるたびに receipt が残る。今の値は GET /v1/auth/me の workspace.settings にある。

設定値外側の member には
agent_outsider_accessuse(既定値)情報を読み、セッションを開始できる
view情報だけ読める。セッション開始は 403 FORBIDDEN(reason_code: role)
noneエージェントが一覧になく、読むと 404。セッション開始は 403
agent_outsider_session_visibilitymanaging_team(既定値)エージェントの workspace 共有セッションが、担当チーム外のメンバーには一覧・件数・詳細・イベント・使用量の最近の一覧に出ない
workspaceそのセッションもすべての member が見る
  • agent_outsider_access と agent_outsider_session_visibility はすべてのエージェントに適用される。エージェントには常に担当チームがある。担当チームが必須になる前にチームがなかったエージェントは、メンバーのいない保管チーム(名前を変えても、サーバーは保管チームとして認識する)が引き受けた。これらのエージェントの workspace セッションは、適切なチームに移すまで以前と同じくすべてのメンバーに見える。
  • 外側の member でも、自分が開始したセッションと、自分や自分のチームを指定して共有された(people・team)セッションは引き続き見える。
  • どちらの設定も次のリクエストから、作成済みのセッションにも適用される。開いているイベントストリームは次の確認で切れる。担当チームを変えたときや、メンバーがチームから外れたときも同じである。
  • 使用量の合計(セッション数・費用・成果数)は変わらず、最近の成果一覧から見られないセッションの行だけが抜ける。
  • 共有範囲が workspace でも外側の member に見えないセッションは、GET /v1/sessions/{id}/share の audience_limited が true になる。
curl -sS -X PATCH "$API/v1/workspaces/$WID/agent-access" "${WEB[@]}" \
  -d '{"agent_outsider_access": "view"}' | jq -c '{agent_outsider_access, agent_outsider_session_visibility, changed: (.receipt_id != null)}'
{"agent_outsider_access":"view","agent_outsider_session_visibility":"managing_team","changed":true}

WID は GET /v1/auth/me の workspace.id である。

コンソールでは ワークスペース設定 の エージェントへのアクセス で変える。担当チーム外のメンバーのエージェントへのアクセス は 表示と実行(use)・表示のみ(view)・非表示(none)、ワークスペース公開のセッション は 担当チーム内のみ(managing_team)・すべてのメンバー(workspace)である。変えた値だけを送り、保存すると画面が GET /v1/auth/me を読み直す。owner・admin でないメンバーには、選択肢なしで今の値だけが表示される。

以前は workspace 共有セッションをすべての member が見ていた。今は既定値が managing_team なので、エージェントのセッションはすぐに内側だけが見る(保管チームに残っているエージェントは例外である)。以前のように見せるには agent_outsider_session_visibility を workspace に変える。

作成の AID と WEB を引き続き使う。

curl -sS "$API/v1/agents/$AID/admins" "${WEB[@]}" | jq '{users: [.users[].email], teams}'
{
  "users": [
    "owner@example.test"
  ],
  "teams": []
}
リクエスト内容
POST /v1/agents/{id}/admins {"user_id"} または {"team_id"}管理者の指定
DELETE /v1/agents/{id}/admins/users/{user_id}, …/teams/{team_id}解除
PUT /v1/agents/{id}/managing-team {"team_id"}担当チームの指定・変更
GET /v1/administered-agents自分が管理しているエージェント

認証情報の紐付け

カードには、使う認証情報の名前だけを capabilities.credential_refs に書く。値は Werft の外 (secret store、remote MCP server の接続) にある。その名前をこのエージェントが使ってよいという紐付けは、管理者が別途作成する。カードに書かれた名前のうち紐付けられていないものがあると、有効化は 409 CREDENTIAL_UNBOUND になる。

curl -sS "$API/v1/agents/$AID/credential-bindings" "${WEB[@]}" -d '{"credential_ref": "notion-token"}' \
  | jq '{credential_ref: .binding.credential_ref, created}'
curl -sS "$API/v1/agents/$AID/credential-bindings" "${WEB[@]}" | jq -c '[.items[].credential_ref]'
{
  "credential_ref": "notion-token",
  "created": true
}
["notion-token"]

解除 (DELETE /v1/agents/{id}/credential-bindings/{binding_id}) は、動作中のセッションを止めない。次のセッションから遮断される。すぐに遮断するには、外部サービスでその認証情報を失効させる。

次のステップ

このページ