「OS」は看板ではなかった

2026年8月4日、Cloudflareが Cloudflare OS を発表し、翌日にはソースコードがApache-2.0cloudflare/cloudflare-os として公開されました。 社内では2026年5月から全社に展開され、エンジニアリングから営業まで数千人が毎日使っているとされています。

名前を見て「またAI系プロダクトが大げさな名前を付けたな」と思うのが自然な反応です。私もそう思いました。 ただ README を読み進めると、この命名は少なくとも技術構造のレベルでは筋が通っています。 そして中身を追うと、いま我々がエージェントを組むときに何も考えずに置いている前提が 2つ、明確に否定されていることがわかります。

本記事はプロダクト紹介ではなく、その2つの前提の壊し方を読むことを目的にします。 自分でエージェント基盤を設計する人にとって、そこがいちばん持ち帰れる部分だからです。

公開までの経緯

リポジトリ作成

cloudflare/cloudflare-os が作られる。v1の反省を踏まえた新基盤への書き直し(v2)が進行。

社内全社展開

Cloudflareの全職種の従業員に開放。「Cloudflare OS is how we run Cloudflare」(Matthew Prince CEO)。

発表

プレスリリースと公式ブログで発表。マネージド提供とダッシュボード統合は Coming soon。

ソース公開

Apache-2.0 でGitHubに公開。デプロイ用スターター cloudflare-os-starter も同時公開。

技術構造としてのOSアナロジー

README には対応表がそのまま載っています。これが「OS」と呼ぶ根拠です。

一般的なOSCloudflare OS役割
kernelpackages/workshop-backendユーザーとプログラム/デバイスを接続し、サンドボックスとアクセス制御を担う
device driverspackages/gatekeeper-*外部サービスへの接続を仲介する
shellpackages/workshop-frontendユーザーが操作する面
processesgadgets実行中のアプリ実例
executablesblueprints配布可能なアプリのコード
ACLsshared permissions共有権限
(該当なし)agentsAIエージェント

注目したいのは最後の行です。従来のOSにはエージェントに相当する概念がない—— README はこれを「伝統的OSに欠けている機能」だと言い切ります。 エージェントはユーザーとして扱えない。人間のユーザーに対して説明責任を負いながら、 同時にそのユーザーより狭い権限を持つ必要がある。 そしてエージェントはコード片を書いて即時実行することで仕事をするので、 そこに適した security model は ACL ではなく capability-based security だ、という主張です。

実装基盤は Cloudflare Workers です。ワークスペースは Durable ObjectGadget は Dynamic Worker の Facet として動き、Gatekeeper もワークスペースに facet を差し込みます。 Dynamic Workers や Facets は Cloudflare OS を実現するためにランタイムへ追加された機能だと明言されていて、 つまりこのリポジトリは Workers を作った本人たちが考える Workers の使い方のリファレンス実装でもあります。 Workers ランタイム workerd 自体がOSSなので、自前サーバ上での運用も原理的には可能です(ドキュメント・ツールは Coming soon)。

壊された前提1: 「アプリは1つを全員で共有する」

Cloudflare OS でスライドを作ると、クラウド上のスライドSaaSを呼び出すのではありません。 システムはあなた専用のスライドアプリのプライベートインスタンスを生成します。これが Gadget です。 他人のスライドとは別のサンドボックスで動きます。

ここから2つの帰結が出ます。README の言い方をそのまま借りると:

  1. スライドアプリのバグであなたのスライドが漏れることが原理的に起こらない。サンドボックスがあなたのインスタンスへのアクセスをすべて統制しているため
  2. コードを自由に書き換えてよい。機能が足りなければエージェントに追加させればよく、1のおかげでそれが安全にできる

この2つは順序が重要です。「AIでアプリを書き換えられます」は今どこでも言われますが、書き換えて壊れても他人に波及しないという隔離が先にないと、非技術者に開放できません。 Gadget の設計は「ユーザーに書き換えさせる」ための前提条件として隔離を置いています。

サンドボックスの中身

