
halo-record v0.2.7
AIエージェント向けの改ざん防止ランタイムレコード。ハッシュチェーン方式で、依存関係がなく、誰でも検証可能。
halo-record
改ざん検知可能なAIエージェントの監査証跡 — ハッシュチェーン化されたRuntime Recordを、顧客自身が検証できるRuntime Reportとしてレンダリングします。
エージェントが実行するすべてのアクション(ツール呼び出し、モデル呼び出し、データアクセス、承認)は、追記専用のハッシュチェーンログ内の1つのRuntime Recordとなり、Runtime Reportはそのチェーンを自己検証可能なHTMLページとしてレンダリングしたものです。チェーンのチェックポイントを保持する当事者は誰でも、それを生成した者を信頼することなく、その背後にあるレコードが改変されていないことを検証できます — このチェックポイントが要となる部分です。チェーン単体では、レコーダーを運用する当事者以外のすべてに対して改ざん検知可能です(LIMITS.md §1)。顧客のセキュリティチームが「あなたのエージェントは我々のデータで何をしたのか?」と尋ねてきたとき、長文の説明の代わりにリンクを1つ渡せます。セキュリティレビューではすでにSOC 2チェックリストの隣でAIに関する質問がなされており、そしてますますそれらの質問はISO 42001、EU AI Actの記録保持条項、顧客自身のアンケートから来ています。今日では書面による保証でもまだ通ります。このプロジェクトの背後にある賭けは、それが長くは続かないだろうというものです。
Help Net Security で紹介されました(2026年8月)。
レコード形式はオープンで、自由に実装できます。このパッケージはリファレンス実装です:レコーダー、検証器、ウィットネスクライアント、レポートサーバー。
halo-recordを使っていますか、あるいは検討していますか? あなたが誰で、何のために使うのか教えてください → Who's using halo-record?
自分で確認する
あなたはエージェント内にレコーダーを組み込むよう求められています。それを鵜呑みにするべきではありません:
- ランタイム依存ゼロ。 標準ライブラリのみ。
pip install halo-recordはちょうど1つのパッケージをインストールします。 - ネットワーク呼び出しなし、ただしオプトインの3つを除く — ウィットネスへのアンカリング(サブジェクトID、レコード数、2つのチェーンフィンガープリント — ヘッドとチェーンルート — を送信)、ウィットネスのチェックポイントの読み戻し(サブジェクトIDを送信)、およびRFC 3161タイムスタンプ(チェックポイントの状態ハッシュのみをTimestamp Authorityに送信)。これらはすべて、あなたが呼び出さない限りオフです。レコードの内容があなたのインフラから出ることはありません。
- 生のツール引数はハッシュ化され、併せて秘匿化されたサマリーが付きます。 引数は正規化ハッシュとサマリーとして保存されます:既知のシークレットおよびPIIパターンをマスクした引数テキストで、200文字に制限されます。どのパターンにも一致しない短い入力は、サマリーにそのまま現れます。ハッシュのみモード(
summaries=False)ではサマリーは一切保持されません。秘匿化はベストエフォートです(一般的なシークレットおよびPII形式に対する正規表現と、エントロピーによるキャッチオール):これは多層防御として扱い、保証とは考えないでください。summary以外にあなたが指定するアウトカムフィールドは、そのままの形で封印されます(LIMITS §13)。 - 監査できるほど小さい。 約5,300行のPython(空行とコメントを除いたコード行数)。午後1回で全部読めます。
- Apache-2.0。
- ドキュメントは第一級です。 LIMITS.md(チェーンが証明できないこと)、PRIVACY.md(レコードに含まれるものと、あなたのマシンから出るもの)、RETENTION.md(保持ポリシーの下での運用)、そして REVIEWERS.md — 4コマンドの独立チェックと、レビュー所見のための引用形式。
各レイヤーが何を証明するか — このプロジェクトにおける要となる区別(LIMITS.md §1):あなた自身が保持するチェーンは、すでに誰かが保持しているヘッドに対して、レコードが編集されていないことを証明します。運用者の外部で保持されるチェックポイントのみが、何も削除されていないことを証明します。そして、すべてのアクションが捕捉されたことを証明するハッシュは存在しません。
| 主張 | 自己保持チェーン | + 外部チェックポイント | + 信頼されたキャプチャ |
|---|---|---|---|
| 確立された成果物への編集を検知 | ✔ | ✔ | ✔ |
| コミット済み履歴の書き換えを検知 | — | ✔ | ✔ |
| 欠落/遅延チェックポイントを検知 | — | ✔(合意されたケイデンス) | ✔ |
| すべてのアクションが記録されたことを証明 | — | — | キャプチャ境界に依存 |
インストールする前に1つ見る: サンプルRuntime Report — 架空のデータ、本物のチェーン、そしてあなたが見ている間にブラウザ上で自己再検証します。
60秒デモ
エージェントは不要です。uv があれば、インストールするものは何もありません:``` uvx --from halo-record halo demo --serve
または従来の方法:```
pip install halo-record
halo demo --serve
どちらかを選ぶと、2社の顧客を持つ架空のサポートエージェントベンダーをスキャフォールドし、チェーンを目撃し(オペレーター外部の1社を代行するローカルwitnessファイルについてはLIMITS.md §1を参照)、ゲート付きのRuntime Reportsを提供し、ブラウザでオペレーターコンソールを開きます。次に改ざんテストを試してください:.jsonlファイルの1つから1行削除してリロードします。レポートがそれを検出します。
自分のエージェントを記録する
境界での1行:```python from halo_record import trace
agent = trace(run_my_agent, profile="my-agent", log="audit.jsonl") # wraps your entrypoint; records the run boundary to ./audit.jsonl — add record_call() or a framework adapter at each tool boundary to capture individual calls
`from halo import ...` という便利なシムも同梱されていますが、PyPI 上の `halo` という名前は無関係なターミナルスピナーパッケージのものであり、そのパッケージがインストールされている場合はそちらがインポートで優先されます。`halo_record` は曖昧さがないため、例ではこちらを使用しています。
`log=` を指定しない場合、レコードは `~/.halo/my-agent.jsonl` に書き込まれます(エージェントごとに1チェーン)。ラッパーは実行境界を封止し、証拠は呼び出しごとのレコードに残ります。これらはフレームワークアダプター(下のマトリクスを参照)でキャプチャするか、明示的にキャプチャします。後者は委譲リンクの仕組みも示します:```python
from halo_record import Recorder, record_call
rec = Recorder("audit.jsonl")
with record_call(rec, "crm.lookup", {"account": "acct-9"}) as call: # one sealed record per tool call
call.result = crm.lookup("acct-9")
with record_call(rec, "payments.refund", {"amount": 120},
parent_id=rec.last_record_id()) as call: # child links to the action that spawned it
call.result = payments.refund(120)
次にレポートをレンダリングします:``` halo report audit.jsonl -o report.html # one chain -> self-verifying HTML halo serve ./records --port 8721 # all tenants, gated per customer
クイックスタートは、ブラウザで自分のエージェントのRuntime Reportを表示した時点で終了します。JSONLファイルだけが得られてレポートが表示されない場合は、何かがおかしいのでissueを開いてください。
### 検証ブロック
ガードレールまたはポリシーレイヤーがアクションをチェックした場合、その判定結果をレコードに載せることができます — ゲートが何を決定したかを記録し、他のすべてのフィールドと同様にハッシュチェーンに封印されるオプションのブロックです:```python
from halo_record import build
build("tool_call", "security", tool="payments.refund",
verification={"status": "allowed", "verifier": "gate/1.2",
"policy_ref": "sha256:1f3a...",
"checked_at": "2026-08-01T12:00:00Z"})
レコードに封印される内容は次のとおりです:```json "verification": {"status": "allowed", "verifier": "gate/1.2", "policy_ref": "sha256:1f3a...", "checked_at": "2026-08-01T12:00:00Z"}
`record_call(...)` は同じ `verification=` キーワードを受け付けます。`status` はブロック内で必須であり、`verifier`、`policy_ref`、`checked_at` は任意です。各ステータスの意味は次のとおりです:
| ステータス | ゲートが報告する内容 | アクションは実行されたか? |
|---|---|---|
| `allowed` | アクションを許可した | はい — アクションは続行された |
| `blocked` | アクションを拒否した | 統合側によって決まり、このフィールドでは決まらない — レコードが結果を保持している場合もあり、ブロックだけでは未実行を証明しない |
| `modified` | 実行前にアクションを変更した — `action.input` は変更後の、**実行されたまま**のアクションを記述する | はい、変更された形で |
| `unverified` | 実行された(または参照された)が、いかなる判定も下さなかった — ブロックが存在しない場合とは異なり、後者は検証の主張が一切なされなかったことを意味する | はい — アクションは判定なしで続行された |
このブロックは運用者の統合コードによって提供され、ゲートが述べたと報告する内容を記録します — `principal` と同じ信頼の姿勢です([LIMITS](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md#11-verification-status-is-the-gates-report-not-halos-finding) を参照)。封印はステータスが事後に編集されなかったことを証明しますが、チェックが行われたこと、判定が正しかったこと、またはブロックされたアクションが実行されなかったことを証明するものではありません。これは独立した検証ではありません。
`policy_ref` を証拠として使用可能にするには、ルールセットのコンテンツハッシュを使用し、ルールセットの成果物を保持してください — 解決できないラベルはこのフィールドを装飾的なものにします。
## すでに運用しているものに接続する
| 境界でキャプチャ | 既存のテレメトリから取り込み |
|---|---|
| ネイティブレコーダー(`from halo_record import trace`) | OpenTelemetry GenAI スパン |
| MCP インターセプター | LiteLLM コールバック |
| LangChain / LangGraph コールバック | Langfuse エクスポート |
| OpenAI Agents SDK フック | 任意のゲートウェイ / リバースプロキシログ |
| Claude Agent SDK フック | Claude Code および Codex CLI の `PostToolUse` フック(ツール実行後に発火) |
フレームワークアダプターと取り込みパスは各レコードに `source` タグを付与するため、レポートは各証拠がどのように収集されたかを開示します。キャプチャされたレコードと取り込まれたレコードは同じチェーン内に存在します。
LangChain / LangGraph の場合、それはコールバックハンドラーです:```python
from halo_record import Recorder
from halo_record.integrations.langchain import HaloCallbackHandler
recorder = Recorder("audit.jsonl")
result = my_chain.invoke(inputs, config={"callbacks": [HaloCallbackHandler(recorder)]}) # every tool call becomes a record
MCPの場合、1回の呼び出しでクライアントセッションをラップし、その後はどのMCPを使用するエージェントでも、どのフレームワークが駆動していても、すべてのツール呼び出しに対してレコードを出力します:```python from halo_record.integrations.mcp import instrument_client_session
instrument_client_session(session, Recorder("audit.jsonl"), server="stripe") # every session.call_tool() is now recorded
ゲートウェイまたはプロキシのログ(Cloudflare AI Gateway、Portkey、モデルの前段の nginx)については、ログ行をチェーンにマッピングする — 境界でキャプチャされたものではなく、取り込み済みとして明示的にタグ付けする:```python
from halo_record.integrations.gateway import record_log
record_log(Recorder("audit.jsonl"), {"tool": "gen_ai:gpt-4o", "model": "gpt-4o", "status": 200, "subject": "acme-corp"})
OpenTelemetry GenAI スパン(CrewAI、LlamaIndex、および OTel インストルメンテーションを備えたほとんどのエージェントフレームワーク)を出力するものはすべて、OTel アダプターを通じてチェーンに取り込まれ、TypeScript パッケージは Vercel AI SDK と JS エージェントエコシステム向けのネイティブアダプターを提供します。あなたのスタック用のアダプターがありませんか?issue を作成してください。ほとんどのアダプターは約 100 行です。
コーディングエージェント(Claude Code または Codex)を記録する
Claude Code は、ツール呼び出しのたびに PostToolUse フックを発火します。これを halo hook に向けると、各アクション — ファイル書き込み、シェルコマンド、MCP コネクター呼び出し — がローカルチェーン内のレコードになります。コード変更は不要で、設定エントリを 1 つ追加するだけです:```json
{
"hooks": {
"PostToolUse": [
{"matcher": "*", "hooks": [{"type": "command", "command": "halo hook"}]}
]
}
}
これを `~/.claude/settings.json` に追加すると、記録は `~/.halo/audit.jsonl` に保存されます(`$HALO_LOG` で上書き可能)。データ、ネットワーク、外部状態に一切触れない純粋なオーケストレーションツールはスキップされます — チェーンが記録するのは思考ではなく、信頼境界を越えるアクションです。`HALO_HASH_ONLY=1` を設定すると、要約なしでコンテンツハッシュを記録します。`HALO_AGENT_VERSION`(および任意で `HALO_AGENT_MODEL`)を設定すると、すべての記録をそれを生成したエージェントビルドに紐付けます — 監査人が特定の期間に実行されていたバージョンについて尋ねたとき、エクスポートは記憶ではなく列によって答えます。
Codex CLI は同じイベント形状を持つ同じライフサイクルフックを提供します(フックはデフォルトで有効)。これを `~/.codex/hooks.json` に追加すると、Codex のシェルコマンド、`apply_patch` による編集、および MCP 呼び出しが同じチェーンに記録されます:```json
{
"hooks": {
"PostToolUse": [
{"matcher": ".*", "hooks": [{"type": "command", "command": "halo hook"}]}
]
}
}
フックはイベント自体から両者を区別し(Codex は turn_id と model を追加する)、各レコードに claude-code または codex のラベルを付ける。HALO_HOOK_AGENT を設定すると一方を強制できる。どちらも取り込み層である。PostToolUse フックはツールの実行後に発火するため、レコードはハーネスが報告する内容から構築される。
レポートが「この実行はどのようなルールの下で行われたか?」に答えられる必要がある場合は、HALO_AUTHORITY_FILE にそのセッションの有効な権限の JSON スナップショットを設定する。プライバシーに配慮すること。ハッシュと参照のみとし、生のプロンプト、非公開のポリシーテキスト、シークレット、完全なツールスキーマは含めない。既知のシークレット形式はシール時にマスクされるが、ハッシュと参照はそのまま通過し、自由形式のテキストは検出されない(LIMITS §6 を参照)。snapshot_id は、基盤となる権限が変更されていない間のみ再利用すること。同じ id で内容が変更されていない連続したレコードは圧縮される。変更された内容に対して id を再利用した場合は、通知とともに完全な形で保存される。```json
{
"snapshot_id": "auth_2026_07_08T1100Z",
"captured_at": "2026-07-08T11:00:00Z",
"scope": "session",
"workspace": {"path_hash": "sha256:...", "git_commit": "abc1234"},
"refs": [
{"kind": "project_rules", "id": "CLAUDE.md", "hash": "sha256:...", "loaded": true, "truncated": false},
{"kind": "mcp_tool_registry", "id": "filesystem", "hash": "sha256:..."}
],
"omissions": [{"kind": "private_policy", "reason": "customer_secret", "hash": "sha256:..."}],
"stale_if": ["project_rules_hash_changed", "mcp_tool_registry_hash_changed"]
}
## 検出
### 検出の仕組み
`detect` コマンドは、ファイルシステムをスキャンして、既知のAIエージェント設定ファイル、MCPサーバー設定、およびエージェント関連のアーティファクトを探します。検出は、ファイル名のパターン、ディレクトリ構造、およびファイルの内容に基づいて行われます。
### 検出されるもの
- **エージェント設定ファイル**: Claude Desktop、Cursor、Windsurf、VS Code、およびその他のAIツールの設定
- **MCPサーバー設定**: `mcp.json`、`claude_desktop_config.json`、および同様のファイル
- **エージェント指示ファイル**: `CLAUDE.md`、`.cursorrules`、`AGENTS.md`、およびその他のプロンプトファイル
- **認証情報ファイル**: エージェント設定内で参照されるAPIキーとトークン
- **インストール済みエージェント**: システム上に存在するAIエージェントCLIツールとそのバージョン
### 検出出力
検出結果は、見つかった各アーティファクトの種類、場所、および関連するメタデータとともに表示されます。出力は、エージェント、設定、および認証情報ごとに整理されています。
### 検出の制限
- 検出は、既知のファイル名パターンと場所に依存しています
- カスタムまたは非標準の設定は検出されない可能性があります
- 検出は、ファイルの内容を変更したり、エージェントと対話したりしません
- 一部の検出には、ファイルシステムのアクセス許可が必要です
## スキャン
### スキャンの仕組み
`scan` コマンドは、検出されたアーティファクトに対してセキュリティ分析を実行します。これには、設定の検査、認証情報の露出のチェック、および潜在的なセキュリティ問題の特定が含まれます。
### スキャンチェック
- **認証情報の露出**: 設定ファイル内の平文のAPIキー、トークン、およびパスワード
- **過剰な権限**: 過度に広範なファイルシステムまたはネットワークアクセスを持つエージェント
- **安全でない設定**: 安全でないデフォルト設定または危険なオプション
- **既知の脆弱性**: インストールされているエージェントのバージョンに対するCVE
- **ネットワーク露出**: 外部に公開されているMCPサーバーまたはエージェントエンドポイント
### スキャン出力
スキャン結果には、重大度レベル、影響を受けるアーティファクト、および修復の推奨事項が含まれます。結果は、重大度(クリティカル、高、中、低、情報)別にグループ化されています。
### スキャンの制限
- スキャンは、静的な分析と既知のパターンに基づいています
- 動的な動作や実行時の問題は検出されません
- 一部のチェックでは、完全な結果を得るために追加の設定が必要になる場合があります
- スキャンは、エージェントやその設定を変更しません```sh
HALO_AUTHORITY_FILE=./authority.json halo hook
スナップショットはアクション記録と同じハッシュチェーンに封印される。良いデフォルトは、開始時のセッションレベルのスナップショット1つと、ルール、Skills、フック、MCPツールレジストリ、またはコンパクションポリシーが変更されたときの新しいスナップショットである。長いセッションをスリムに保つため、同じ authority.snapshot_id を持つ連続したレコードは、最初の完全なスナップショットの後にコンパクションされる。以降のレコードは {"snapshot_id": "...", "same_as_previous": true} のみを保持する。ポインタはハッシュチェーンに留まるが、かさばる refs/omissions/stale-if ブロックはすべてのアクションで繰り返されない。(コンパクションはレコーダープロセスごとである。ツール呼び出しごとに1プロセスを生成するフックスタイルのキャプチャでは、前回の完全なスナップショットが末尾レコードでない限り完全なボディを再保存するため、短命なプロセスはチェーンサイズと引き換えに再利用ガードを得る。)
SDKユーザーは同じブロックを直接アタッチする — build(..., authority={...}) または record_call(..., authority={...})。ハッシュのみのキャプチャも同じサーフェスである(いずれでも summaries=False):```python
from halo_record import Recorder, record_call
rec = Recorder("audit.jsonl") with record_call(rec, "crm.lookup", {"account": "acct-9"}, authority={"snapshot_id": "auth_1", "rules_hash": "sha256:..."}, summaries=False) as call: # hash-only: no summaries, no excerpts call.result = crm.lookup("acct-9")
次に、いつものように:```
halo verify ~/.halo/audit.jsonl
halo report ~/.halo/audit.jsonl -o report.html
アクション後のフックを公開するエージェントランタイムであれば、同じコマンドを供給できる — フックは1つのイベントをstdinでJSONとして読み取り、1つのレコードを追記する。
1つのチェーン、同時に1人の書き手。チェーンは連結リストである。同じヘッドを読み取った2人の書き手がどちらも追記すると、チェーンは分岐し(2つのレコードが同じ前任者を主張する)、検証は影響を受けたレコードを特定する。Recorderは自身の追記をサイドカーロック(ここではPOSIXのflock、TypeScriptパッケージではロックディレクトリ)で直列化し、halo hookはRecorderを通じて追記するため、上記のフック設定はカバーされる。チェーンファイルに直接書き込むもの — 手書きのフック、並列ワーカー、ログシッパー — は、ヘッドを読んでから追記するシーケンス全体にわたって同等の排他ロックを保持するか、プロセスごとのチェーンに書き込む必要がある。LIMITS.md section 9が、言語をまたぐ境界を含めてこれを完全に扱っている。
記録が失敗するとき
2つの統合スタイルは、意図的に逆方向へ失敗する — 自分が許容できる失敗をする方を選ぶこと:
- フレームワークアダプター(LangChain、コールバックマネージャー経由のフック)はフェイルオープンする。 レコードを書き込めない場合(ディスクフル、権限)、エージェントのアクションは正常に完了し、レコードは失われる。LangChainハンドラーはstderrに大きな警告を出力し、損失をカウントする(
handler.lost_records)が、チェーン自体には決して書き込まれなかったレコードを示すことはできない — 停止したチェーンでも検証は通る。停止したチェーンを可視化するのは、定期的なウィットネスチェックポイントである。到着するはずのチェックポイントが決して到着しないことが警報となる。 - ネイティブの
trace()ラッパーはフェイルクローズする。 レコードを書き込めない場合、例外がエージェントのアクションに伝播する — 証拠がなければ、アクションもない。より厳格だが、エージェントを中断させる可能性がある。
どちらのデフォルトも万人にとって正しいわけではない。自分がどちらを実行しているのかを知っておくこと。
完全性 vs. 網羅性(この部分を読むこと)
各レイヤーが何を証明するのかを正確に把握すること — それらは異なる主張であり、その違いこそが要点である:
自己保持チェーンが証明するのは、確立されたヘッドに対する完全性である。誰かがすでに保持しているチェーンヘッドが与えられれば、その背後にあるレコードに対するあらゆる編集、並べ替え、削除が検出可能になる。それ自体では — 運用者以外の誰かがヘッドを見る前に — チェーンが証明するのは内部整合性であり、履歴ではない。運用者はレコードを削除して再シールでき、新しいファイルは検証を通る。チェーンが歴史的にコミットされるのは、そのヘッドが運用者の制御を離れた瞬間である。
それがウィットネスである。運用者の外部の当事者がチェーンの定期的なチェックポイントを保持する — サブジェクトID、レコード数、そして2つのチェーンフィンガープリント(ヘッドとチェーンルート)。正確なペイロードはそれだけで、他には何もない。チェックポイントはコミットされた履歴の書き換えを検出可能にし、逃したチェックポイント自体が可視的なイベントとなる:``` halo anchor audit.jsonl witness.jsonl # anchor a checkpoint to a local witness halo anchor audit.jsonl witness.jsonl --check # completeness verdict against it
特に *time* については、外部の RFC 3161 タイムスタンプがチェックポイントの自己申告時刻を、運用者が制御しない Timestamp Authority からの証明に置き換えます —「このチェーンは T までにこのヘッドに到達した」という証明であり、ホスト型インフラを必要とせず第三者による検証が可能です。デフォルトの TSA は無料の freetsa.org です(評価には十分)。本番環境では `--tsa` で商用 TSA(DigiCert / Sectigo / 自前のもの)を指定してください:```
halo anchor audit.jsonl witness.jsonl --timestamp # attach a TSA time proof to the checkpoint
halo anchor audit.jsonl witness.jsonl --check # reads the token's claimed time
--check はトークンがこのチェーン状態にバインドされていることを確認し、その証明された時刻を読み取りますが、TSA の署名を検証しません — これは意図的に標準ツールに委ねられており、レビュアーが当方のコードを一切信頼しなくて済むようにしています。時刻を独立して検証するには(これがセキュリティレビュアーに渡すものです):```
tsa.token_b64 lives in the witness log; decode the latest one to a standard .tsr file
python3 -c 'import json,base64; cps=[json.loads(l) for l in open("witness.jsonl") if l.strip()]; t=[c["tsa"] for c in cps if c.get("tsa")][-1]; open("token.tsr","wb").write(base64.b64decode(t["token_b64"])); print(t["digest"])' curl -s -o tsa-ca.pem https://freetsa.org/files/cacert.pem # CA for the default TSA (a commercial TSA publishes its own) openssl ts -verify -digest -in token.tsr -CAfile tsa-ca.pem # → "Verification: OK"
もう一つの境界を率直に述べると、チェーンもウィットネスも、現実世界のすべての行動がレコーダーを通過したことを証明するものではありません。それは**キャプチャ完全性**であり、レコーダーがスタックのどこに位置するか(ネイティブインストルメンテーション、フック、ゲートウェイ取り込み)に依存する性質であって、ハッシュに依存するものではありません。レコードが `source` タグを持つのはまさにこの理由からです。このページ冒頭の「Check it yourself」にあるクレーム表は、これら三つの層の要約です。
ウィットネスは誰でも運用できます。自分で運用するウィットネスは履歴を*自分*にコミットしますが、それを*顧客*にコミットするには、顧客が信頼するに足る理由のあるウィットネスが必要です。プロトコルはいずれにせよオープンです。
ホスト型の、認知されたウィットネスが、このプロジェクトが自らを維持していく方法です。アーリーアクセス:[email protected]。
## チェーン内の個人データ
チェーンは追記専用です。レコードに封印されたものはそこに残り続けます。なぜなら、それを削除すると、それ以降すべての検証が壊れるからです。ツール引数はすでに対処済みで、ハッシュと200文字に制限された編集済みサマリーとして保存されます(ハッシュのみモードではサマリーは保持されません)。
その文の限界に注目してください。*編集済み*であって、削除済みではありません。[LIMITS.md](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md) のセクション6は、氏名や郵便住所には信頼できるパターンが存在しないため、どちらも検出されず、どちらもマスクされないことを明示しています。そして、あなたが提供するテキストを含むフィールドは `subject` だけではありません。`principal`、`approver`、`session_id`、`agent`、`authority`、`data`、およびすべてのサマリーも同様です。
機能するパターンはこうです。安定した仮名IDをチェーンに入れ、個人へのマッピングは削除可能なシステムに保持します。そうすれば、消去要求はマッピングを削除することで満たされます。`subject` は個人ではなくテナント組織を指すようにしてください。```python
from halo_record import build
build("tool_call", "privacy", subject={"id": "acme", "name": "Acme Corp"})
これを強制する設定はない — レコーダーの呼び出し方における規律である。 これは消去を扱いやすくするものであり、匿名化ではなく、組み込みの 保持やプルーニングはまだ存在しない。 LIMITS.md セクション13に完全なフィールド リストがあり、マッピングが消えた後でも保存された入力フィンガープリントが推測可能な値を確認できる理由を説明し、 レビュアーが尋ねるべき質問で締めくくられている。
モデル呼び出しを記録する(買い手の最初の質問:「どのモデルが私のデータを見たのか?」):```python from halo_record import record_model_call
record_model_call(rec, provider="anthropic", model="claude-sonnet-4-6", zdr=True, purpose="draft support reply", subject="acme") # tool=model.generate, scope=model:anthropic
## コンプライアンススタックにおける位置づけ
halo-record は証拠レイヤーであり、認証ではありません。評価フレームワークがさまざまな言葉で繰り返し求めてくる成果物を生成します。以下のすべての項目に適用されるスコープ上の注意が1つあります。これらは記録に関する完全性の主張であり、運用者に対する完全性を主張するにはチェックポイントを保持する外部の証人が必要です([LIMITS.md §1](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md))。
- **セキュリティ質問票および SOC 2 レビュー:** AI セクションには、スクリーンショットや文章ではなく、検証可能な Runtime Report で回答できます。
- **AIUC-1:** 改ざん検知可能なログ証拠(E015.4)と、認可イベントを含む実行チェーン記録(E015.2 — 明示されたギャップあり: 推論トレースは取得されません)を生成します。これらは標準の AccountAbility コントロール E015 が名指しするものです。E015 自体は必須であり、E015.2 と E015.4 はその補足層です。合格に必須ではなく、顧客や規制当局から求められたときにベンダーが採用するものです。チェーンが、依拠する当事者が信頼するに足る理由を持つ証人にアンカーされれば — 運用者自身が運用する証人ではこれを提供できません — それは監査時に再構築されるものではなく、継続的に証人付けされたチェーンとなります(チェーンに入るものは依然としてキャプチャ面によって制約されます)。意図的にスコープ外としているものを含む、コントロールごとの証拠マッピングは [`AIUC.md`](https://github.com/bkuan001/halo-record/blob/main/AIUC.md) にあります。
- **OWASP Top 10 for Agentic Applications 2026:** 10 の脅威のうち 8 つが記録に対する決定論的ポリシールールにマッピングされ、2 つは理由とともにスコープ外と明記され、パックは実行可能な形で提供されます。公式な OWASP 成果物ではなく、コミュニティによるおおよそのマッピングです。[`OWASP.md`](https://github.com/bkuan001/halo-record/blob/main/OWASP.md) を参照してください。
- **AARM (CSA):** AARM が規定する改ざん検知可能なアクションレシートを生成します — R5、および R6 の封印部分(アイデンティティはハッシュに封印されるが、暗号学的に認証されるわけではない)。halo-record はレシートレイヤーであり、完全な AARM システムには強制ゲートウェイと組み合わせてください。[`AARM.md`](https://github.com/bkuan001/halo-record/blob/main/AARM.md) を参照してください。
- **Agentic Trust Controls:** ATC の証拠コントロールを支えるランタイム記録 — 改ざん検知可能なアクションログ(RBM-03)と権限証明の記録部分(AID-05、強制部分はゲートに属します)を1つのチェーン化された記録にまとめたもの。[`ATC.md`](https://github.com/bkuan001/halo-record/blob/main/ATC.md) を参照してください。
- **CSA AI Controls Matrix (AICM) / STAR for AI:** LOG ドメインの証拠 — 生成された監査記録、未検知の改変に対する封印、記録された入力および出力イベント — をコントロールごとにマッピングしたものは [`AICM.md`](https://github.com/bkuan001/halo-record/blob/main/AICM.md) にあります。CSA 自身の v1.1 クロスウォークは、そのドメインを AIUC-1 E015 に結び付けています。
- **MITRE ATLAS:** エージェントテレメトリの緩和策(AML.M0024)を、ATLAS 自体が求めていない完全性特性を備えて実装しています — ログは運用者の外部の者によって検証可能です。[`ATLAS.md`](https://github.com/bkuan001/halo-record/blob/main/ATLAS.md) を参照してください。
- **EU AI Act / ISO 42001 / NIST AI RMF:** これらのフレームワークが記述する記録保持およびログ記録の義務は同じ成果物クラスです — [EU-AI-ACT.md](https://github.com/bkuan001/halo-record/blob/main/EU-AI-ACT.md)、[ISO42001.md](https://github.com/bkuan001/halo-record/blob/main/ISO42001.md)、[NIST-AI-RMF.md](https://github.com/bkuan001/halo-record/blob/main/NIST-AI-RMF.md) で保守的にマッピングされています。
これらのいずれも、それ自体で何かを認証するものではありません。評価者に検証可能なものを提供するものです。境界 — halo-record が意図的に行わないこと、およびレビュアーが尋ねたときに何を言うべきか — は [`LIMITS.md`](https://github.com/bkuan001/halo-record/blob/main/LIMITS.md) に文書化されています。
### 証拠を GRC プラットフォームに取り込む
ほとんどの GRC プラットフォーム(Vanta、Drata など)は、アップロードされたファイルをコントロールに対するカスタム証拠として受け付けます。halo-record のエクスポートは、そのフローにそのまま投入できるように作られています:```bash
halo export audit.jsonl --from 2026-06-01 --to 2026-06-30 -o evidence.csv
# scope the export to the actions a control covers
halo export audit.jsonl --from 2026-06-01 --to 2026-06-30 --tool email.send --tool db.query -o evidence.csv
これにより、監査ウィンドウ用に2つのファイルが書き出されます。CSV(記録された各アクションにつき1行、左から右へ いつ → 何が起きたか → 誰が → どの権限の下で → 何がフラグされたか → 来歴 → 検証方法 の順にグループ化され、呼び出しとその結果の編集済み平易な要約、各アクションを生成したエージェントビルドとモデル、それが代理して実行されたアイデンティティ、それを引き起こしたレコード、その認可決定とスコープ、およびあらゆる個人データカテゴリや取り込まれた脅威フラグを含む)と、CSVをそのソースに結び付けるマニフェスト(evidence.csv.manifest.json)です。チェーンの先頭ハッシュが、それが由来する検証可能なログにリンクし、csv_sha256 はエクスポートされたファイル自身のハッシュであるため、エクスポート後に編集されたCSVはもはやそのマニフェストと一致しません。コントロールが特定のアクションのみを対象とする場合は、--tool で母集団を絞り込んでください。マニフェストはフィルターを記録するため、スコープ付きエクスポートは母集団全体として読まれるのではなく、サブセットであることを開示します。両方をログ記録または監視コントロールに対してアップロードしてください。レビュアーがチェーンを自分で検証したい場合は、Runtime Report HTMLを添付してください。このエクスポートは、検証に失敗したチェーンでは実行を拒否します。
ネイティブのプッシュ統合 — エビデンスが自動的にあなたのプラットフォームに届く — はロードマップ上にあります。上記のファイルパスは、アップロードされたエビデンスを受け入れるあらゆるプラットフォームで今日機能します。
CLI```
halo verify validate schema + hash chain (exit 1 broken, 3 empty chain; CI-friendly) halo report render a chain as a self-verifying HTML Runtime Report (--from/--to: a date-windowed report covering only the review period) halo policy corroborate a chain against a declarative policy pack (per-rule pass / violation / evidence-gap; exit 1 violated, 3 nothing in scope) halo serve serve per-tenant reports over HTTP, access-scoped per customer halo grant designate a report recipient (email or domain) halo viewers list who has unlocked a gated report halo anchor witness a chain head, or --check completeness (exit 1 incomplete, 3 unwitnessed) halo witness-serve run a witness over HTTP: vendors anchor chain heads, viewers fetch checkpoints halo demo scaffold the full vendor demo (record -> witness -> gated report) halo export date-bounded evidence export: CSV + manifest tied to the chain head halo sample emit a valid example log halo hash canonical sha256 of a JSON value halo hook Claude Code PostToolUse hook
## 完全性モデル
レコードのハッシュを計算するには: `integrity.hash` を除いたレコードを取得し、`integrity.prev_hash` を前のレコードのハッシュに設定し、RFC 8785 (JSON Canonicalization Scheme) で正規化し、そのバイト列を SHA-256 でハッシュ化します。最初のレコードの `prev_hash` は 64 個のゼロです。検証ではすべてのハッシュを再計算し、すべてのリンクをチェックします。秘密情報は不要です。それが要点です。
検証者に気付かれずにチェーンを改ざんできると思いますか? [試行と結果はこちら](https://github.com/bkuan001/halo-record/discussions/2)。
完全なフィールドリファレンス: [`halo-record.schema.json`](https://github.com/bkuan001/halo-record/blob/main/src/halo_record/halo-record.schema.json)。
## TypeScript
同じレコーダーが Node 向けにも提供されています: [`halo-record-ts`](https://github.com/bkuan001/halo-record-ts)。同じチェーン形式、同じウィットネスプロトコルです。どちらの言語で書かれたレコードも、どちらの検証者でも検証できます。
## コミュニティの例
[trail-halo-poc](https://github.com/AmeyParle/trail-halo-poc) — Halo レコードのプリンシパル権限を TRAIL 資格情報に結び付けるコミュニティの概念実証: 相互の org–agent バインディングと org 署名付きスコープグラントを Halo チェーンに記録し、敵対的検証スイートを備えています。
## コントリビューション
Issue、ディスカッション、プルリクエストを歓迎します — 基本ルールについては [CONTRIBUTING.md](https://github.com/bkuan001/halo-record/blob/main/CONTRIBUTING.md) を参照してください (要約: テスト必須、小さな PR、スキーマ変更はまず議論)。
## ライセンス
Apache-2.0