DeepSeek Harness: すべてがプラグインになっているオープンソースのエージェントフレームワーク
エージェントスタックがまるごと GitHub に公開
DeepSeek は 2026 年 8 月 13 日、DeepSeek Harness(dsh)のデベロッパープレビューを公開した。リポジトリは deepseek-ai/deepseek-harness にある。当日の終わりには スター 1.6k、コミット 12,293、コントリビューター 19 人 — この数字から、週末の趣味プロジェクトではないことがわかる。コードベースは TypeScript 97.1%、CSS 1.6%、Python 0.7%。公開時のパッケージバージョンは 0.1.0-rc.5。
ランディングページは deepseek.com/harness、開発者ドキュメントは deepseek-harness.github.io/deepseek-harness。
ライセンスは MIT。
一行で説明すると
README から引用:「Agent = Model + Harness.」
モデルは魂。ハーネスはエージェントに環境を理解し、ツールを使い、現実の設定で動き続ける能力を与える。DeepSeek の考え方:モデル、ツール、スキル、セッション、サンドボックス、ストレージ、ループ、スケジューリング、UI — あらゆる機能が差し替え可能なプラグインになっている。
これはスローガンではない。アーキテクチャで強制されている。
Cordis:すべての下にあるカーネル
DeepSeek Harness は Cordis というベンダードされたプラグインフレームワークの上に構築されている。Cordis の設計は A Programming Paradigm for Spatiotemporal Composability という論文で説明されている。
フレームワーク全体は 5 つの考え方に還元される:
- プラグインは Service を実装したオブジェクト。
injectとapply(ctx)を持つ関数、またはServiceのサブクラスとして実装できる。 - コンテキストはサービスのリポジトリ。 プラグインは
ctx.tools、ctx.llm、ctx.sessionsのような安定したキーを要求する。他のプラグインは具体的な実装をインポートするのではなく、キーでサービスを探す。 injectでサービスの依存関係を宣言。 必要なサービスを指定したプラグインは、それらのサービスが使用可能になるまで待つ。手動で起動順序を制御する必要はない。- 通信用の型付きイベント。 4 つの配信モード:
emit(発火して忘れる)、waterfall(next()を使うミドルウェア風)、parallel(全リスナーが並行実行)、serial(リスナーが順番に実行され、戻り値を持つ)。 - 登録は可逆可能な効果。 プロンプトセクション、ツールスキーマ、アダプタ、リスナー — すべてが
ctx.effect()を通じてインストールされるので、リロードや終了時に予測可能な形で解除される。
Cordis の waterfall モデルは周囲を取り巻くミドルウェアだ。リスナーは (...args, next) を受け取る。next() を呼ぶと次のサービスに委譲し、next() なしで戻るとショートサーキットする。単一決定のイベントでは、ショートサーキットが設計そのもの — ポリシーリスナーが決定を完全に所有できる。
すべてがプラグイン(マジで)
deepseek.com/harness のプラグインリストが、全機能範囲を明らかにしている:
- Models — LLM バックエンド(DeepSeek、OpenAI、Anthropic、Bedrock、Vertex、Azure、Codex、その他 OpenAI 互換エンドポイント)
- Tools — モデルが呼び出せるもの
- Skills — 再利用可能なプロンプトとツールのバンドル
- Sessions — 会話状態管理
- Sandboxes — コードの実行場所(PTY bash、
danger-full-accessローカルバックエンド、landlock ベースのネイティブサンドボックス) - Storage — セッションの永続化
- Loops — エージェントのターンロジック
- Scheduling — サブエージェントとタスクのディスパッチ
- UI — デフォルトでポート 3080 で起動する Web UI
開発者はこれらのいずれも設定で選択、差し替え、拡張できる — DeepSeek Harness 自体のソース変更は不要。Plugin Config Catalog はソース(scripts/gen-config-catalog.ts)から自動生成され、CI で随時検証されるので、cordis.yml の config: ブロックの各フィールドは、プラグインが宣言した設定型と完全に一致する。
4 つのランタイムモード
ドキュメントには 4 つのプリセットが付属する。それぞれ異なるユースケースを対象としている。
Standard Mode — フルコーディングエージェント:ファイル編集、シェル、ファイル・Web 検索、スキル、計画、ゴール、サブエージェント、ワークフロー。デフォルトの Web UI 体験はこれ。
Code Mode — Standard の機能に加え、ツールが Code Mode SDK 経由で公開されるので、モデルは複数ステップの操作を 1 つの TypeScript プログラムにまとめられる。モデルが生成した 1 つのプログラムで、数ラウンドのツール呼び出しを置き換える。
Minimal Mode — ツールは 2 つだけ:持続的な bash シェルと str_replace_editor。簡素化された環境でモデルをベンチマークするためのもの。スキル、計画、サブエージェントはなし — 実際のコードベースに対する生のモデル能力だけ。
Creator Mode — カスタムエージェントプリセットを書くために設計。Standard モードの全機能に加え、ランタイムインスペクション、メモリ上での Cordis プラグイン実験、プリセット作成ガイダンスを含む。5 番目、6 番目、7 番目のモードを作るのはこれ。
すべての実行が追跡可能
ここが Harness を他の大半のエージェントツールと分ける点。モデルが見るものはすべて、追記型セッションログに記録される:
- システムプロンプト
- 推論出力
- ツール呼び出しとその結果
- サブエージェントのスケジューリング決定
- すべてのコンテキスト注入
Web UI には Trajectory ビュー があり、ソースでフィルタリングしてこれらのレコードを検証できる。再開、分岐、検索、リプレイ — これら 4 つの操作はすべて同じイベントストリームに対して動作する。別のトレース DB も、エクスポート手順も不要。セッションの JSONL 自体が単一情報源。
Python SDK の場合、セッションディレクトリには、組み立てられたモデルリクエストとツール呼び出しを含む非圧縮 JSONL が保存される。examples/jsonrpc-agent/minimal.py の例が、この一連の流れを端から端まで示している。
モデル設定:DeepSeek + 何でも
モデル設定ページ(モデル設定)には 3 つのレイヤーがある。
DeepSeek 公式。 Settings → Models を開き、DeepSeek API キーをペーストして保存。キーは書き込み専用。保存後、UI は平文ではなく、削除処理が施された記述子を受け取る。キーは \$DSH_HOME/.credentials.yaml に保存され;設定ページはクレデンシャル参照のみを保持する。
カタログプロバイダ。 「Add provider」をクリックし、Anthropic または OpenAI を選び、キーをペースト。ネイティブ認証を使うプロバイダ(AWS クレデンシャル + リージョン経由の Bedrock、ADC プロジェクト経由の Vertex、api-version 経由の Azure、OAuth 経由の Codex)は、API キーフィールドだけでは動作しない — それぞれ独自の認証パスが必要。
カスタムプロバイダ。 企業のゲートウェイ、セルフホストサーバー、カタログにないプロバイダ向け。小文字の Provider ID(恒久的 — リクエスト、保存されたセッション、モデルのデフォルト、クレデンシャル参照がすべてこれを使用)、ベース URL、API プロトコル、クレデンシャル、少なくとも 1 つのモデルを設定する。
ビジュアルモデルには追加の手順が必要。カスタムエンドポイントはサポートするモダリティを通知する方法がないため、フォームはビジョンサポートを自動検出できない。\$DSH_HOME/settings.yaml のモデルに input: [text, image] を追加する。カスタムモデルがすべて画像を受け入れるなら、モデルごとではなくプロバイダレベルで defaultInput: [text, image] を 1 回設定すれば済む。input フィールドは表明であり、チェックではない — モデルがビジョン対応だと主張してもエンドポイントが実際には対応していない場合、Harness ではなくプロバイダがリクエストを拒否する。
トラブルシューティングはドキュメントに直接記載されている:
MISSING_CREDENTIAL→ Models ページからプロバイダキーを保存するか、参照されている環境変数をエクスポートUNKNOWN_MODEL→ 設定済みのモデルを選ぶか、不足しているモデルをカスタムプロバイダに追加- 「Get available models returns 401」→ キーを確認。モデル検出は OpenAI 互換の
GET /modelsエンドポイントを呼び出す。サービスがこれを公開していない場合、手動でモデルを入力する。 - 「Image rejected before send」→ モデルが
imageモダリティを宣言していない。input: [text, image]を追加。 - 「Provider rejects a request with an image」→ モデルがビジョン機能を主張したが、エンドポイントには実際にはない。リストから
imageを削除し、新しいセッションを開始する(古い画像はセッションログに残り、同じリクエストを繰り返し続ける)。
入門:3 つのパス
パス 1:npx @deepseek-ai/dsh web
Node.js をインストールし、1 つのコマンドを実行。Web UI が http://127.0.0.1:3080 で起動する。以上。クローンもビルドも pnpm も不要。
npx @deepseek-ai/dsh webその後:Settings → Models → DeepSeek API キーをペースト。ワークスペースを選ぶ(dsh を起動したディレクトリで OK)。セッションを開始:
このリポジトリを要約し、主要なパッケージを特定してください。
エージェントはワークスペースのファイルを読み書きし、コマンドを実行し、作業を委譲し、計画を維持する。アクティブな権限ポリシーで承認が必要な操作は、実行前に Web UI でダイアログが表示される。
パス 2:ソースからクローンしてビルド
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspnpm installpnpm run buildpnpm dsh webパス 3:Python SDK
必要条件:Python 3.10+、Linux x64 / Linux arm64 / macOS 14+ on arm64、DeepSeek 互換エンドポイント。
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspython -m venv .venv. .venv/bin/activatepython -m pip install deepseek-harness-sdkクレデンシャルを設定:
export DEEPSEEK_API_KEY=sk-your-key-here# 任意:# export DSH_MODEL=deepseek-v4-flash# export DSH_SYSTEM_PROMPT='You are a helpful software engineer assistant.'隔離されたワークスペースでタスクを実行:
python examples/jsonrpc-agent/minimal.py \ --workspace /absolute/path/to/workspace \ --session-root /absolute/path/to/sessions \ --session-id example-001 \ "Inspect the repository and fix the failing tests."自作コードでは、SDK のエントリーポイントはコンテキストマネージャとしての DeepSeekHarness:
from pathlib import Pathfrom deepseek_harness import DeepSeekHarness
config = Path("examples/jsonrpc-agent/minimal.cordis.yml").resolve()workspace = Path("/absolute/path/to/workspace").resolve()sessions = Path("/absolute/path/to/sessions").resolve()
with DeepSeekHarness( provider="deepseek-official", model="deepseek-v4-flash", max_tokens=49_152, cwd=str(workspace), session_root=str(sessions), cordis=str(config),) as harness: result = harness.run( "Inspect the repository and fix the failing tests.", session_id="example-001", ) print(result.final_response)DeepSeekHarness はバンドルされたランタイムを遅延起動し、with ブロックが終了するまで再利用する。同じセッション ID を再利用すれば Bash プロセス(作業ディレクトリ、環境変数、シェル関数)が維持される。独立したタスクには新しいセッション ID を使う。
jsonrpc-agent の最小構成は意図的に質素:モデル向けツールとして持続的な bash と str_replace_editor のみ。Bash のタイムアウトは 300 秒。エディタの出力上限は 16,000 文字。コンテキスト圧縮は無効。ファイルシステムは素のローカルバックエンドを使用 — エディタのパスはランタイムプロセスから見えるものなら何でも参照できる。ドキュメントは明示的に警告している:「使い捨てのチェックアウトまたはコンテナ内でのみ実行してください。」持続的な PTY バックエンドは POSIX 端末基盤も必要 — この構成では Windows はサポートされない。
最初のプラグインを書く
チュートリアル:最初のプラグイン。プラグインは apply 関数をエクスポートする TypeScript モジュール:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) { console.log('[hello-plugin] plugin loaded!')}cordis.yml パッチに登録:
- insert: - id: hello name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'オーバーレイ付きで起動:
pnpm dsh web --patch ./scratch-plugin/cordis.yml自動クリーンアップが最高の機能だ。ctx を通じて登録されたもの — イベントリスナー、ツール、タイマー — はすべて、プラグインのアンロード時にクリーンアップされる。手動で removeListener や clearInterval する必要はない。明示的なクリーンアップ(ネットワーク接続など)が必要な場合は、ctx.effect() からディスポーザーを返す。
依存関係は inject で宣言:
export const name = 'my-tool-plugin'export const inject = ['tools']
export function apply(ctx: Context) { // ctx.tools はここで準備完了}Cordis は、必要なサービスがすべて揃うのを待ってからプラグインをロードする。
プラグインの形式は 3 つある:関数(上記)、apply を持つオブジェクト、Service を継承するクラス。プラグイン自体が他のプラグインに消費されるサービスを提供する場合は、クラス形式を使う。
最初のツールを書く
チュートリアル:ツールを作る。@deepseek-ai/dsh-tools から defineTool を使う:
import type { Context } from '@deepseek-ai/cordis'import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'export const inject = ['tools']
export function apply(ctx: Context) { ctx.tools.register(defineTool({ name: 'greet', description: 'Greet someone by name.', parameters: { name: { type: 'string', required: true, description: 'The name to greet', }, }, output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }], }, async execute(args) { return `Hello, ${args.name}!` }, }))}defineTool は parameters から args を推論して検証する。execute は output.schema で宣言された正準値を返す。output.render はその正準値をモデル向けコンテンツに変換する。パッチを当てて再起動したら、Web UI に「Use the greet tool to greet Ada.」と問いかける。モデルは greet を呼び出し、Hello, Ada! を受け取る。
チュートリアルの次のステップは、プラグイン設定、ツール作成リファレンス(ネストされたスキーマ、正準値、バックグラウンド処理、ポリシーフック、Code Mode、UI カード)、機能レイヤリング(サービス定義 → サービスプロバイダ → コンシューマパッケージの分割)だ。
CLI エントリーモード
@deepseek-ai/dsh コマンドはプロダクトランチャー。4 つのエントリーポイント:
| コマンド | 目的 |
|---|---|
dsh --profile <name> |
\$DSH_HOME/profiles/<name> 配下の指定プロファイルを起動 |
dsh --profile headless "job" |
新規の持続セッションを 1 つ実行し、最終回答を表示して終了 |
dsh web |
--profile web のエイリアス |
dsh plugin --profile <name> <pnpm args> |
pnpm にフォワードしてプロファイルのプラグインを管理 |
起動ディレクトリがデフォルトのワークスペースルートになる。web と headless のプロファイルは初回使用時に付属テンプレートから自動初期化される。その他のプロファイルは dsh plugin で作成する必要がある。
ランチャーフラグは最初に置く。ランチャーが認識しない最初のトークンがアプリの引数になる。例:dsh --profile web --port 8080 は --port 8080 をランチャーではなく Web アプリに渡す。
プロファイルディレクトリには package.json(ツリー外のプラグイン依存関係と、順序付けられた bundles リストを持つプロファイルマニフェスト dsh.profile)と cordis.patch.yml(ユーザー自身のパッチレイヤー)が格納される。空のルートに対する合成順序は:dsh.profile.bundles 順の各バンドルのパッチ → プロファイルの cordis.patch.yml → ホームレベルの \$DSH_HOME/cordis.patch.yml → --patch オーバーレイ。--dump-default-config と --dump-config を使うと、起動せずに合成されたツリーを検査できる。
コミュニティプラグインとエコシステム
発見性のため、GitHub でプラグインリポジトリに dsh-plugin のタグを付ける。公式サイトはこのトピックページに直接リンクしている。ディスカッション用に DeepSeek Harness Discord コミュニティもある。
プロジェクトはフィードバックとバグ報告に GitHub Discussions を使用。ドキュメントからは、開発ワークフローの CONTRIBUTING.md、システム設計の architecture.md、エージェント固有のコーディング規約の AGENTS.md にリンクされている。
デベロッパープレビュー — 壊れるのは確定
README には全大文字でこう書かれている:「互換性を壊す変更が入ります。」
コアプラグインと API はまだ進化中。ランディングページにも直接記載がある:「DeepSeek Harness はデベロッパープレビューのままであり、エージェントハーネスを構築する開発者によってテストが続けられています。」
上に構築するなら、コミットハッシュを固定し、設定カタログに対してプラグインを薄く保ち、rc が上がるたびに再テストする覚悟が必要。プラグインの自動クリーンアップと依存性注入により、モノリシックなフレームワークより再テストは苦痛ではなくなるが、「デベロッパープレビュー」は文字通りの意味だ。
何が違うのか
今のエージェントフレームワークの大半は、ターンループから始めて、拡張性を後付けする。Harness はそれを逆にする:拡張性こそがフレームワークであり、ターンループはただの別プラグインに過ぎない。観察できる結果として、通常は 1 つのパッケージで得られない 3 つのことが実現されている:
- フォークなしで何でも差し替え可能。 組み込みのツールシステムが気に入らない?置き換えればいい。別の LLM ルーティングレイヤーが欲しい?プロバイダを差し替えればいい。すべて Cordis サービスキーを通じて解決される。
- デフォルトで追跡可能。 追記型ログはオブザーバビリティのアドオンではない。セッションの仕組みそのものだ。再開、分岐、検索、リプレイはすべて同じストリームを使用する。
- 機能フラグではなく、合成可能なプリセット。 4 つのモード(Standard / Code / Minimal / Creator)は、順序付けられたプラグインバンドルのパッチレイヤーに過ぎない。コードではなく YAML で、自分のプリセットを上に重ねられる。
このアプローチがモノリシックな SDK に勝つかどうかは、差し替え・再合成のストーリーを現実のものにするだけのサードパーティ製ツールとプロバイダが、プラグインエコシステムから生まれるかどうかにかかっている。初日で 1.6k スター、12k コミットなので、勢いは明らかにある。
参考
- DeepSeek Harness ランディングページ
- GitHub 上の deepseek-ai/deepseek-harness
- 開発者ドキュメント クイックスタート
- モデル設定ガイド
- Python SDK ガイド
- 最初のプラグイン チュートリアル
- ツールを作る チュートリアル
- Cordis 入門
- プラグイン設定カタログ
- CLI README
- GitHub 上の Cordis
- Cordis 論文:A Programming Paradigm for Spatiotemporal Composability
- GitHub コミュニティ dsh-plugin トピック
- DeepSeek Harness Discord