「サンドボックス」と言っても実態はかなり具体的です。Gadget はデフォルトでインターネットに一切出られません

graph TB
  subgraph BROWSER["ブラウザ"]
    PARENT["親フレーム<br/>workshop-frontend"]
    IFRAME["サンドボックス iframe<br/>Gadget クライアント<br/>CSP + iframe sandbox で<br/>外部通信を遮断"]
  end
  subgraph EDGE["Cloudflare Workers"]
    SERVER["Dynamic Worker Facet<br/>Gadget サーバ<br/>インターネットアクセス無効"]
    GK["Gatekeeper Worker"]
  end
  EXT["外部サービス<br/>GitHub / Google / Slack ..."]
  IFRAME <-->|"postMessage 上の<br/>Cap'n Web RPC のみ"| PARENT
  PARENT <--> SERVER
  SERVER -->|"明示的に導入された<br/>Workers Binding だけ"| GK
  GK --> EXT
  SERVER -.->|"直接の外向き通信は不可"| EXT
クライアントもサーバも「デフォルト外に出られない」側から設計されている

サーバ側は外向き通信を無効化した Dynamic Worker で動き、明示的に指定した外部リソースへの Workers Binding 経由でしか通信できません。 クライアント側は sandbox 化された iframe で、親フレームへの postMessage 上に張られた Cap'n Web RPC セッション以外の経路を持ちません。 「許可したものを塞ぐ」ではなく「何も通らない状態から穴を1つずつ開ける」向きになっています。

配布は Blueprint、つまり「コードを配る」

作った Gadget を他人にも使わせたいときは、Gadget 自体を共有するのではなく Blueprint を共有します。 Blueprint はコードのスナップショットで、受け取った人は自分のコピーを作る

Blueprint が持っていくもの/持っていかないものが明確に分かれているのが実務的に効きます。

項目Blueprintに含まれる?
ソースコード(コミット済みスナップショット)含まれる
必要な binding の「形」(gatekeeper種別・モデル・URLパターン)含まれる
メタデータ(タイトル・説明・作者・バージョン)含まれる
SQLite ストレージの中身含まれない
AIチャット履歴・編集履歴含まれない
認証情報・生きたコネクション含まれない

つまり配布されるのは「何に繋ぐ必要があるか」という要求仕様と、コードだけ。 受け取った側は自分のアカウントを自分で繋ぎます。 これは SaaS の伝統(作者がサーバをホストし、全員がそこに繋ぐ)ではなく、 モバイルアプリやPCアプリの配布モデルに近い。 個人開発者がオンラインサービスを維持し続ける負担がなくなり、 ユーザーは機能要望を出す代わりに自分で直せる、という主張です。

壊された前提2: 「承認はエージェントを止めて求める」

ここが本記事でいちばん紹介したい部分です。

Gatekeeper は README の表現では「supercharged MCP servers」。 エージェントや Gadget を外部リソースに導入(introduce)すると、 そのアクセスを管理する Gatekeeper が作られます。サービスごとに実装された Worker で、次を担います。

  • サービスのネイティブAPIをラップし、きれいな Cap'n Web API を提供する
  • OAuth などの認可を処理する
  • ユーザーが意図したその特定のリソースだけに狭くアクセスを絞る
  • Gadget/エージェントが行ったすべてのアクションをログに残す
  • 副作用のあるアクションについて、人間に承認・却下の機会を与える(human in the loop)

同期的な承認が破綻している、という診断

最後の項目の実装が独特です。まず問題認識を確認しておきます。

従来の human-in-the-loop は同期です。エージェントが何かしたくなったら止まって承認を待つ。 タスクを投げてコーヒーを取りに行き、戻ってきたら1ステップ目の承認待ちで固まっていて何も進んでいない。 だから人は諦めて auto-approve や --dangerously-skip-permissions に手を伸ばす—— README はこれを「obviously, unsafe」と書きます。 身に覚えのある話だと思います。ここで重要なのは、これを人間の規律の問題ではなく設計の問題として扱っている点です。

解: 結果を模擬して先へ進ませる

