pi-durable-dev-rules について
pi-durable-dev-rulesは、@earendil-works/pi-durableなどを使ってアプリケーションを構築する開発者向けのリファレンススキルです。永続実行、API、ランタイム動作、実装例を扱い、APIは実験的です。
主な機能
- 01ハーネス構成とストレージ選択
- 02会話とタスクのライフサイクル指針
- 03ツールスキーマと実行パターン
- 04クラッシュ復旧とリプレイ安全性
- 05API、ランタイム、レシピの資料
活用シーン
- 01エージェントアプリのハーネス構築
- 02永続タスクやツールコードのレビュー
- 03復旧やタスク停滞の原因調査
- 04実装前のパッケージAPI確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents365-ai/ 365-skills --skill pi-durable-dev-rulesインストール後、Claude Code で/pi-durable-dev-rulesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.skillspector-baseline.yamlassets/workflow-en.drawioworkflow-zh.drawioreferences/codemode-sandbox.mddurable-api.mddurable-guide.mddurable-recipes.mddurable-runtime.mddurable-spec.mdpi-ai-models.mdscripts/build-references.pyREADME.mdrefresh.sh詳細
Pi Durable 開発ルール
@earendil-works/pi-durable は永続化対応エージェントハーネスです。会話、モデルのターン、ツール呼び出し、タスク、および独自のドキュメントは、表示される前にストレージへコミットされるため、ターンの途中でプロセスが停止しても、中断した箇所から再開できます。pi モノレポに @earendil-works/pi-ai(モデルアクセス、ツール、メッセージ)および @earendil-works/chord(追跡対象の JSON 状態)と並んで含まれています。
設計上の選択の大半を左右する点が、2 つあります。
- API は実験的です。 バージョン 1.2.0 はモノレポに追随しており、破壊的変更はリリースのたびに発生します。インストール済みのバージョンに基づいて引用・記述し、シグネチャの違いは誤りではなく、バージョンの違いとして扱ってください。
- エージェント型アプリケーションを構築するためのライブラリであり、コーディングエージェント CLI ではありません。 Pi CLI、その拡張機能、スキル、MCP、および SDK については、関連するスキル
pi-dev-rulesを使用してください。
このスキルを使用する場面
@earendil-works/pi-durableまたは@earendil-works/pi-aiをインポートするコードの作成やレビュー。- ハーネスの組み立て:ストレージバックエンドの選択、
HarnessOptions、設定、レジストリ、実行環境。 - 会話:送信と待機、ビジー時の受信箱(誘導、フォローアップ、書き込み)、リセットと引き継ぎ、フォーク、会話ごとのエージェント変更。
- ツール:TypeBox スキーマ、3 つの出力チャネル、
executeTool()を使ったネストされた呼び出し、callers、deferredツールとツール検索、リプレイの安全性、出力制限、画像の処理。 - 永続化タスク:フェーズとチェックポイント、所有権、待機と
failFast、中断、復旧、移行。 - サブエージェントと子タスク、フォアグラウンドとバックグラウンドの使い分け、回答の報告。
- ドキュメント:スコープ、履歴とフォークのセマンティクス、移行、チェックポイント、観察。
- コードモード(会話のツール上で動作する QuickJS スクリプト)、フックとガード、コンパクション、使用量。
- ランタイムに関する質問:クラッシュ後に何が保持されるか、入力がキューに残っている理由、タスクがブロックまたは孤立する理由、中断がどのように連鎖するか、部分的な回答が表示または欠落する理由。
- ハーネスの拡張:適合性テストスイートで検証されたストレージバックエンドと実行環境、カスタムタスクとプロンプトセクション。
リファレンス一覧:必要なファイルを読み込む
| ファイル | 内容 |
|---|---|
references/durable-guide.md | パッケージ独自のガイドをそのまま収録:クイックスタート、概念、永続化と再開、拡張機能、ツール(ネストされた呼び出しや callers を含む)、コードモード、システムプロンプト、会話ごとのエージェント、設定、環境、再読み込み、監視中の会話、ビジー状態の会話、リセットと引き継ぎ、コンパクション、エージェントイベント、フック、複数の会話とフォーク、アボートとサブエージェント、子タスク、タスクグラフ、独自の状態、使用量とコスト、ストレージ、エラー、実行可能なサンプル。まずここをお読みください。 |
references/durable-api.md | 正確な公開 API:エントリーポイントの一覧、Context、Harness/Session/Conversation/ConversationHandle、送信、Tx トランザクション API、ドキュメント、エントリー、拡張機能とセクション、フック、ツールと ToolExecutionApi、タスクと TaskRuntime、環境、ストレージ、テスト、監視、エラークラス、およびサブパスごとのエクスポート一覧 |
references/durable-runtime.md | 実際の処理の実行方法:コミットラインとそのルール、1 つの入力の一連の処理、タスクのチェックポイント、所有権ツリー、ケースごとの復旧、コンパクション、受信トレイの境界、ライブ状態と進捗の間隔、障害モデル、動作を変える設定項目、意図的に対象外としている項目 |
references/durable-recipes.md | プロジェクトのセットアップ、実行可能な全 32 サンプルの一覧、コード付きの 19 のレシピ:最小限のチャット、永続化と入力の厳密に 1 回の処理、ライブ UI、エージェントイベント、構造化出力ツール、ツール呼び出しツール、フォアグラウンドとバックグラウンドのサブエージェント、永続的な待機を伴う子タスク、コーディングエージェント、計画モード、会話ごとのサンドボックス、ツールのオーバーライドとラッパー、拡張機能の状態と移行、フック、コンパクション、コードモード、ツール検索、適合性テスト、および落とし穴のチェックリスト |
references/durable-spec.md | Pico5 仕様をそのまま収録した規範文書(5340 行):レコードとライフタイム、ドキュメントと変更の所有権、トランザクションとストレージの所有権、タスクとエフェクトサンドイッチ、構造化並行処理、送信と受信トレイ、拡張機能/フック/ツール、組み込みタスク、ドキュメントの監視、ストレージ契約と障害モデル、バックエンド、API 使用時の注意点、および対象外項目。リリース前にセクション 12 をお読みください |
references/pi-ai-models.md | モデルレイヤーをそのまま収録:createModels()/builtinModels()、プロバイダーファクトリーと認証、モデルカタログの照会、環境変数、TypeBox を使ったツールの定義、制約付きサンプリング、イベントリファレンス、画像入力、使用量とコスト、再試行、および最終的にエントリーに格納されるメッセージ型 |
references/codemode-sandbox.md | @earendil-works/pi-codemode をそのまま収録:スクリプトから呼び出せるもの、注入されるグローバル、サンドボックスのモジュール API、決定性とメモリ制限、ローカルとリモートのサンドボックス |
チートシート
npm install @earendil-works/pi-durable @earendil-works/pi-ai @earendil-works/chord
node --conditions=source --experimental-strip-types app.ts # run TS directly against the source
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
import { builtinModels } from "@earendil-works/pi-ai/providers/all";
import { createRegistry, Harness, AssistantEntry } from "@earendil-works/pi-durable";
import { openNodeSqliteStorage } from "@earendil-works/pi-durable/storage/sqlite/node";
const context = BACKGROUND_CONTEXT;
const harness = await Harness.open(await openNodeSqliteStorage("./session.sqlite"), {
models: builtinModels(), registry: createRegistry(), env: (target) => new NodeExecutionEnv({ cwd: target.cwd ?? process.cwd() }),
}, context);
const root = await harness.root(context, { agent: { model: { provider: "openai", modelId: "gpt-6-sol" } } });
harness.resume(); // continue unfinished work from a previous process
const submission = await root.submit({ type: "input", content: "Hello", requestId: "greeting-1" }, context);
const settled = await submission.wait(context); // "done" | "unanswered"
if (settled.status === "done" && settled.type === "input") {
const answer = await root.commit((tx) => tx.entry(AssistantEntry, settled.answer), context);
}
await harness.close(context);
ストレージ:MemoryStorage(何も永続化されません)、openNodeSqliteStorage(path)(長時間稼働するあらゆる用途でのデフォルト。WAL により、プロセスのクラッシュ後もコミットが維持されます)、openNodeJsonlStorage(directory, context)(追記専用で、履歴全体をメモリに保持します)、openDurableObjectSqliteStorage(ctx.storage)。
1 つのストレージを同時に所有できるのは、1 つのプロセスのみです。
厳守すべきルール
- 書き込みは単一のコミットラインを通り、コミットが保存されるまでは何も表示されません。 コミットコールバック内では
tx経由でのみ読み取り、必要なテーブル行はすべて最初のテーブル書き込みより前に読み取ってください (ReadAfterWrite)。また、その中で時間のかかる処理を待機してはいけません。モデル、ツール、プロセス、ネットワーク、人間、ネストしたコミット、セッションの待機処理は禁止です。 - すべての非同期呼び出しには
Contextが必要です。 キャンセルしてもキャンセルされるのはその呼び出しまたは待機のみで、永続的な処理はキャンセルされません。キャンセルさせたくない場合はBACKGROUND_CONTEXTを使い、ホスト境界ではwithCancel()を使います。withoutAbortSignal()はclose()など、必ず実行するクリーンアップに使用します。 - 実行内容の報告は、コミット後に行ってください。 タスクの各ステップでは、意図をコミットし、処理を実行してから、結果をコミットします。処理の実行後にコミットする前にクラッシュすると、そのステップは再実行されるため、ステップを冪等にし、最初に書き込んだ値を優先する判断には
runtime.memo()を使い、再実行して本当に安全な場合に限ってツールにreplay: "safe"を設定してください。安全でないツールが中断されると、ここまでにコミットされた出力とともに、モデルにはinterruptedエラー結果が返されます。 - ツールには3つの出力チャネルがあります。
outputはモデルが読み取る内容、structuredOutputはツールを呼び出すプログラムが読み取る内容(structuredOutputSchemaに照らして検証され、結果がエラーでない限り必須)、detailsはホスト UI 用です。トランスクリプトに入るのはoutputとdetailsのみです。 - 各ツール呼び出しは、呼び出し元が所有する独立した永続タスクです。
api.executeTool()で行ったネストした呼び出しは、結果をトランスクリプトではなく呼び出し元に返し、再実行時には同じキーを再利用します。コンテキストをキャンセルしても、待機のみが停止します。ネストした結果のusageはすでにそのツールの使用量として計上されているため、転送すると二重計上になります。 - 所有権によって存続期間が決まります。 各タスクは作成時に所有者を指定します。各会話は所有者なし、またはタスク所有です。中止は所有者からその配下に伝播します。タスクは、通常の所有対象作業が完了してから終了し、それまでは
completingとして保存されます。background: trueのタスクは境界となり、通常の中止やアイドル待機では処理されません。中止ハンドラーから所有対象の作業を作成してはいけません(タスクには中止済みの印が付いています)。インラインで補償するか、会話所有のバックグラウンドタスクとruntime.waitForTask()を使ってください。 - 実行はそれ自身の書き込みを所有します。 実行中の会話に生のエントリーを追加しないでください。生の
tx.appendEntry()では置き換えられず、古さのチェックも実行する書き込み送信を使ってください。 pi.で始まる名前は、タスク名、ドキュメント種別、エントリー種別について組み込み機能が使用します(pi.user、pi.assistant、pi.system、pi.tool-result、pi.reset、pi.compaction、pi.agent、pi.provider、pi.live、pi.inbox、pi.usage、pi.generation、pi.tool)。使用を強制する仕組みはなく、再利用するとハーネスの動作と衝突します。- ストレージエラーが発生すると、ハーネスは終了します。 エラーになった呼び出しは拒否され、それ以降のすべての呼び出しと保留中の待機も
SessionFailedで拒否され、監視はsession_failedで終了し、onReportにはエラーが一度だけ渡されます。再試行は行われません。復旧するには再度開き、同じrequestIdで再送信してください。無効なリクエストで失敗するのはその呼び出しのみ(StorageRequestError)で、独自コードで失敗するのはそのコードのユニットのみです。 - ドキュメントはオブジェクトではなく種別で識別されます。 種別と表示名は永続化されるプロトコルです。値のマイグレーションでは種別の名前を変更できません(コピーして古い方を廃止してください)。また、保存されたバージョンがコードより新しい場合、または
migrateがない状態で古い場合は、アクセスに失敗します。存在しないドキュメントを作成できるのは、型付きのtx.doc()のみです。 snapshot()、ドキュメントの状態、監視から取得する値は、追跡対象のコンテナーです。 決して変更せず、まずコピーしてください。監視では、未配信のフレームが最大100件まで保持され、それを超えると全値を置き換える単一のフレームにまとめられます。すべての遷移を確認する必要があるコンシューマーは、自らジャーナルに記録してください。- 拡張機能は全体単位で選択されます。 フックとラッパーが適用されるのは、その拡張機能が選択されている場合のみです。そのため、ツールを明示的な配列として選択し、ガードを含めない会話では、ガードなしで実行されます。ラッパーは純粋でなければなりません。拡張機能をアンインストールすると新たな使用は停止しますが、実行中の呼び出しが使用するリソースは解放されません。
- プロンプトのセクションは安定していなければなりません。 実際の内容に変更がないのにテキストが変わるセクション(時計やランダム値など)は、リクエストのたびに
pi.systemエントリーを追加し、プロバイダーのプロンプトキャッシュを無効にします。設定はゲッターにできます。設定は使用するたびに読み取られ、保存されることはありません。 - API は実験的なものであり、Pico5 仕様は設計文書です。 動作については
references/durable-guide.mdを、ルールが重要な場合はreferences/durable-spec.mdを読み、本番公開の前に仕様のセクション12(API の落とし穴)を確認してください。