RPCと聞くと、多くの人はスキーマ定義(.protoなど)を書き、コード生成し、型を合わせて…という手間を思い浮かべる。Cap’n Webcloudflare/capnweb)は、その前提をひっくり返す。スキーマもコード生成もほぼ要らず、関数やオブジェクトをそのまま参照で渡し依存する複数の呼び出しを1往復に束ねる——JS/TSネイティブな object-capability RPC だ。READMEの見出しは「Cap’n Web: A JavaScript-native RPC system」。依存ゼロで minify+gzip 時 10kB未満、ブラウザからCloudflare Workers・Node.js・Bun・Denoまで動く。MIT・GitHubスター約3,900(2026-08-11時点)・最新 0.10.0。

本記事では、capnweb の正体・他RPCと違う3つの勘所・最小コード・トランスポート・Cloudflare Workersやエージェント基盤での役割までを、公式README/npm/公式ブログの一次情報だけで日本語に整理する。RPCという言葉に馴染みが薄い読者にも、「なぜ関数やオブジェクトを“参照で渡せる”ことが効くのか」「なぜ往復が1回で済むと嬉しいのか」が具体的に伝わることを目指す。

Cap'n Webの勘所。一般的なRPCが1呼び出し1往復なのに対し、Cap'n Webはpromiseを待たず次の引数に使い依存チェーンを1リクエストに束ね、関数やオブジェクトを参照(stub)で渡す
Cap'n Webの核心は promise pipelining と参照渡し(stub)。依存する呼び出しを1往復にまとめ、関数・オブジェクトはコピーでなく参照で渡す(出典: cloudflare/capnweb 公式README を基に作図)。
30秒でわかる Cap'n Web(2026年8月時点)
  • 正体:JS/TSネイティブのobject-capability RPC(npm: capnweb、MIT、0.10.0)。スキーマ・boilerplateがほぼ不要。
  • 何ができる双方向呼び出し関数・オブジェクトの参照渡し(stub)promise pipelining(依存する呼び出しを1往復に)。
  • 何を解決する:スキーマ定義とコード生成の重さ、そして「呼び出しのたびに往復が増える」レイテンシ。
  • 動く場所:HTTP/WebSocket/postMessage で、ブラウザ・Workers・Node.js・Bun・Deno。依存ゼロ・10kB未満。
  • 系譜:Cap'n Protoの精神的な兄弟(同じ作者)。ただしスキーマ無し・シリアライズは実質JSON

Cap’n Web単体は汎用のRPCライブラリだが、当サイトが扱う理由は明確だ。これはCloudflareのエッジとAIエージェント基盤を支える通信層で、AIエージェントフレームワーク比較2026|LangGraph・CrewAI・Dify等9種をStar数・実コードで検証で見たような「複数のプロセス・エージェントが会話する」構成の、まさに配管にあたる。

Cap’n Web(capnweb)とは——JS/TSネイティブのobject-capability RPC

READMEの冒頭はこう述べる。「Cap’n Web is a spiritual sibling to Cap’n Proto (and is created by the same author), but designed to play nice in the web stack.」——Cap’n Proto の精神的な兄弟(同じ作者による)だが、Webスタックで扱いやすく設計されている。そして「Like Cap’n Proto, it is an object-capability protocol. (“Cap’n” is short for “capabilities and.”)」と続く。名前の「Cap’n」は capabilities and の短縮で、オブジェクトケーパビリティ(能力=参照を渡し合う)モデルであることを示している。package.jsonのauthorは Kenton Varda だ。

Cap’n Proto との違いは2点、READMEが明言する。「Unlike Cap’n Proto, Cap’n Web has no schemas. In fact, it has almost no boilerplate whatsoever.」——スキーマが無く、boilerplateもほぼ無い。もう1点、「Also unlike Cap’n Proto, Cap’n Web’s underlying serialization is human-readable. In fact, it’s just JSON, with a little pre-/post-processing.」——シリアライズが人間可読で、実質は前後処理を足したJSON。スキーマファイルやコード生成のパイプラインを持ち込まずに、TypeScriptの型だけで通信できるのが最大の実務的メリットだ。

Cap'n Webの狙いは「速いシリアライザ」ではなく「Webスタックのまま、能力(参照)を渡し合えるRPC」。スキーマもコード生成も要らない。