Gatekeeper のやり方はこうです。承認が必要なアクションが来たら、その結果をローカルで模擬(simulate)し、エージェントには「完了した」と伝えて先に進ませる。 エージェントが結果を読み戻そうとしたら、模擬した結果を返す。 エージェントが一連の作業を終えた後、ユーザーはまとめて、あるいは1件ずつ、都合のよいタイミングで承認・却下します。

sequenceDiagram
  participant U as 👤 ユーザー
  participant A as エージェント / Gadget
  participant G as Gatekeeper
  participant S as 外部サービス
  U->>A: タスクを依頼(そして離席)
  A->>G: 副作用のあるアクション 1
  G->>G: 結果をローカルで模擬<br/>キューに積む
  G-->>A: 「完了しました」(模擬)
  A->>G: アクション1の結果を読み戻し
  G-->>A: 模擬結果を返す
  A->>G: 副作用のあるアクション 2
  G->>G: 同じく模擬してキューへ
  G-->>A: 「完了しました」(模擬)
  A-->>U: タスク完了(実世界にはまだ何も起きていない)
  U->>G: 戻ってきてキューを確認
  U->>G: 一括承認 / 個別却下
  G->>S: 承認された分だけ実際に実行
エージェントの進行と人間の承認を時間軸から切り離す — 止めないための模擬

もちろん代償はあります。模擬結果と実結果が食い違う場合の扱い(承認時点で前提が崩れているケース)は 本質的に難しく、副作用の結果に強く依存する分岐を含むタスクでは模擬が破綻しえます。 ただ、読み取り主体のタスクでは代償がほぼゼロで、承認による停止だけが消える—— この非対称性が利いている設計だと読めます。

MCP の「常時接続」との違い

もう1つ、Gatekeeper には現行のエージェント環境への明確な批判が入っています。 Cloudflare OS ではエージェントも Gadget も、初期状態で何にもアクセスできません。 ワークスペースに外部アカウントを設定してあっても、それだけでは使えない。 リンクを貼る、UIで選ぶ、といった形でリソースごとに「導入」する必要があります (エージェント側から「これが必要だと思う」と導入を要求し、人間が許可/拒否することもできる)。

観点一般的なMCP構成Cloudflare OS の Gatekeeper
アクセス設定のタイミング事前にサーバを登録タスクごとにリソースを導入
既定のアクセス範囲登録済みサービス全体が全チャットで環境的に利用可能ゼロ。導入されたリソースのみ
権限の粒度サーバ/ツール単位特定リソース単位(このリポジトリ、このドキュメント)
監査ホスト実装に依存Gatekeeperが全アクションをログ
承認モデル同期的(止まって待つ)か auto-approve非同期(模擬して進み、後でまとめて承認)

「MCPサーバを事前に登録しておくと、全会話でそのアクセスが環境的(ambient)に手に入ってしまう」 という指摘は、率直に言って自分の .mcp.json を見返したくなる話です。 タスクに必要のない権限が常に卓上に乗っている状態を、capability ベースの導入で潰しにきています。

リポジトリには gatekeeper-github / -google / -slack /-notion / -linear / -confluence / -supabase /-scheduler / -email のほか、既存のMCPサーバを取り込むgatekeeper-mcp、さらには -spotify-homeassistant まで同梱されています。

共有すると権限が検査される — Observer

Gadget の共有には、もう一段面白い仕掛けがあります。「共有によって、相手が元々読めなかった情報を渡してしまわない」という不変条件を機械的に守る仕組みです。

Alice が共有した Gadget を Bob が開くとき、Bob は Gadget が使う各 Gatekeeper に対して自分自身の接続アカウントを指定しなければなりません。 各 Gatekeeper は、その Gadget がこれまでその Gatekeeper 経由で読んだすべての情報を Bob が直接読める権限を持っているかを検証します。持っていなければ Bob はアクセスを拒否されます。 検証を通った Bob は Gadget の observer として登録されます。

