Dunstan について
Dunstanは、コーディングエージェントのプルリクエスト報告に含まれる主張を、決定論的なルールでGitHubのリポジトリ記録と照合します。エージェントの作業をレビューするチーム向けで、記録から確認できない主張は検証不能となり、判定にモデルは使いません。
主な機能
- 01PR記録に基づく宣言済み主張の確認
- 02ファイル、コミット、CI実行の調査
- 03裏付けのない主張を検証不能として表示
- 04再現可能な検証記録の作成
- 05報告にない主張の候補提示
- 06MCPサーバーとGitHub Actionの提供
活用シーン
- 01エージェントが報告したファイルとHEADコミットを確認
- 02記載されたテストとプルリクエスト状態を確認
- 03PR完了を報告する前に主張をレビュー
- 04ブランチ保護の必須チェックとして実行
MCP 対応
`dunstan_check_handback`と`dunstan_suggest_declarations`をMCPツールとして提供します。エージェントは宣言済みの報告ブロックを検査し、本文中で宣言されていない主張を特定できます。判定はGitHubの記録に対する決定論的なチェックに基づきます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
2掲載時のツール一覧 · 4 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| block | object | いいえ | JSON オブジェクト形式の dunstan-handback ブロック。これかレポートのどちらか一方を指定してください。 |
| report | string | いいえ | レポート本文。```dunstan-handback フェンスをちょうど 1 つ含めてください。これか block のどちらか一方を指定してください。 |
| outPath | string | いいえ | レコードをこのパスに書き込みます(パスは存在していてはいけません)。指定しない場合、何も書き込まれません。 |
| repository | string | はい | GitHub リポジトリ(owner/name)。 |
| pullRequest | integer | はい | この handback の対象となる pull request 番号。 |
詳細
Dunstan
Dunstan は、コーディングエージェントの完了報告を記録に残します。
エージェントは作業を終えると、変更したファイル、実行したテスト、クローズした参照、HEAD コミット、マージ日時を引き継ぎ報告に記します。Dunstan はその報告で宣言されたブロックを読み取り、各主張をリポジトリ自体の記録(プルリクエストの状態、変更されたファイル、コミット、CI の実行)と照合し、決定論的なチェックを行います。誰でも自分のマシンで再実行して同じ判定を得られる記録を作成します。
- 合否を判断するモデルはありません。
- フェイルクローズです。記録で確認できない主張は、根拠がないからといって合格にせず、
unverifiableとします。 - ゲートではなく証拠です。Dunstan は記録を返します。何をブロックするかは、ブランチ保護で決めます。
主張の形式、エージェントが宣言するブロック、Dunstan が作成する記録は、オープンな仕様として公開されています。spec/claim-format.md、JSON Schema は spec/schema/ に、例は spec/examples/ にあります。記録は in-toto Statement です。in-toto、SLSA、PER における位置づけと、引き継がれない内容については、docs/interop.md を参照してください(参考情報。エクスポート機能はありません)。
Claude で使う
Dunstan は Claude Code プラグインとして提供されます。2 つの MCP ツールと、完了を宣言する前に Claude がプルリクエストの引き継ぎ内容を宣言、確認、報告するスキルが含まれます(plugins/dunstan/)。
インストール。 Claude Code で次を実行します。
/plugin marketplace add BargLabs/dunstan
/plugin install dunstan@barglabs
このプラグインは、npx -y [email protected] mcp を使って MCP サーバーを起動します。これは同じバージョンの dunstan npm パッケージです。依存関係のない、単一ファイルで完結したパッケージです。
トークン。 プラグインを有効にすると、Claude Code は任意の GitHub トークンを求め、安全なシステム資格情報ストアに保存します。読み取り専用権限を持ち、チェック対象のリポジトリのみに限定され、有効期限が設定された、細粒度の個人アクセストークンを使用してください。必要な権限は docs/mcp.md に記載されています。公開リポジトリを匿名で読み取る場合は、空欄のままにします。GitHub の GraphQL API は匿名の呼び出しを拒否するため、トークンがない場合、closes 参照は fail ではなく unverifiable になります。プラグインが環境変数からトークンを読み取ることはありません。
読み取る内容と取得元。 サーバーはお使いのマシン上で動作し、そのマシンから GitHub の API に直接アクセスします。対象はプルリクエスト、変更されたファイル、コミット、チェックの実行、ワークフローの実行とテスト成果物、デプロイ、およびブロックが参照するイシューです。すべて読み取り専用のリクエストです。GitHub やリポジトリに何かを書き込むことはなく、Barg Labs に情報が送信されることもありません。
試してみる。 Barg Labs の公開プルリクエストを使った 3 つのプロンプトです。
Use Dunstan to check this handback for BargLabs/cejel#408: head commit 35d6201d00cf926f9af10df61bfec05b6624ee12, files changed .github/workflows/verify-published-windows-binary.yml and scripts/validate-distribution-metadata.mjs, merged at 2026-10-04T13:30:48Z.すべての主張が確認できるため、判定はpassになります。Before I report BargLabs/cejel#408 as done, use Dunstan to list the claims in this report that my handback block does not declare:に続けて、報告とそのdunstan-handbackブロックを入力します。Dunstan は、テスト件数やclosesなど、ブロックに記載されていない報告内の各主張を、それを宣言するフィールドとともに列挙します。これは判定ではありません。Use Dunstan to check whether BargLabs/cejel#408 closes #407, with head commit 35d6201d00cf926f9af10df61bfec05b6624ee12 and the same two files.トークンがない場合、closesの行はunverifiable(source_unreadable:closing_references)になります。記録だけでは判断できなかったという意味であり、偽であることとは異なります。トークンがあればpassになります。
サポート。 GitHub のイシューまたは [email protected] までお問い合わせください。 プライバシーおよび利用規約。
チェッカー
pnpm install && pnpm build # writes dist/dunstan.mjs and prints its SHA-256
# Check a pull request against the report it names (exactly one report source).
GITHUB_TOKEN=... dist/dunstan.mjs check --repo <owner/name> --pr <n> --report-pr-body --out record.json
# or --report-file <path|->, or --report-comment-author <login> (that author's latest comment)
dist/dunstan.mjs verify record.json # offline: recompute claims, verdict and digests
dist/dunstan.mjs rerun record.json # online: re-read the sources, report evidence_changed
終了コード:0 は合格、1 は不合格、2 は検証不能、3 は記録なしです。使用方法の誤り、読み取れないプルリクエスト、チェック中に変更され再チェック時にも移動していたプルリクエスト(pull_request_moved)、または内部エラー(verify:0 は検証済み、1 は未検証)が該当します。
--sign-key <path> --signer <principal> は、記録を JCS バイト列として、SSH の分離署名とともに書き込みます。verify --sig <file> --allowed-signers <file> で検証します。
dist/dunstan.mjs mcp は同じチェッカーを MCP ツール dunstan_check_handback として提供します。エージェントは完了を宣言する前に、ブロックを渡してこれを呼び出せます。また、dunstan_suggest_declarations(下記)も利用できます。
docs/mcp.md。
記録内の checker.digest は、実行された単一ファイルのバンドル dist/dunstan.mjs の SHA-256 です。このバンドルには、チェッカーのコードと依存関係、およびビルド時にインライン化された spec/schema/ の両方のスキーマが含まれます。
Dunstan がチェックしないこと
Dunstan は、ハンドバックで宣言された主張を記録と照合します。ハンドバックが課題で求められた内容を網羅しているかはチェックしません。誤った作業を正確に報告した場合でも、合格します。
宣言する内容については、docs/agents.md を参照してください。
完了前に宣言する
宣言された主張のチェックは正確です。読み手がつまずくのは、文章から主張を見つけ出すところです。適切な段落が与えられれば、ホスト型モデルの判定者が誤報を見逃す数は大幅に減ります。また、Dunstan 自身の抽出器も、テスト対象として埋め込まれた誤った主張を見逃しました。どちらもチェックではなく、読み取りで失敗します。レポートを書いたエージェントが最適な読み手であり、ハンドバック前ならまだ対応できます。そこで Dunstan は、ブロックをほぼ手間なく書けるようにし、ブロックでカバーされていない文章について作成者に確認します。
dist/dunstan.mjs template # the block for HEAD, filled from local git
dist/dunstan.mjs suggest --report-file report.md # prose claims the block does not declare
template は headCommit と filesChanged(HEAD と、リモートのデフォルトブランチとのマージベース、または --base との比較)を入力します。また、tests は JUnit ファイルと、それに名前が記載された CI 記録からのみ入力します。references と mergedAt は入力せず、git で判定できない場合はブロックを出力しません。suggest はフェンスの外にある文章に対して助言用の抽出器を実行し、ブロックで宣言されていないと判断した各主張を一覧表示します。主張を宣言するか、言い換えてください。これは判定ではなく、記録には何も書き込まず、常に終了コード 0 を返します。MCP サーバーでは dunstan_suggest_declarations として提供されます。手順、AGENTS.md または CLAUDE.md にコピーする指示ブロック、および出力例については、docs/agents.md を参照してください。
GitHub Action
ワークフローの 1 ステップと、ブランチ保護で必須にする 1 つのチェックで構成されます。
permissions: { contents: read, pull-requests: read, issues: read, deployments: read, checks: write, actions: read }
steps:
- uses: BargLabs/dunstan@<full commit SHA>
with:
report-source: pr-body # or comment:<author-login>, or file:<path>
HEAD コミットに dunstan チェック実行を作成します。その概要は主張の表で、記録はアーティファクト dunstan-record として保存され、同じ表がジョブの概要にも表示されます。pass のみが success となります。fail、unverifiable(unverifiable-conclusion: neutral を設定した場合を除く)、およびすべてのエラーは failure となります。コメント、ラベル、レビュー、マージは行いません。セットアップ、ブランチ保護の設定、各結論の意味については、docs/action.md を参照してください。
ホスト型プラン
ローカルツールに加えて任意で利用できるプランです。ローカルツールがこれを利用することはありません。レポートまたはブロックとプルリクエストを指定して POST /v0.1/check を実行すると、Barg Labs の読み取り専用 GitHub App がそのプルリクエストのメタデータを読み取ります(ファイルの内容は読み取りません)。同じチェッカーが SSHSIG で署名された記録を返し、dunstan verify をオフラインで再実行して同じ判定を確認できます。記録はデフォルトで 90 日間保持され、レポートのテキストは保持されません。読み取り・保持される情報、Contents の読み取り権限に関する注意点、API については、docs/hosted.md を参照してください。Worker は hosted/ にあります。プロビジョニングとデプロイは運用担当者が行います(docs/runbooks/hosted-provisioning.md)。
読者の主張の検索(DRAFT)
文章によるレポートでは、読者がテキストを型付きの主張に変換し、Dunstan は各主張がどの記録項目について述べているのかを特定する必要があります。src/retrieval/ はモデルを使わずにこれを行います。まず完全一致する識別子を検索し、次に BM25 を使い、明示された下限を適用します。検索で提示されるのは候補だけです。チェックは記録に保持された候補に基づいて判断するため、dunstan verify では再検索せずに判定を再現できます。dunstan-eval retrieval は k = 5 での再現率を測定します。記録形式は DRAFT 0.2.0 で、まだ確定していません。詳細は docs/retrieval.md を参照してください。
文章からの勧告(DRAFT)
dunstan check --advisory、または Action の advisory: true を指定すると、レポートの文章も読み取ります。src/advisory/ の抽出器は、明文化された文法に従い、モデルを使わずに、各パス、#N、SHA、件数、タイムスタンプを断定を表す動詞を含む節に結び付け、結び付けられないトークンはすべて除外します。残った内容をゲート独自のチェックで証拠と比較します。各結果は勧告として記録されます。値は agrees、differs:<reason>、unanswered:<reason> のいずれかで、名前または部分パスだけで示されたファイルの場合は agrees_by_name です。勧告によって判定が変わることはなく、fail になることもありません。記録には、測定した数値が勧告とともに記載されます。ただし、それぞれの数値は測定に使った抽出器と比較方法の組み合わせに限られ、それ以外は「未測定」となります(下記の「測定値」)。詳細は docs/advisory.md を参照してください。
differs の注記は、決して告発としてではなく、**「不一致の可能性あり、未検証」**と表示されます。測定前に事前登録された判定ルールでは、測定精度が 0.50 を下回った場合、differs の注記にこのラベルを付けることになっていました。このルールが適用されました。CLI、Action の要約、MCP ツールのテキストでは、新しい文言に続けて記録に示された内容を記載し、勧告の横に定型の一文を表示します。公開済みの数値では、次のように表示されます。「勧告が判定に影響することはありません。抽出精度 0.80(24/30、95% CI 0.63–0.90)。不一致の可能性は未検証です。独自のエージェント PR 170 件のうち、虚偽の主張としてマークされたものは 20 件中 0 件で、そこで記録による確認が可能だった 44 件の勧告のうち、虚偽の主張はありませんでした(0/44)。」 まだ測定されていない後続の抽出器や比較方法については、数値を示しません。記録には引き続き differs:<reason> と記載されます(docs/advisory.md、「differs の注記の表示方法」)。
測定値
公開日:2026-10-05。値、n、手法のみを公開し、レポート、その条項、判定ラベルは公開しません。
| 項目 | 値 | n | Wilson 95% 区間 | 対象 |
|---|---|---|---|---|
| 抽出精度 | 0.80(実際の主張 24 件) | アドバイザリー 30 件 | [0.627, 0.905] | extractor 0.1.1、ダイジェスト ab77ce47…c360 |
実際に誤った主張を示した differs ノート | 0 | differs アドバイザリー 20 件 | [0, 0.161] | extractor 0.1.1 および comparison 0.2.0 |
| ベースレート:実際に誤った完了主張 | 0 | 確認可能なアドバイザリー 44 件(149 件中) | [0, 0.080] | extractor 0.1.1 および comparison 0.2.0 |
手法:extractor 0.1.1 は、Barg Labs 自身のマージ済みエージェントプルリクエスト 170 件から、149 件のアドバイザリーを提案しました。オペレーターは、抽出精度を調べるため、そこからシード付きのホールドアウトサンプル 30 件を判定し、実際に誤った主張を示していたかどうかを調べるため、すべての differs アドバイザリー(全数調査の 20 件)を判定しました。ベースレートについては、記録と照合できた 149 件中 44 件(24 件は一致、20 件は相違)のうち、誤った主張はありませんでした。残りの 105 件は記録と比較できず、判定対象外でした。各値は extractor のダイジェストにひも付けられ、differs の値とベースレートは comparison のバージョンにもひも付けられています。その後の extractor や comparison は、新たに測定するまで「未測定」であり、過去の値を引き継ぐことはありません。現在稼働している extractor は 0.1.3 です。0.1.2 以降、別のプルリクエストに関する記述、未実施の変更、ベースライン、否定されたリスト、意図的なテスト失敗を主張として読み取らないようになりました。また、0.1.3 以降は、コロンの後にあるファイル一覧やマージ時刻を読み取ります(docs/advisory.md の「帰属」と「リスト、マージ時刻、および自身への参照」を参照)。extractor 0.1.4 のルールはホールドアウトプルリクエストに一般化できず、元に戻されました(「ラベル、使用された名前、説明」を参照)。0.1.3 の値は公開されていないため、この extractor が作成した記録には「未測定」と記されます。現在稼働している comparison は 0.4.0 です。変更されたファイルに含まれないファイル主張は、そのパスがヘッド時点でファイルの場合に限り、相違の可能性があるものとして扱われます。該当箇所に何もない場合やディレクトリがある場合は未回答として扱われます(「ヘッド時点に存在しないパス」を参照)。また、closes 主張は、ゲートの場合と同じく、対象を誰がクローズしたかによって確定されます(「対象をクローズした人に基づく Closes の判定」を参照)。これも未測定であり、differs の値は引き続き comparison 0.2.0 にひも付けられています。
ベースレートは常に differs の値と並べて表示します。記録と照合できたアドバイザリー 44 件の中に、誤った主張はありませんでした(44 件中 0 件)。したがって 20 件中 0 件という結果は、チェックで見つけられなかったということではなく、見つける対象がほとんどなかったことを意味します。記録と照合できなかった 105 件のアドバイザリーは判定対象外であり、その中に誤った主張があったとしても検出されていません。differs ノートを不一致と呼ぶ表現が認められるのは、誤った主張を含むコーパスで、事前登録した基準を超える測定結果が得られた場合に限られます(決定日:2026-10-05)。現時点では、まだ実現していません。詳細はdocs/advisory.md の「測定値」を参照してください。
受け入れ基準と事前登録済みのフィクスチャ:docs/acceptance/preregistration-0.1.md、fixtures/。
ステータス:開発中。主張形式の仕様はレビュー中のドラフトです。
ライセンス:チェッカーとツールは AGPL-3.0-only(LICENSE)、spec/ 内の主張形式仕様は Apache-2.0(spec/LICENSE)です。貢献には CLA が必要です(CLA.md)。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。