DeepSeek Harness の基盤技術「Cordis」の仕組みを解説
本文の状態
日本語全文を表示中
詳細モードで約44分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Tencent Engineering
DeepSeek が独自開発した AI エージェント用ランタイム基盤「Cordis」の技術的詳細と、元 QQ ロボットフレームワークから派生したその設計思想、および北京大学との共同論文発表について解説する。
AI深層分析を開く2026年9月4日 21:56
AI深層分析
キーポイント
Cordis の役割転換と定義
DeepSeek Harness の基盤として機能する Cordis は、元々 Koishi ロボットフレームワークのプラグインシステムから派生し、現在は「誰がいつ生きていられるか」を問うメタフレームワークとして位置づけられている。
開発者 Shigma と技術スタック
Cordis を中心に Schemastery や Minato などを開発した Shigma 氏により構築された技術スタックは、一人の人間が支える包括的なエコシステムとして確立されている。
学術的裏付けと論文発表
北京大学と DeepSeek-AI が共同で発表した論文『A Programming Paradigm for Spatiotemporal Composability』は、Cordis のメカニズムを形式化し、その理論的正当性を示している。
フレームワークの核心機能
Cordis は「インストール」「設定管理」「アンロード(クリーンアップ)」「相互運用」の 4 つの課題に対し、プラグイン作者の依存に頼らず、フレームワークレベルで保証する仕組みを提供する。
構成による組み合わせとプラグインの多様な形態
アプリケーションの外観は設定ファイルで決定され、プラグインは機能のみを提供する「構成即結合」のアプローチを採用している。
重要な引用
Cordis は拉丁語"心"(cor)的所有格,意为"心脏"。
Cordis 不是机器人框架,也不是 DI 容器,而是规定"副作用如何组合、依赖如何解析"的 meta-framework。
它把"卸载"和"协作"这两件事,从"插件作者的自觉"上升为"框架级保证"。
「插件因此不是平铺的,而是一棵树:子上下文能看到父上下文的一切(继承),但卸载是按层级的」
編集コメントを表示
編集コメント
DeepSeek が独自に開発したランタイム基盤「Cordis」の詳細が明らかになったことは、同社の技術スタックの深さを示す重要な材料である。特に、学術論文と実装が連動している点は、研究と開発の密接な連携を象徴する事例として注目される。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
2026年9月4日 17時36分 広東
腾讯程序员 による記事
Koishi から DeepSeek Harness へ:Cordis の過去と現在
著者:lss233
DeepSeek Harness の「すべてがプラグイン」という思想の裏側で動いているのが、Cordis というフレームワークです。もともとはサードパーティ製の QQ ボット向けに開発されたこの技術ですが、今では DeepSeek におけるエージェント実行時の基盤として活用されています。
この記事では、Cordis の魅力をわかりやすく解説します。「アンインストール」と「協調動作」がなぜデフォルトの挙動になるのか、「設定変更で再起動不要」がなぜ当然のことなのか、そしてなぜ 88 ページにも及ぶ論文がこのフレームワークを研究対象としているのか。その理由を探っていきましょう。
1. プラグインシステムにフレームワークが必要な理由
1.1 4 つの課題
仮にチャットボットのロジックを最初から単一のファイルに記述していたとしましょう。機能が増えるにつれてモジュール化を進めることはできますが、それによって解決できるのは「コードの整理」だけです。残りの 4 つの問題は依然として残ります。
- インストール: 新しい機能をどのようにシステムに組み込むか?
- 設定: 同じ機能でもデプロイ環境ごとに異なる設定が必要だが、どこで管理すべきか?
- アンインストール: 機能を停止する際、そのタイマーやリスナー、接続を誰がクリーンアップするか?不十分な処理はリソースリークの原因になります。
- 協調動作: 機能 A が機能 B の能力に依存している場合、B がまだ起動していない、あるいは将来的に別の実装に置き換わったとしても、A はどう対応すべきか?
プラグインシステムとは、まさにこれら 4 つの課題に対する回答です。Cordis の特徴は、「アンインストール」と「協調動作」を「プラグイン作者の自己責任」から「フレームワークレベルでの保証」へと昇格させた点にあります。
1.2 開発者:Shigma
まずはこのフレームワークを生み出した人物、Shigma について紹介しましょう。
Shigma はサードパーティ製の QQ ボットコミュニティにおいて非常に著名な存在で、仲間からは親しみを込めて「夢夢」と呼ばれています。彼の GitHub アカウント(shigma)には 130 以上の公開リポジトリが登録されています。また、npm でいくつかの主要パッケージを開発している際にも、その maintainer がすべて同一人物であることが確認できます。
- パッケージ名:一言で言うと
- koishi:クロスプラットフォームなチャットボットフレームワーク(npm 公式説明:"Made with Love")
- cordis:プラグイン化されたアプリケーションフレームワーク。この記事の主人公です。
- @satorijs/core:クロスプラットフォームなチャットプロトコルアダプター層(Koishi が QQ、Discord、Telegram をサポートする基盤)
- schemastery:型駆動型の schema バリデーター
- minato:型駆動型のデータベースフレームワーク(Koishi のデータレイヤーを担う)
- cosmokit:ユニバーサルなツールキット
「Cordis」は、一人の開発者が支える技術スタックの骨格です。Cordis はライフサイクルと依存関係の管理を担い、「Schemastery」が設定の検証、「Minato」がデータアクセス、「Satorijs」がプラットフォームプロトコルを担当します。そして「Koishi」がこれらを集大成した存在で、全体は Cordis 上で稼働しています。この記事で紹介されるすべての概念(fiber、effect、Schema、Service)も、すべて一人の手によって生み出されました。
Shigma は 2023 年末、腾讯媒体研究院のシリーズ『20 代で何をすべきか』にインタビューされました(BV1AQ4y157S8)。当時彼は大学院 2 年生で、QQ ボット開発を 5 年間続けていました。AI が人間の仕事を奪うかどうかという問いに対し、「古い職は消えるが、新しい職も生まれるはずだ」と答えました。むしろ人間は、より良い世界で暮らす機会を得られると彼は考えています。彼が QQ ボットの作成を始めた理由の一つに、自身の業務効率化がありました。当時は Cordis も Koishi の限られたコミュニティ内でしか知られておらず、2 年後には DeepSeek Harness の心臓部になると誰も予想していませんでした。
現在、Cordis を解説する論文『A Programming Paradigm for Spatiotemporal Composability』がプレプリントとして公開されています。所属は北京大学と DeepSeek-AI で、第一著者は Yifan Shi、共著者に Wei Zhang と Tianyi Cui が名を連ねています。この論文では Cordis のメカニズムを形式化し、定義・定理・証明を示しています。
1.3 出身と名前
Cordis は Shigma が立ち上げたクロスプラットフォームチャットボットフレームワーク「Koishi」から誕生しました。2020 年 1 月に最初の正式バージョンがリリースされました。Koishi のプラグインシステムが成熟したことで、そのコア部分が独立して汎用フレームワークとなりました。2022 年 4 月には cordis パッケージが npm に登場し、2023 年末には 3.x バージョンへ移行しました。そして 2024 年末からは Cordis 4 の開発が始まり、2024 年 11 月に最初のプレリリース版が公開されました。これは完全な再構築であり、fiber ベースのライフサイクル体系を導入したものです。
名前の由来はラテン語です。「Cordis」は「心(cor)」の所有格で、「心臓」という意味を持ちます。それは Koishi の心臓であり、現在では DeepSeek Harness の心臓でもあります。
1.4 位置づけ:メタフレームワーク
Cordis はロボットフレームワークではありません(それは Koishi の役割です)。また DI コンテナでもありません。従来の DI が「誰が作成するか」を問うのに対し、Cordis はより困難な問い、「誰がいつ生存しているか」に答えます。論文における Cordis の位置づけはメタフレームワークです。「副作用の組み合わせ方」「依存関係の解決方法」を規定しますが、特定のビジネス領域を前提とはしません。QQ ボットにも、Agent ランタイムにも利用可能です。
2. コアメカニズム:5 つの概念と 7 つの小節
Cordis のすべての意味は、以下の 5 つの概念に集約されます。プラグイン、コンテキスト、注入、イベント、可逆副作用です。これらを浅いところから順に解説していきます。
#### 2.1 最初のプラグイン
Cordis でプラグインを書く際、最も爽快な点は、フレームワーク起動用のコードが一切不要であることです。
DeepSeek Harness(DSH)の背後にある「心臓部」——Cordis とは何か
// hello.ts
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello'
export function apply(ctx: Context) {
console.log('hello from my first plugin')
}
cordis.yml —— アプリケーション自体が設定ファイルである
./hello.ts を実行すると、DSH に付属する起動ツールが動作します。このプロセスではルートコンテキストが作成され、Loader プラグインがマウントされ、cordis.yml が読み込まれた上で、「hello from my first plugin」という出力が表示されます。
ここで重要なのは役割分担です。プラグインは「機能の提供」のみを記述し、アプリケーションの外観や振る舞いは設定ファイルによって決定されます。これが「設定による組み合わせ(Configuration as Composition)」という考え方です。
プラグインには主に 3 つの形態があります。
import { Service, type Context } from '@deepseek-ai/cordis'
export function apply(ctx: Context) {}
// 1. 関数型(最も一般的)
export const objectPlugin = {
name: 'object-plugin',
apply(ctx: Context) {},
}
// 2. オブジェクト型
export class MyService extends Service {
constructor(ctx: Context) {
super(ctx, 'myService')
}
}
// 3. クラス型(外部サービスを提供する場合に使用)DSH において、あなたが作成するすべてのツールプラグイン、アダプタープラグイン、パネルプラグインは、この 3 つのいずれかの形態で実装されます。
2.2 コンテキスト(Context):すべての操作への入口
Cordis を使う際、ほぼ常に扱うのは ctx という 1 つのものだけです。これはコンテキストであり、同時にサービスコンテナでもあります。プラグインが実行できるすべての機能は、このコンテキストを通じて提供されます。
export function apply(ctx: Context) {
ctx.on('some/event', (payload) => { /* ... */ }) // イベントの監視(アンロード時に自動解除)
ctx.effect(() => { /* ... */ }) // 副作用の登録(アンロード時に自動ロールバック)
ctx.plugin(SomePlugin) // サブプラグインのマウント(親プラグインのアンロードに連動)
ctx.get('someService') // サービスの取得(存在しない場合は undefined)
ctx.provide('someValue', 42) // 値やサービスの提供
}ctx.plugin(child) は単なる「登録」ではなく、派生した子コンテキストを作成する操作です。そのため、プラグインは平面的に並ぶのではなく、ツリー構造を形成します。
image子コンテキストは親コンテキストの情報をすべて継承して参照できますが、アンロード(削除)は階層単位で行われます。親プラグインをアンロードすると、その下位にあるすべての子プラグインも再帰的にアンロードされます。一方、子プラグインをアンロードしても、兄弟や上位のプラグインには影響しません。このように構築された「プラグインタリー」こそが、Cordis のライフサイクルにおけるすべての意味論を支える骨格です。
DSH(DeepSeek Harness)においては、あなたが目にするあらゆる機能——ツール、モデル、セッション、パネル——は、すべてこのツリー構造上で ctx.plugin() が呼び出された結果として実現されています。
2.3 Fiber:プラグインのライフサイクル
Cordis 4 では、ロードされた各プラグインインスタンスに対して「Fiber(繊維)」が1 つずつ維持され、その状態遷移は以下の通りです。
- PENDING:プラグインは宣言済みですが、依存するサービスがまだ inject されていないため待機状態です。
- LOADING / ACTIVE:apply メソッドが実行中、または完了した状態です。
- FAILED:apply メソッドで例外が発生した場合や、設定の検証に失敗した場合です。
- UNLOADING / DISPOSED:クリーンアップ処理中、あるいは完全に解除された状態です。
プラグインは、設定の変更、ホットリロードの実行、明示的な dispose() 呼び出し、あるいは依存するサービスの消失などによってアンロードされます。どのような理由であれ、その後のクリーンアッププロセスは自動的に実行されます。
DSH においては、cordis_inspect コマンドが各 Fiber の状態を監視しています。「プラグインは読み込まれているのに反応しない」という現象の多くは、実はこの PENDING 状態で待機していることが原因です。
2.4 Effect:可逆的な副作用
これが Cordis の最初の核となるメカニズムであり、従来の DI(依存性注入)コンテナとの決定的な違いです。
ctx.effect(() => {
const conn = createConnection()
return () => conn.close() // disposer:どのようにクリーンアップするか
})effect の本体はプラグインのロード時に実行され、返される disposer(破棄関数)はアンロード時に呼び出されます。ユーザーが手動でクリーンアップ関数を呼ぶ必要は一切ありません。プラグインがどのような理由でアンロードされたにせよ、Cordis が自動的にタイマー、リスナー、データベース接続などをすべて元に戻します。
さらに、Cordis の組み込み API もすべて effect として実装されています。ctx.on() で登録したリスナーはプラグインのアンロード時に解除され、ctx.plugin() で生成された子プラグインも再帰的にアンロードされます。また、サービスの登録も、その提供者が消失すれば自動的に解除されます。
論文の実装セクションには重要な結論が記されています。「Cordis におけるコンテキストへの変更はすべて、最終的に ctx.effect という単一の原語に集約される」という点です。サービス提供、プラグインのマウント、リスナーの登録——これらすべてが ctx.effect の特殊なケースに過ぎません。したがって、「コンテキストを介した操作はすべて自動的に追跡可能で回復可能である」というのは単なる設計思想ではなく、システム構造そのものが保証する事実なのです。
プラグイン作者が守るべき鉄則はただ一つです。「自分で作成し、Cordis が管理しないリソース」があれば、必ず ctx.effect() で包んでください。
副作用が可逆であるため、プラグインは安全にアンインストールして再インストールできます。これにより、ホットリロード(HMR)、障害時の自動復旧、テストの分離が可能になります。第 5 章で詳しく解説しますが、DSH の「動的にプラグインを装ってすぐに卸す」という挙動も、すべてこの原語に基づいています。
DSH では、「設定を変更する → 古いプラグインをアンインストール(すべての効果ロールバック)→ 新しいプラグインをロード」という流れで、プロセスの再起動なしに処理が完了します。これが「設定変更時に再起動不要」を実現する裏側の仕組みです。
2.5 サービスと注入:応答性の依存関係
これは Cordis の 2 つ目の核心メカニズムです。
ある機能を ctx に登録し、他のプラグインが名前を指定して利用できるようにするのが「サービス」です。
import { Service, type Context } from '@deepseek-ai/cordis'
export class GreeterService extends Service {
constructor(ctx: Context) {
super(ctx, 'greeter') // 登録:以後、誰でも ctx.greeter でこのサービスを取得可能
}
greet(who: string) {
return `Hello, ${who}!`
}
}利用側は実装をインポートするのではなく、名前だけを宣言します。
export const inject = ['greeter'] // 依存関係を宣言
export function apply(ctx: Context) {
console.log(ctx.greeter.greet('world')) // この時点で greeter は必ず準備完了している
}inject の意味は、「プラグインが PENDING 状態のままで、リストされたサービスがすべて準備されるまで待機する」ということです。設定ファイルの記述順序には関係なく、起動順序は依存関係によって自動的に決定されます。
従来の DI(依存性注入)との本質的な違いは、従来の DI が「一度バインドすればサービスは常に存在する」と仮定しているのに対し、Cordis は「サービスはいつでも出現し、いつでも消失する可能性がある」という前提に立っています。これは Agent シナリオではごく当然のことです。LLM プロバイダがレート制限に引っかかる、MCP サーバーがクラッシュしてツールが登録解除される、ファイルウォッチャーがシステムによって強制終了される、といったケースが日常的に起こり得ます。
Cordis の対応策は、プロバイダーがアンインストールされた場合、それに依存するすべてのプラグインも自動的にアンインストールされ(効果ロールバック)、新しいプロバイダーが準備されると自動的に再ロードされます。依存側は再接続のためのコードを一切記述する必要はありません。
また、これに付随する 2 つのメカニズムもあります。
ctx.isolate(key, realm):隔離。あるスコープ内の特定のサービス解析を独立したインスタンスに割り当て、2 つのグループがそれぞれ独自の実装を使用し、互いに干渉しないようにします。
ctx.intercept(key, meta):インターセプト(中継)。依存関係へのアクセスにメタデータを付与し、コンポーネント自体を変更せずに、外部のコンテキストでその依存関係をどのように使用するかを制約できます。
DSH では、ctx.tools、ctx.llm、ctx.shell、ctx.sessions、ctx.skills などがすべてこのようなサービスです(完全なスロット一覧は第 4 章に記載されています)。
2.6 イベント:呼び出しと意思決定チェーン
サービスは「直接電話をかける」のに適していますが、多くの場合、プラグインは単に「声を上げる」か、「一時的に止める」だけで、誰が聞いているかは気にしません。Cordis のイベントシステムは型安全であり、イベント名とリスナーのシグネチャは TypeScript の宣言マージによって、エンドツーエンドで完全な型の安全性を確保します: (原文の技術表記: Hello, ${who}!)
DeepSeek Harness(DSH)の背後にある「心臓」——Cordis とは何か
declare module'@deepseek-ai/cordis' {
interface Events {
'stats/report'(name: string, count: number): void
}
}
ctx.emit('stats/report', 'tool_call', 42) // 発火
ctx.on('stats/report', (name, count) => { /* リスナー登録、アンロード時に自動削除 */ })
イベントの分发(ディスパッチ)モードは、Cordis の公開契約そのものです。この契約が、リスナーに値を返せるか、並列実行が可能か、あるいは早期終了(ショートサーキット)できるかを決定します。
- モード:意味
- emit:同期ブロードキャスト;待機せず、戻り値も収集しない
- parallel:すべてのリスナーを並列実行し、完了まで待つ
- serial:順次実行;最初の非空の戻り値が勝者となり、以降の実行は停止する
- bail:serial の同期版
- waterfall:中間処理(around-middleware)モード。詳細は後述
waterfall は DSH で最も頻繁に利用されるモードで、Koa や Express のミドルウェアをイベントシステムに取り込んだような仕組みです。各リスナーは引数と、次のステップへ進むための next() コールバックを受け取ります。
ctx.on('some/decision', async (input, next) => {
if (!hasPermission(input)) return { denied: true } // next() を呼ばない=拒否、ショートサーキット
return next() // next() を呼ぶ=許可
})
互いに顔も知らない複数のプラグインが、このようにして一つの意思決定チェーンを形成します。DSH には明確なルールがあります:観察や記録のみを行う waterfall リスナーは、必ず next() を呼び出すことです。これを怠ると、下流のデフォルト動作が静かに消えてしまいます。
DSH におけるツール実行パイプライン tools/pre-execute → tools/execute → tools/post-execute も、まさにこの waterfall チェーンです。同様に、approval/request や agent/request も waterfall モードで動作します。
2.7 スキーマと宣言的コンポジション:設定こそがプログラム
cordis.yml の各項目(entry)にはメタデータを付与できます。
- id: greeter # 安定した識別子:ローダーはこれにより「修正」か「削除して再追加」かを判別する
name: './greeter.ts'
- id: consumer
name: './consumer.ts'
disabled: true # エントリを保持しつつマウントしない;設定を戻せば自動的にロードされる
id を付与しないエントリは、読み込むたびに新しい ID が生成されるため、設定ファイルのあらゆる編集が「削除後、再追加」として扱われます。正確なインクリメンタル更新を行うには、必ず id を指定する必要があります。
group:複数のプラグインを一つのユニットとしてパッケージ化し、一括でロード・アンロード可能にします。isolate と組み合わせることで、グループ内でのみ独立したサービスインスタンスを使用することも可能です。
Schema による検証:プラグインの schema 宣言と設定構造は「Schemastery」(Shigma が開発したライブラリ)で定義され、Cordis は apply 実行前にこれを検証します。設定が不正な場合、ロードに失敗して詳細なエラーメッセージが表示されるため、設定が不完全な状態でプラグインが半端に起動することはありません。
export const Config: Schema = Schema.object({
greeting: Schema.string().default('Hello'),
targets: Schema.array(String).default(['world']),
})JS 式による動的評価:DSH の Loader 拡張機能では、config および disabled フィールド内で実行時評価が可能な式(例:!!js process.env.X ?? 'default')を記述できます。ただし、依存関係が完全に準備されるまで評価は保留されます。
設定=プログラム:設定の変更は部分的なホットリロードとして即座に反映され、アプリケーションの再起動は不要です。
DSH における実装では、cordis.patch.yml と --patch フラグによるオーバーレイが、この宣言型コンポジションを生産環境でどのように活用されるかを表しています(詳細は次章で解説)。
Cordis の 5 つの核となる概念——プラグイン、コンテキスト、注入、イベント、可逆的な副作用——と、これらを統括する Schema がここに登場しました。これらのメカニズムを組み合わせることで、どのようなシステムが構築可能になるのか?次章では DeepSeek Harness を通じてその答えを示します。
- DeepSeek Harness における「すべてはプラグイン」
以下の内容は、DSH 0.1.0-rc.6 の実装ソースコード(@deepseek-ai/cordis 4.0.1)に基づいています。
3.1 起動:約 20 行のコードでアプリケーション全体を構築
import { Context } from '@deepseek-ai/cordis'
import Loader from '@deepseek-ai/cordis-plugin-loader'
async function boot(binName, configPath, patches, prepare, baseUrl) {
const ctx = new Context()
ctx.baseUrl = /* 相対パスの基準 */
ctx.provide('dshHomePath', dshHomePath) // 初期値の設定
await ctx.plugin(Loader) // Loader のマウント
await prepare?.(ctx)
await mountRootInclude(ctx, configPath, patches, baseUrl) // Include による設定ツリーのマウント
await ctx.get('loader')?.await() // ツリーが安定するまで待機
await assertEntriesActivated(ctx, binName) // 監査:半起動状態の項目は許容しない
return ctx
}根幹となる Context は、たった 3 つの小さな役割しか果たしていません。残りのすべては設定ツリーから構築されます。
3.2 Profile:アプリケーションを積み重ね可能な層として分割
DSH では「Profile」という概念を導入しました。これは $DSH_HOME/profiles/ ディレクトリ内のフォルダで、manifest(dsh.profile.bundles で順序付きに適用されるバンドル群)と、ユーザーが作成した cordis.patch.yml を含みます。設定ツリーの組み立て順序は以下の通りです。
Bundle(组合包)とは、package.json で "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } と宣言された npm パッケージのことです。コアとなる Bundle パッケージである @deepseek-ai/dsh-base では、数十個のプラグインを一度に空のルートへ挿入するパッチファイルが用意されています。
- insert:
- id: timer
name: '@deepseek-ai/cordis-plugin-timer'
- id: hmr
name: '@deepseek-ai/cordis-plugin-hmr'
config:
root: ['.']
- id: llm
name: '@deepseek-ai/dsh-llm'
- id: session
name: '@deepseek-ai/dsh-session'
- id: agent
name: '@deepseek-ai/dsh-agent'
- id: jobs
name: '@deepseek-ai/dsh-jobs-local'
# ……さらに多くのプラグインも追加可能
デプロイ側が既定の動作を変更したい場合でも、ソースコードを直接修正する必要はありません。独自の patch レイヤで id を指定して行を上書きするだけで済みます(後から記述されたものが先の内容を上書きし、挿入や無効化も可能です)。
「どのプラグインがアプリケーションに含まれているか」「各プラグインの設定はどうなっているか」といった情報自体が、重ね合わせ・上書き・監査可能な宣言として管理されています。これが「すべてをプラグイン化する」という技術的基盤です。
3.3 ツールパイプライン:エージェントの各機能
エージェントの能力範囲は、ctx.tools サービスによって定義されます。ツールを登録する本質とは、Cordis プラグインを追加することと同じです。
export const name = 'greet-tool'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet',
description: 'Greet the named person.',
parameters: { name: { type: 'string', required: true } },
async execute(args) { return Hello, ${args.name}! },
}))
}
inject: ['tools'] はレジストリが準備されるのを待ちます。ctx.tools.register(...) で登録すると即座に効果が発生し、プラグインのアンロード時にツールは自動的に注销(削除)されます。また、tools/result イベントにより、どのプラグインも実行者を特定することなく、すべてのツール呼び出しを監視できます。
本記事執筆において使用した bash、read、grep、subagent などのツールはすべて ctx.tools に登録されています。
3.4 自己言及的な設計:エージェントが自身のランタイムを検査・改造する
DSH で最も注目すべきパッケージは @deepseek-ai/dsh-tool-cordis です。これは公式に「自己言及的な Cordis ツールセット(self-referential Cordis toolset)」と称されています。
このツールセットはエージェントに対して以下の 5 つの機能を提供します。
- cordis_inspect:現在のプロセスに対する只読の点検。どのサービスが稼働中か、各 fiber の状態、登録されているツールのリスト、および各 ctx. の完全な契約を確認できます。
- cordis_define:その場で小さなプラグインパッケージを定義する機能(「ホスト側半分+ブラウザ側半分」を含む場合もあり)。ただし、これは記録のみを行い、実行は行いません。
- cordis_run:ホスト側部分を node:vm サンドボックス内で実行し、ブラウザ側部分をすべての開いているウェブページにプッシュします。 (原文の技術表記:
Hello, ${args.name}!)
「cordis_stop」や「cordis_undefine」コマンドを用いて、動的なパッケージのアンインストールが可能です。
エージェントは自身が動作しているフレームワークを確認し、その場で動的プラグインを記述・実行できます。使用後は即座にアンインストールするため、cordis.yml の変更も npm パッケージの追加もプロセスの再起動も不要です。DSH(DeepSeek Harness)の信頼モデルは明確で、「動的パッケージは bash スクリプトと同権」とし、サンドボックスはグローバルな隔離を提供しますが、それ自体が絶対的なセキュリティ境界となるわけではありません。
これに付随する「双半プラグイン」設計では、ロジックを管理するホスト側(サーバーサイド)と UI を管理するブラウザ側(クライアントサイド)がそれぞれ独立して動作します。両者は host.call による RPC で連携しています。「すべてはプラグイン」という DSH の理念は文字通り実現されており、フロントエンドの UI コンポーネントもまたプラグインです(dsh-client-ui-* シリーズには数十個のパッケージが含まれます)。ブラウザ内では、独立した Cordis クライアントランタイムが稼働しています。
自己分析とその場でのカスタマイズという 2 つの特徴を組み合わせることで、「進化するエージェント」の原型が生まれます。論文の結論部でも、「自己進化型エージェントランタイム」が本理論の将来検証方向として明記されています(セクション 5.9 参照)。
- DSH で何を開発できるか:プラグインのスロットとアイデア
この章では、より実務的な問いに答えます。「DSH で何かを実現したい場合、どこに接続すればよいのか」。以下のスロット一覧は、DSH の能力ドキュメント(capability-seams)およびインストールパッケージに登録されている実際のサービスキーに基づいています。
4.1 スロット:拡張ポイントはすべてサービス
DSH の拡張ポイントは単なる「API リスト」ではなく、Cordis サービス登録表です。どのプラグインも新しいサービスを登録できたり、既存サービスの提供者を差し替えたりできます(これは§2.5 で説明した反応型依存関係の直接的な応用です)。主要なスロットをカテゴリ別に整理すると以下のようになります。
- カテゴリ:スロット (ctx.) / 用途 / 現在の提供者(差し替え可能)
- 実行:shell / Bash 実行 / bash-local、bash-sandbox、pwsh-local、E2B
コード実行(codeRuntime)
コード・ランタイム・ワーカー(code-runtime-worker)が実行を担当します。
サブプロセスやターミナル(subprocess、terminals)は、子プロセスと永続 PTY として機能します。ローカル環境では subprocess-local や terminal-bash が利用されます。
LSP(言語サーバープロトコル)によるナビゲーションは、lsp-local を通じて提供されます。
モデル層では、LLM アダプター登録表が管理され、llm-deepseek、llm-pi-ai、llm-replay などのアダプターが登録されています。
エージェント機能(agents)には、agentLoop や agentDefaultModel が含まれ、エージェントの登録表、ループ駆動、デフォルトモデルを定義します。また、セッションレベルのエージェント構成である agentPresets も用意されています。
サブエージェントは subagents として提供され、プロセス内での生成やフォーク(subagent-spawn/fork-in-process)、ACP、Codex、Claude Code などが利用可能です。
データ管理では、セッションログと永続化機能を持つ sessions と sessionPersistence が扱われます。保存形式には JSONL (session-persistence-jsonl) や SQLite (-sqlite) が選べます。
セッションの読み取りと検索は sessionQuery で行われ、SQLite (session-query-sqlite) を使用します。
ストレージ機能では、汎用ストレージ(storage)、アタッチメント(attachments)、溢出存储(spillStore)が提供されます。保存先には JSON (storage-json) や SQLite (storage-sqlite)、ローカルファイルシステム(attachment-local、spill-local)が利用可能です。
セッションタイトルや投影ユニットは sessionTitle と sessionProjections で管理され、session-title-first-prompt-llm などの設定が適用されます。
環境層では、ファイルシステムの提供元として fs-local、サンドボックス(fs-sandbox)、E2B(fs-e2b)が利用可能です。
Web アクセス機能は、ウェブの取得や検索を担う web-fetch-http や、DeepSeek/Exa/Perplexity などの検索エンジンを利用する web-search-deepseek/exa/perplexity で実現されます。
認証情報とユーザー設定は credentials と settings で管理され、ローカル環境(credentials-local)やファイルベースの設定(settings-file)が利用可能です。
Web サーバー機能では、HTTP ルーティングやディレクトリ選択が webServer や directoryPicker によって提供されます。具体的には webserver コマンドやネイティブの directory-picker-native/browse が使われます。
ガバナンス層では、ツール登録表と保護された実行パイプラインを管理する tools が存在し、すべての dsh-tool-* ツールが対象となります。
承認(approval)、権限設定(permissionPresets)、サンドボックスポリシー(sandboxPolicy)は、それぞれ approval、permission-presets、sandbox-policy で定義されます。
オーケストレーション機能では、長期目標(goals)、ジョブ(jobs)、ワークフローエンジン(workflowEngine)、プランモード(planMode)がサポートされています。具体的には dsh-goal、ローカルジョブの dsh-jobs-local、およびスレッドベースの workflow-worker-thread が利用可能です。
自己言及機能では、動的なパッケージホスト(dynamicCordisRunner)やランタイム検査(cordisInspect)が提供され、cordis-host-runner によって実現されます。
フロントエンド層では、UI スロット(slots)、クライアントモジュール(clientModules)、テーマ(theme)、言語設定(locale)が定義されています。これらは dsh-client-ui-* シリーズのコンポーネントで構成されます。
4.2 槽位背后的设计:三种角色
このセクションでは、スロット設計における3つの主要な役割について解説します。
DSH は「能力の交換可能性」に対して明確なパターンを持っています。Service Definition(サービス定義)、Service Provider(サービス提供者)、Consumer(消費者)という三つの役割があり、shell を例に挙げると以下のようになります。
Definition はサービスと型を宣言するだけで、ほぼ不変です。
Provider は独立して交換可能です。例えば実行環境を沙箱に変更する場合でも、cordis.yml の設定を一行書き換えるだけで済み、Definition やすべての Consumer に影響はありません。
Consumer と Provider は互いに依存しません。
このパターンこそが、「すべてをプラグイン化する」という理念を能力レベルで実現したものです。各能力は「継ぎ目(seam)」として機能し、その両側は独立して進化することができます。
4.3 プラグイン導入の三つの方法
patch カバーレイ方式(最速)
YAML を記述し、dsh web --patch ./my-plugins.yml で起動時に項目を挿入します。
- insert:
- id: my-plugin
name: '/abs/path/to/my-plugin.ts'
プロファイルの cordis.patch.yml は、ユーザー層として常時有効になります。
bundle パッケージ方式
複数のプラグインを npm パッケージにまとめてパッケージ化し、dsh.bundle.patch を宣言することで、再利用可能な「コンボパック」として扱います。
プラグインのコード自体は依然として Cordis の標準に従います。関数、オブジェクト、クラスの三つの形態があり、依存関係は inject で宣言し、リソース管理には ctx.effect を使用します。設定の検証には Schema を使い、ツール登録には ctx.tools.register(defineTool(...)) を利用します。
4.4 既存のプラグイン例
組み込みのプラグイン(dsh-* パッケージ)は、役割に応じて以下の四つに分類されます。
ツール系(ctx.tools に登録され、Agent が呼び出せる能力です)
tool-bash、tool-fs、tool-fs-search、tool-web、tool-subagent、tool-subagent-control、tool-workflow、tool-goal、tool-jobs、tool-todo、tool-skill、tool-ralph、tool-ask-user、tool-lsp、tool-cordis(自己参照ツールセット)など。
プロバイダー系
モデルアダプター(DeepSeek、pi-ai による複数プロバイダー対応、replay)、shell プロバイダー(ローカル、沙箱、PowerShell)、fs プロバイダー(ローカル、沙箱、E2B)、Web 検索ソース(DeepSeek、Exa、Perplexity)、永続化バックエンド(JSONL、SQLite)、ストレージバックエンド、スキルプロバイダー、会話タイトル生成器など。
システム系
コンテキスト圧縮(compaction-basic)、トークン計測、メッセージフィードバック、権限プリセット、計画モード、長期目標、承認パイプラインなど。
フロントエンド系
dsh-client-ui-* の数十のパッケージ。設定ページ、モデル選択、プラグイン管理、タスクパネル、サブエージェントパネル、ゴールパネル、テーマなど。
コア機能の外部には、すでに活発なコミュニティによるプラグイン生態系が形成されています。GitHub 上では「awesome-dsh-plugin」というコミュニティ運営の厳選リストがあり、「dsh-plugin」で検索すると見つかります。2026 年 8 月時点で、dsh plugin add コマンドを使ってインストール可能なプラグインが 174 個登録されています。
代表的な例をいくつか挙げます。
UI の変更:
- dsh-visualize:モデルが対話型 HTML カードを会話ストリーム内に直接描画します。
- dsh-TUI:「Pixel Whale(ピクセル・ホエール)」のトップバーを模した、フルスクールのターミナル UI です。
- dsh-deep-whale:一連の Web スキンセットです。
- dsh-balance-meter:入力欄にアカウント残高と使用料を表示します。
記憶機能の変更:
- dsh-memento:境界付き、階層化された、承認ゲート付き、監査可能なセッション間メモリを提供します。
- dsh-mneme:SQLite と編集可能な Markdown ミラーリングを活用したセッション間メモリを実現します。
機能拡張:
- dsh-computer-use:エージェントが macOS を直接制御できるようにします。
- dsh-data-agent:AI がデータベースに接続し、SQL を記述・実行するのを支援します。
- dsh-docker:安全装置(ガードレール)付きのコンテナ制御機能です。
- dsh-toolkit:ゼロ依存の 10 個のツールをワンクリックでインストールできます。
コラボレーションの変更:
- dsh-agent-teams:マルチエージェントチームを構築します。
- dsh-crosstalk:セッション間でのメッセージ交換を可能にします。
- dsh-chat-import:Claude Code、Codex、ChatGPT のチャット履歴を DSH セッションとしてインポートできます。
自己進化:
- dsh-evolve:エージェントがセッション内で自らプラグインのホットマウントやアンインストールを行い、永続化します。
- dsh-continual-evolve:セッションの軌跡から、監査可能でロールバック可能なハーネス状態を蓄積・学習します。
プラグイン基盤:
- dsh-find-plugin:エージェントがセッション内で直接プラグインを検索・インストールできます。
- dsh-plugin-manager:dsh pm コマンドによる多ソースのプラグイン管理を提供します。
4.5 期待されるプラグイン:「標準的」な方向と「驚異的」な方向
標準的な方向(既存のプラグインパターンに則り、確立されたアプローチで開発):
- 新ツール:データベース照会、ブラウザ自動化、Docker、Kubernetes 操作、MCP クライアント、Git 操作、デプロイとテストランナー。
- 新プロバイダー:あらゆる LLM に接続するアダプター、リモート環境、コンテナシェルプロバイダー、新たな検索ソース、新しい永続化・ストレージバックエンド、新しいスキルプロバイダー。
「管理と可観測性」には、ウォーターフォールチェーンに組み込まれる承認戦略プラグイン、権限の事前設定、監査ログ、トークン予算制御、そして既存のシームを活用した OTel によるテレメトリが含まれます。
「インターフェース」では、新しい Web パネル(スロット)、コマンドパネル、および webServer を介して公開される HTTP API が提供されます。
「驚異的な方向性」として挙げられる機能は、すべて空想ではなく DSH の既存の仕組みに基づいています。
プラグインを書くためのプラグイン
プラグインは ctx.loader.create() を用いて実行時に動的にマウント・更新・削除が可能であり、他の設定項目を「組み立て」ることで、プラグイン自体がプラグインを生成します。さらに cordis_define や cordis_run と組み合わせることで、エージェントは現場で自らのツールを生成して実行できます。これは「生成→サンドボックスでの実行→結果の観測→保持またはアンインストール」という自己進化の閉ループを実現するものです。
セッションレベルで隔離された「分身」
ctx.isolate と agentPresets を活用すれば、各セッションに独立した設定を持つサービスインスタンスを割り当てられます。例えば、あるセッションでは DeepSeek モデルとローカル実行を組み合わせ、別のセッションでは他モデルとサンドボックス実行を組み合わせることで、互いに干渉させることなく運用可能です。これは単一のプロセス内で複数の「仮想 Harness」を実行しているようなものです。
本番環境での停止なしエンジン交換
パッチ層で LLM や Shell の提供元を置き換えるだけで、依存するすべてのコンポーネントが自動的にアンロード・再ロードされます。もし論文の 5.7 セクションにある「サービスブローカー」モデルを実装すれば、グレーディングやロールイング切り替えも可能になります。新旧の提供元を並行して稼働させ、重み付けに基づいてリクエストを振り分ける仕組みです。
ポリシーゲートウェイ
ウォーターフォールイベントを用いて、「承認→権限→レート制限→監査」という一連の意思決定チェーンを構築できます。新しいポリシーを追加する際も、実行パイプラインを変更する必要はなく、単にリスナープラグインを追加するだけで済みます。
専門家エージェントプール
ctx.subagents を基盤として、コードレビュー担当、テスト担当、ドキュメント作成担当などの常駐サブエージェントを構築します。メインエージェントは必要に応じてこれらのリソースをスケジューリングし、失敗した場合は引き継ぎを行います。これにより、サブエージェントは「使い捨てのツール」から「常駐サービス」へと進化します。
階層化された記憶システム
sessionProjections や sessionProjectionCache を活用して、作業用メモリ、長期記憶、要約折りたたみ機能を実装できます。これにより、エージェントの「記憶」はプラグインとして着脱可能なものになります。
ブラウザ向けデュアルハーフプラグイン
動的パッケージにはホスト側とブラウザ側の両方が含まれており、Web UI に対してパネルや監視ビューを注入します。使用後は即座にアンインストールされ、コードの提出は一切行われません。
ワークフローそのものがプラグイン
workflowEngine に新しいオーケストレーションのパラダイム(Ralph ループや並列 fan-out を除くカスタム反復モードなど)を登録することで、「複数エージェントがどのように協働するか」というプロセス自体を、組み合わせ可能なプラグインとして扱えるようになります。
これらの方向性の共通点は、すべて「フレームワークを変更する」のではなく「プラグインを追加する」ことで実現される点です。これが、Cordis の時空間的組換え可能性が DSH において具体的に実装された証左となります。
5. 論文は何を語っているか:「使いやすいフレームワーク」から「証明されたパラダイム」へ
Cordis に付随する論文『A Programming Paradigm for Spatiotemporal Composability』は、北京大学と DeepSeek-AI の研究者によって共著され、88 ページのプレプリントとして公開されています。この論文の目的は単に Cordis のマニュアルを作成することではなく、その核心となるメカニズムを形式化し、それが新しいプログラミングパラダイムを構成していることを証明することにあります。
論文内には「私たちのフレームワークは優秀だ」といった主張は一切含まれていません。代わりに、定義、定理、証明が並べられ、一貫して主張されているのは以下の点です。
動的な組み合わせ(実行時のコンポーネントの着脱)には形式化された基礎が存在しない。しかし Cordis は 2 つのランタイムメカニズムによってこれを補完し、それによって得られる性質を証明した。
5.1 論文が解決しようとしている課題:なぜ動的な組み合わせは難しいのか
ソフトウェア工学のすべては「組み合わせ」の上に成り立っています。しかし、従来の組み合わせは静的なものでした。関数の呼び出しやモジュールのインポート、クラスの継承などは、コンパイル時にすでに固定されてしまいます。
一方、現代のソフトウェアでは動的な組み合わせがますます必要とされています。実行時にコンポーネントをロードしたりアンロードしたり、再構成したりする能力です。プラグインアーキテクチャや自己進化型エージェント(Agent)はすべて、「実行時にも安全に機能を追加・削除できる仕組み」を必要とします。しかし、こうしたシステムの理論的基盤は、静的な組み合わせに比べてまだ成熟していません。
論文では、この動的な組み合わせを二つの独立した次元に分解しています。
一つ目は時間的な次元(temporal composability)です。コンポーネントが削除された際、共有環境に対して行った変更は、完全に、かつ安全に元に戻されなければなりません。静的なプログラムではこれは「辞書的スコープ」、つまり RAII(リソース取得=初期化)の概念に対応します。しかし動的なシナリオでは、副作用が長寿命であったり、辞書的な境界を持たなかったりするケースが多く、対応は非常に困難です。
二つ目は空間的な次元(spatial composability)です。コンポーネントは互いの依存関係を宣言し、発見し、解析できる必要があります。静的なプログラムではこれはモジュールの解析に相当しますが、動的な世界では依存関係が出現したり消えたり、あるいはその正体を変えたりします。
なぜこの問題は長年避けられてきたのでしょうか?それは、オペレーティングシステムやコンテナオーケストレーションが、粗粒度の代替手段を提供してきたからです。つまり、「プロセス単位での時間的な可組合性(プロセスが終了すれば状態はすべてクリアされる)」と「サービス単位での空間的な可組合性(依存関係はオーケストレーターに任せる)」です。しかし、その代償は甚大でした。再起動するたびにプロセス内のすべての状態(キャッシュ、接続、計算途中の成果物など)を捨てなければならず、再構築には数秒から数分を要します。また、アドレス空間を跨ぐ依存関係は関数呼び出しでは表現できず、ネットワーク経由での通信に頼らざるを得ません。
論文では VS Code を反例として挙げ、この痛点を浮き彫りにしています。人気トップ 100 の拡張機能のうち 87 個には実行可能なコードが含まれていますが、拡張機能のホスト環境は、実行時に単一の拡張機能だけをアンロードすることができません。無効化やアンロードを行うには、ホストプロセス全体を再起動する必要があります。また、deactivate フックが呼ばれるのはホストプロセスが終了する時だけであり、「作成した効果」と「クリーンアップ」の処理が別々の場所で行われるため、関心の分離(コネーン・オブ・コンサーン)という原則に反しています。さらに、拡張機能間の依存関係メカニズム(extensionDependencies)は、解析が型のない any であり、構造的な契約を持たないため、実際に使用されているのはわずか 7 つの拡張機能だけです。
これらの限界は VS Code に特有のものではなく、プラグインシステム全体に共通する課題です。Cordis の目標は、時間と空間という二つの次元における保証を、システムの構造そのものに組み込むことです。
5.2 理論的支柱:effect と coeffect
論文の二大支柱は、プログラミング言語理論における二つの古典的な概念です。
一つ目は effect(効果)です。これは「計算が環境に対して何を行ったか」を記述するものです。ファイルへの書き込み、メモリ割り当て、メッセージ送信などが該当します。この概念は Moggi の monad 理論に由来し、Haskell の IO や代数効果(algebraic effects)、そしてプロセッサ(processor)もこの系譜に含まれます。
二つ目は coeffect(余効果)です。これは「計算が環境に対して何を要求するか」を記述するものです。どの設定を読み取る必要があるか、どのサービスに依存しているかなどが対象となります。この概念は Petricek 氏らによる 2013 年の研究に由来し、effect の双対(対偶)として位置づけられています。
重要な洞察は、これらの概念が従来はコンパイル時の静的解析ツールとして使われてきた点です。型システムはコンパイル時に「このコードがどのような副作用を発生させる可能性があるか」「どのような文脈が必要か」をチェックし、その制約は辞書的スコープ内で固定されていました。Cordis の論文では、これらをランタイムメカニズムへと昇華させ、コンポーネントが随時到着・離脱する動的なシナリオでも機能するようにしました。これが、既存の取り組みとの決定的な違いです。
5.3 可逆的な副作用:「取り消し」を構造的保証とする
5.3.1 コアアイデア:すべての変換には逆変換が伴う
時間次元における要請は、「コンポーネントのアンロード=共有環境への復元」です。論文では effect を以下のようにモデル化しています。
e : Γ → Γ × (Γ → Γ)
これは、effect 関数が現在の文脈(Γ)を受け取り、新しい文脈と逆変換関数(undo 関数)のペアを返すことを意味します。この逆変換をランタイムに委ねることで、effect の追跡が可能になります。そして、その逆変換をランタイムが自動的に組み合わせることで、「復元」は開発者が手動でクリーンアップする仕組みではなく、構造的な保証へと昇華します。
形式的には、効果文脈 ∂Γ = (γ, φ) と定義されます。ここで γ は現在の状態を表し、φ はこれまでのすべての effect の逆変換を合成した累算器です。これにより、track 関数は effect を実行する際に新しい状態を γ に書き込み、その逆変換を φ に合成します。
リカバリ処理では、φを現在の状態に作用させることで、φ(γ) が初期状態 γ₀(論文では「健全性不変量」と呼ばれる)へと戻ります。
逆順の累積(ツイストされた合成)により、「先に実行された効果ほど後に撤销される」という LIFO(後入れ先出し)の仕組みが自然に実現されます。
Cordis におけるすべてのコンテキスト変更は、ctx.effect という単一的原語に集約されています。サービス提供、プラグインのマウント、リスナーの登録などはすべてこの原語の特殊ケースに過ぎません。そして今、その正当性が証明されました。
News to Guide
ニュースの次に確認する
発表内容を、現在の料金や仕様と照らし合わせられる関連ガイドです。
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み