そして以後、Gadget が新たな読み取りを行おうとしたとき、登録済み observer のうち1人でも それを直接読む権限を持たない場合、その読み取り自体がブロックされます。 Alice は Bob のアクセスを剥がすことで解消できます。Bob の権限は開くたびに再チェックされます。

データ漏洩を「共有時のダイアログで注意喚起する」ではなく「読み取りの実行時点でブロックする」方に寄せているのが特徴です。

エージェントAPIが勝手に生えてくる理由

Cloudflare OS のエージェントは Code Mode 型です。 ツールを呼ぶのではなく、コード片を書いて即座に実行することでタスクを行います。 そしてコーディングエージェント専用というわけではなく、Gadget を作らずに直接作業させることもできます。

ここで Gadget のクライアント/サーバ間通信がCap'n Web RPC に強制されていることが効いてきます。README の言う win-win はこうです。

  1. Cap'n Web はボイラープレートが極端に少ない。サーバにメソッドを定義してクライアントからローカル呼び出しのように呼ぶだけなので、エージェントが扱いやすい
  2. その結果、サーバは必然的に理解しやすいAPIを外に露出していることになる。Code Mode のツール呼び出しはそのAPIをそのまま叩ける

だから「AIにアプリを作らせた後、そのアプリの中でAIと協働する」ために MCPサーバを書く必要もエージェントループを実装する必要もない。最初から生えている。 同じ理屈でリアルタイム多人数共同編集も、各 Gadget が Durable Object に載っているため コーディングエージェントが頼まれずともデフォルトで実装してしまうとされています。

「制約を1つ強制すると副産物が2つ手に入る」タイプの設計で、RPC層の選択がエージェント親和性を決めるという視点は自分の設計にも転用できます。

手元で動かす

一番手軽なのはローカル実行です。pnpm を入れて、次だけ。

# リポジトリを取得して依存を入れる
git clone https://github.com/cloudflare/cloudflare-os.git
cd cloudflare-os

# スタック全体を wrangler + workerd でローカル起動
pnpm run-local
# -> http://localhost:8787

# フロント/バックを分けて開発する場合(別ターミナルで2つ)
pnpm dev-server
pnpm dev-client
# -> http://localhost:3000

データは .wrangler 配下に入ります。本番運用向けではありませんが、挙動を見るには十分です。 自分のCloudflareアカウントへ展開する場合は https://os.cloudflare.app/deploy のフローがあり、 Gatekeeper構成やコード変更を伴うより本格的なデプロイにはcloudflare/cloudflare-os-starter が用意されています。 モデルは Cloudflare AI Gateway 経由で選択でき、主要プロバイダとセルフホストモデルに対応します (GitHub / Google 連携を使うプロンプトを試すには、各Integrationの設定が別途必要です)。

自分の設計に持ち帰るなら

Cloudflare OS をそのまま導入する話とは別に、読んで転用できる判断が3つあります。

Cloudflare OS の判断転用できる問い
副作用を模擬して承認をクリティカルパスから外す自分のツール群は「発行」と「適用」に分けられないか。auto-approveに逃げているのは規律の問題か設計の問題か
アクセスは事前登録ではなくタスクごとの導入このタスクに不要な権限が、常時エージェントの手元に乗っていないか
RPC層をCap'n Webに強制してAPIを自動的にエージェント向けにするクライアント/サーバ境界の通信規約が、後からエージェントを載せる難易度を決めていないか
ユーザーごとに独立したアプリ実例(Gadget)「AIに直させる」を安全にするために、先に必要な隔離が用意できているか

Cloudflare OS の主張は「あなたの会社が Cloudflare OS を使う」ことではなく、「これをコピーして "Your Company OS" にしてほしい」です。 Apache-2.0 でフォーク前提に置かれているのは、その言葉に対して一貫しています。 Workers ランタイムの作者たちが書いた最新コードのリファレンスとして読むだけでも、十分に元が取れます。

参考リンク

理解度チェック

問題 0 / 50%
Q1

Cloudflare OS において、ユーザーごとに独立したサンドボックスで動く「あなた専用のアプリのプライベートインスタンス」を指す用語は何ですか?