シリアライズが「実質JSON」であることの実利も見逃せない。ワイヤ上を流れるデータが人間可読なので、デバッグ時にペイロードをそのまま目で読める。バイナリRPCのように専用ツールでデコードする必要がなく、ブラウザのネットワークタブやログにそのまま出せる。スキーマファイルという「もう1つの真実の源」を持たずに済むため、フロントとバックエンドで型定義がずれる典型的な事故も、TypeScriptの型を共有するだけで避けやすい。

サイズと対応環境も特筆に値する。「The whole thing compresses (minify+gzip) to under 10kB with no dependencies.」——依存ゼロで10kB未満。「It works in all major browsers, Cloudflare Workers, Node.js, Bun, Deno, and other modern JavaScript runtimes.」——主要ブラウザからCloudflare Workers、Node.js、Bun、Denoまで。フロントとエッジ、サーバーを同じRPCで貫けるのは、JSネイティブだからこそだ。バンドルサイズに敏感なブラウザ用途でも、10kB未満・依存ゼロなら気軽に載せられる。

読者の3つの問いへの答え
何ができる:スキーマ無しで双方向RPC。関数・オブジェクトを参照で渡し、依存呼び出しを1往復に束ねられる。
何を解決する:スキーマ定義/コード生成の手間と、呼び出しごとに増えるネットワーク往復のレイテンシ。
何を代替できる:JS/TS環境での自前fetchラッパーや重いRPCスタックを、10kB未満のライブラリに置き換えられる。

何が違う:双方向・参照渡し(stub)・promise pipelining

READMEは「Cap’n Web is more expressive than almost every other RPC system, because it implements an object-capability RPC model.(オブジェクトケーパビリティRPCモデルゆえに、ほぼ他のどのRPCより表現力が高い)」とし、その中身を列挙する。要点は3つだ。

双方向呼び出し:「The client can call the server, and the server can also call the client.」クライアント⇄サーバーのどちらからでも呼べる
関数・オブジェクトの参照渡し(stub):関数を渡すと受け手は「stub」を受け取り、それを呼ぶと元の場所へRPCが戻る。クラスが RpcTarget を継承すれば、そのインスタンスも参照で渡り、メソッド呼び出しは生成元へコールバックされる
promise pipelining:「When you start an RPC, you get back a promise. Instead of awaiting it, you can immediately use the promise in dependent RPCs, thus performing a chain of calls in a single network round trip.」——promiseを待たずに次の呼び出しの引数へ使い、依存する一連を1往復に束ねる

言葉だけだと掴みにくいので、依存する2つの呼び出し(ユーザーを取得→そのユーザーの投稿を取得)を例に、往復の数を図で比べる。

sequenceDiagram participant C as クライアント participant S as サーバー Note over C,S: 一般的なRPC(2往復) C->>S: getUser(id) S-->>C: user を返す C->>S: getPosts(user.id) S-->>C: posts を返す Note over C,S: Cap'n Web/promise pipelining(1往復) C->>S: getUser(id) の promise を
そのまま getPosts() の引数に束ねて送信 S-->>C: user と posts を1レスポンスで返す

このように、5つ目の特徴として「Supports capability-based security patterns.(ケーパビリティに基づくセキュリティパターン)」も挙げられている。参照(能力)を渡した相手だけがその操作を行えるため、「誰が何を呼べるか」を参照の受け渡しそのもので表現でき、権限設計が自然になる。

冒頭の図が示す通り、一般的なRPCでは「結果を取り寄せてから次を呼ぶ」ため往復が積み重なる。Cap’n Webは依存チェーンをまとめて送るので、ネットワークのラウンドトリップ回数という、レイテンシを実際に決める量を減らせる。しかもこれは「任意コードをネットワーク越しに送っている」わけではない——READMEは「Cap’n Web does NOT send arbitrary code over the wire!」と明記し、.map() などは記録・再生(record-replay)で実現する。「Every RPC promise has a special method .map() which can be used to remotely transform a value, without pulling it back locally.」——値をローカルに引き戻さずリモートで変換でき、これも1往復で済む。

capnwebのインストールと最小コード

導入は npm 一発だ(パッケージ名は capnweb)。

npm i capnweb

クライアントは1行でセッションを張り、あとは普通のメソッド呼び出しに見える。

import { newWebSocketRpcSession } from "capnweb";

// ワンライナーのセットアップ
let api = newWebSocketRpcSession("wss://example.com/api");

// サーバーのメソッドを呼ぶ
let result = await api.hello("World");

console.log(result);

サーバー側は RpcTarget を継承したクラスを書き、トランスポートに応じたレスポンスヘルパーで公開する。以下はCloudflare Workersの例だ。

import { RpcTarget, newWorkersRpcResponse } from "capnweb";

// これがサーバー実装
class MyApiServer extends RpcTarget {
  hello(name) {
    return `Hello, ${name}!`
  }
}

// 標準的な Cloudflare Workers の fetch ハンドラ
export default {
  fetch(request, env, ctx) {
    let url = new URL(request.url);
    if (url.pathname === "/api") {
      return newWorkersRpcResponse(request, new MyApiServer());
    }
    return new Response("Not found", {status: 404});
  }
}

RpcTarget を継承したクラスのインスタンスは参照(pass-by-reference)で渡る。スタブは内部的にJavaScriptの Proxy で実装され、using 変数に束ねれば関数スコープの終わりで自動的に破棄([Symbol.dispose])される。リソースの後始末を言語機能に委ねられるのも、JSネイティブ設計の恩恵だ。

トランスポートとAPI(HTTP/WebSocket/postMessage)

Cap’n Web は複数のトランスポートを標準装備する。READMEは「It works over HTTP, WebSocket, and postMessage() out-of-the-box, with the ability to extend it to other transports easily.」と述べ、独自トランスポートも RpcTransport インターフェイス(send/receive/abort?)で拡張できる。

トランスポート 主なヘルパー 用途
HTTPバッチ newHttpBatchRpcSession(クライアント)/ newHttpBatchRpcResponse(サーバー) 複数のRPCを1つのHTTPリクエストにまとめる。promise pipeliningと好相性
WebSocket newWebSocketRpcSession(クライアント/サーバー共通) 双方向・持続的なセッション
MessagePort newMessagePortRpcSession ブラウザ内でWeb Worker・iframe等と会話
ランタイム別 newWorkersRpcResponse / nodeHttpBatchRpcResponse / newBunWebSocketRpcHandler Workers / Node / Bun のサーバー側

トランスポートを状況で選べることは、実装上の自由度に直結する。ブラウザからサーバーへ一括で問い合わせるだけならHTTPバッチが最も素直で、pipeliningの恩恵(1リクエストで依存チェーンを解決)をそのまま受けられる。サーバーからクライアントへも能動的に呼びたい(プッシュ・購読・進捗通知)なら持続的なWebSocketセッションが向く。ブラウザのタブ内でメインスレッドとWeb Worker、あるいはiframe間で会話したいだけなら、ネットワークを介さずMessagePortで同じRPCモデルを使える。どのトランスポートでも「参照渡し」と「pipelining」という核は共通なので、通信経路を変えてもアプリ側のコードの考え方は変わらない。

APIの中心は RpcTarget(参照で公開するクラスの基底)、RpcStubProxyベースのスタブ)、RpcPromise(pipelining可能なthenable)、そしてセッション生成関数群だ。HTTPバッチでは「バッチ内の後続呼び出しの引数に、先行呼び出しの結果を使える」——READMEいわく「the results of one call in the batch can be used in the parameters to later calls in the same batch, even though the entire batch is sent at once」。これがpromise pipeliningの実体で、1リクエストで依存チェーンを解決する。

Cloudflare Workersとの相性、そしてエージェント基盤での役割

Cap’n Web は Cloudflare Workers の組み込みRPCとセマンティクスがほぼ一致するよう設計されている。READMEは「on Cloudflare Workers specifically, it’s designed to play nicely with the built-in RPC system. The two have basically the same semantics… On Workers, the RpcTarget class exported by “capnweb” is just an alias of the built-in one.」と述べる。つまりWorkers上では、capnwebRpcTarget は組み込みのエイリアスであり、「You can also send Workers Service Bindings and Durable Object stubs over Cap’n Web.」——Service BindingsやDurable Objectのstubもそのまま送れる。Honoを使うなら @hono/capnweb の統合も用意されている。

この「Workers/DOのstubを参照で渡せる」性質が、エージェント基盤の配管として効いてくる。当サイトで解説したCloudflare Computer(AIエージェントにDurable Object上の仮想FSと実行環境を与えるOSS)は、コンテナ内のデーモンとDurable Objectの間の状態同期に capnweb を用いている(computer側のREADMEに「capnweb WebSocket」「capnweb RPC channel」と明記)。同様に、企業コンテキストでエージェントを走らせるCloudflare OS(Workers上のエージェント・ワークスペース)のようなプロダクトも、プロセス間・境界越えの通信でこの系統の仕組みに乗る。Cap’n Web単体は地味なライブラリに見えるが、「エッジで分散したコンポーネント同士が、能力(参照)を渡し合って会話する」ための土台として、Cloudflareのエージェント・スタックの底に敷かれているわけだ。

Cap’n Protoとの関係と、いつ使うか

なぜエージェント基盤でこの性質が重要なのか。エージェントの実行環境は、コンテナ・Durable Object・Worker・ブラウザといった複数の実行境界にまたがりがちだ。境界を越えるたびに「相手のオブジェクトのメソッドを呼ぶ」ことを、いちいちREST的なエンドポイント設計に翻訳していては、配管のコードが膨れ上がる。Cap’n Webのように「オブジェクトやDurable Objectのstubを参照で渡し、そのまま呼べる」仕組みがあれば、境界越えの通信を通常のメソッド呼び出しに近い形で書ける。エージェントが増え、コンポーネント間の会話が密になるほど、この「参照を渡し合えるRPC」の価値は効いてくる。

系譜を整理しておく。Cap’n Web は Cap’n Proto の「精神的な兄弟」で、object-capabilityという思想と promise pipelining という強力な仕組みを受け継ぐ。一方で、Cap’n Protoが要求したスキーマ定義とバイナリシリアライズを捨て、スキーマ無し・JSベースの人間可読シリアライズに振り切った。これは「型の厳密さ・多言語対応・最高効率」を最優先するならCap’n Proto(やgRPC等)が向くが、「TypeScriptだけで完結し、ブラウザからエッジまで軽く通信したい」ならCap’n Webが向く、というトレードオフを意味する。

Cap’n Webが向く:JS/TS一色のスタック、ブラウザ⇄Workers⇄Node、双方向コールバックが要る、スキーマ管理を避けたい、バンドルを小さく保ちたい
別の選択が向く:多言語間の厳密なスキーマ契約、極限のバイナリ効率、既存gRPCエコシステムとの整合が最優先

補足として、READMEは「JSON-RPCやgRPCより優れている」といった名指しの比較はしていない点に触れておく。あくまで「object-capabilityモデルゆえに表現力が高い」と述べ、対比の相手はCap’n Proto(スキーマの有無・シリアライズの可読性)に限っている。したがって「gRPCの置き換え」と短絡せず、「JS/TSスタックで、参照渡しと双方向・pipeliningが欲しいときの軽量な選択肢」と捉えるのが正確だ。0.x系でAPIが動きうる点も含め、まずは小さなエンドポイントで往復数やコード量の差を体感してから範囲を広げるのが堅実な導入手順になる。

バージョンと表記の注意
npmのパッケージ名は capnweb、最新は 0.10.0(2026-07時点)。リポジトリはモノレポで、検証用サブパッケージ capnweb-validate も同居します。人間可読な名称は「Cap'n Web」で、READMEはこの表記を使います。まだ0.x系のため、APIは今後変わりうる前提で採用してください。ライセンスは実体ファイル LICENSE.txt がMIT(Copyright 2025 Cloudflare, Inc.)です。
まとめ
Cap'n Web(`cloudflare/capnweb`)は、スキーマもboilerplateもほぼ不要なJS/TSネイティブのobject-capability RPCだ。双方向呼び出し・関数/オブジェクトの参照渡し(stub)・promise pipelining という3つの表現力で、「呼び出しのたびに往復が増える」レイテンシと「スキーマ管理の重さ」を同時に解く。依存ゼロ・10kB未満でブラウザからWorkersまで動き、Cloudflare Workersの組み込みRPCとほぼ同じセマンティクスを持つ。そのためエッジで分散したコンポーネント——Cloudflareのエージェント基盤を含む——の配管として自然に収まる。多言語の厳密なスキーマ契約や既存gRPC資産との整合が要る現場では従来の選択が引き続き妥当だが、JS/TS一色でフロントからエッジまでを軽く繋ぎたいなら、Cap'n Webは「小ささ」と「表現力」を両立する珍しい一手になる。まずは `npm i capnweb` して、`RpcTarget` とWebSocketセッションで双方向RPCの手触りを確かめるところから始めるとよい。

参照ソース

cloudflare/capnweb(公式リポジトリ・README) — 定義・3つの表現力・トランスポート・Workers連携の一次情報
capnweb(npm) — パッケージ名・最新バージョン(0.10.0)・MIT
Cap’n Web: A new RPC system for browsers and web servers(Cloudflare公式ブログ) — 公式アナウンス(2025-09-22)
cloudflare/computer(capnwebの利用例) — コンテナ⇄Durable Object同期にcapnwebを使う実例