3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

IBM Bob に hooks 強制機能が来たので、OpenTelemetry で AI エージェントの利用ログを取れるようにした

3
Posted at

本記事について

  • 筆者個人が検証した内容であり、IBM および IBM Bob の公式情報ではありません。 所属組織としての見解でもありません。
  • 記載内容は執筆時点(2026 年 9 月)の実装・挙動に基づきます。
    検証環境は Bob 2.0.2 / opentelemetry-hooks v0.14.0
    (+Bob 対応のフォーク)/ Python 3.12 です。
  • 4 章では、Bob 2.0.2 の実際の hook ペイロードに対応するために追加したアダプター実装を説明します。
    今後のアップデートでペイロードが変わる可能性があるため、導入前に利用環境で動作を確認してください。
  • ポリシー(EnforcedHooks)の適用は IBM Bob IDE で動作を確認しました。Bob Shellは未検証です。
  • 各製品の正確な仕様は公式ドキュメントを参照してください(末尾にリンクを置いています)。

TL;DR

  • IBM Bob の lifecycle hooks を利用すると、プロンプト送信、ツール実行、停止などのイベントを外部処理へ渡せます
  • EnforcedHooks グループポリシーを利用できる環境では、管理者が指定した hook 登録を配布対象の Bob IDE に適用し、利用者がユーザー設定やワークスペース設定から削除・上書きできない状態にできます
  • 本記事では、既存 OSS の o11y-dev/opentelemetry-hooks(MIT)に Bob 用アダプターを追加し、依頼文、対象ファイル、コードや差分などの変更内容、ツール実行結果、エージェントの最終応答を OpenTelemetry のトレース/ログとして出力します
  • プロンプトやツール入出力の本文取得は既定で無効です。ハッシュのみ、マスキングを適用した本文、本文取得など、収集範囲を設定できます
  • EnforcedHooks が管理するのは Bob 上の hook 登録です。runner の配布、送信設定、ネットワーク、保存先、欠損検知は別途設計します

1. 何ができるようになった?

1-1. 背景

AI コーディングエージェントを組織で利用し始めると、次のような確認事項が生じます。

  • 社内コードや機密情報がエージェントに入力されていないか確認したい
  • AI によるコード生成やファイル編集の利用状況を把握したい
  • 問題が発生した際に、その時点の指示内容やエージェントの操作を確認したい

Bob の管理者向けアクティビティログは、主に管理者のアクセスや管理操作を対象としています。
利用者が日々エージェントに何を指示したか、という粒度までは対象に含まれていません。

また、コーディングエージェントでは、プロンプト本文まで標準で記録できるとは限りません。
そのため、このような要件に対応するには、これまで別の運用や記録の仕組みを用意する必要がありました。

今回追加された hooks の強制適用機能により、こうした記録処理を管理者側の構成として組み込めるようになりました。

1-2. 記録できる情報

Bob 対応アダプターは、lifecycle hooks に渡されたイベントを共通形式へ変換します。
これにより、依頼文、ツール利用、ファイルへの変更内容、エージェントの最終応答を、一連の OpenTelemetry トレース/ログとして記録できます。本文を記録する範囲は設定で選択できます。

確認したい情報 記録可否
AI への依頼文 ○(本文取得は要設定・1-4
エージェントが利用したツール、対象ファイル、所要時間
エージェントの最終応答 ○(Bob 対応アダプターで取得・本文取得は要設定)
ファイルへの変更内容(コード、差分、対象ファイル) ○(本文取得は要設定)
利用されたプロジェクト/リポジトリ ○(cwd をもとに記録)
セッション単位の紐づけ ○(session_id
利用端末または OS ユーザーに紐づく識別子 △(外部設定で付与可能。Bob アカウントの利用者情報を自動取得するものではない)

1-3. 実際に何が記録されるのか

以下は、Bob に依頼を1回行った際の記録例です。

記録された項目 備考
クライアント Bob 自動
プロジェクト my-project(ブランチ main cwd をもとに記録
セッション ID d73b77f6... 自動
外部から付与した識別子 r.nakayama 要設定(3-1
指示した内容 「認証モジュールをリファクタして、パスワードは bcrypt にして」 要設定(1-4
エージェントが利用したツール write_file 自動
対象ファイル auth.py 自動
ファイルへの変更内容 生成・適用されたコードや差分 Bob 対応アダプターで取得・要設定
エージェントの最終応答 「bcrypt に変更しました」 Bob 対応アダプターで取得・要設定
所要時間 9.2 秒 自動

「自動」の項目は hook を登録すると記録されます。太字の項目は、1-4 の本文取得設定を有効にした場合の例です。
利用された編集ツールに応じて、コード、差分、対象ファイルなど、操作に対応した情報が記録されます。

利用者が記録のために追加操作を行う必要はありません。

1-4. どこまで記録するかは、組織が選べる

既定では本文を送信せず、文字数と SHA-256 ハッシュを記録します。
本文が必要な場合に、対象ごとに取得範囲を設定します。

設定 依頼文・応答 コード変更の内容 ツール応答
既定(何もしない) 長さ+ハッシュ 長さ+ハッシュ 長さ+ハッシュ
IDE_OTEL_CAPTURE_CONVERSATION_CONTENT=true 本文 長さ+ハッシュ 長さ+ハッシュ
IDE_OTEL_CAPTURE_TOOL_INPUT_CONTENT=true 本文 本文 長さ+ハッシュ
IDE_OTEL_CAPTURE_TEXT=true 本文 本文 本文

依頼文と最終応答を記録する構成に加え、必要に応じて対象ファイル、コード、差分などの変更内容まで記録できます。収集範囲は目的に応じて段階的に設定できます。
まず本文を収集せずに導入し、必要性を確認したうえで取得範囲を拡張することも可能です。

Bob 対応アダプターでは、Stop イベントに含まれるエージェントの最終応答を共通形式へ変換し、OpenTelemetry の属性として記録します。
依頼文と同様に、本文取得の設定を有効にした場合に応答本文を保存できます。

本文を取得する場合は、事前の周知と規程の整備が必要です。
依頼文には業務内容や、場合によっては個人情報が含まれます。
技術的に取得できることと、組織として収集してよいことは別の論点です。
マスキングを含む注意点は 3 章にまとめています。

1-5. 組織全体への適用

任意設定として各利用者に hook の登録を依頼する方法でも記録はできますが、未設定の端末が生じる可能性があります。
Bob の EnforcedHooks グループポリシーを利用すると、管理者が定義した hook 登録を配布対象の Bob IDE に適用できます。

ここで強制されるのは、Bob 上の hook 登録です。
利用者は、ユーザー設定やワークスペース設定から、ポリシーで定義された hook を削除したり上書きしたりできません。
一方で、hook runner の配置、runner 自身の設定、ネットワーク、送信先の稼働までを EnforcedHooks が保証するわけではありません。

管理対象 各自で任意設定する場合 管理者ポリシーを利用する場合
Bob 上の hook 登録 利用者が追加・削除できる 管理者定義分は、利用者設定から削除・上書きできない
runner の配置 利用者ごとに準備 MDM や構成管理で別途配布する
送信先・本文取得範囲 利用者側の設定に依存 runner の管理設定として別途配布する
ネットワーク・保存先 利用者環境に依存 組織側で設計・監視する
適用状況の確認 個別確認が必要 配布対象とバックエンドの受信状況を照合できる

収集範囲は、1-4 の設定を runner 側へ配布することで組織として決められます。
利用状況のみを記録する構成から、規程に基づいて本文も記録する構成まで選択できます。

この構成は、監視や監査を補助するためのテレメトリ収集です。
ログの完全性、不可否認性、欠損がないことまでを、この仕組みだけで保証するものではありません。
配布後の動作確認とバックエンド側の欠損検知を運用に含める必要があります。

導入時には、runner の配布、送信設定の配布、EnforcedHooks の設定、配布後の確認を順に行います。
具体的な手順を次章にまとめます。


2. 導入方法

導入は、個人環境で確認する → 送信先と取得範囲を決める → 組織へ適用する、の順で進めます。

[1] otel-hook を配置する      ← 個人環境では pipx、組織展開では管理された絶対パス
[2] 送信先と取得範囲を決める  ← ローカル出力 / OTLP、本文取得、マスキング
[3] Bob に hook を登録する    ← 個人設定 / EnforcedHooks ポリシー

組織展開では、次の3つを分けて管理します。
スクリーンショット 2026-09-03 10.51.03.png

EnforcedHooks が直接管理するのは1つ目の「Bob の hook 登録」です。2つ目と3つ目は、端末管理とログ基盤の運用として別途準備します。

Bob 対応の入手先

本記事の Bob 対応(--agent bob / --bob / policy コマンド)は、上流の
o11y-dev/opentelemetry-hooks にはまだ入っていません
筆者のフォークで実装しており、こちらで公開しています。

github.com/r-nakayamasan/bobotel-hooks

そのため pipx install opentelemetry-hooks(PyPI の上流版 v0.14.0)では --agent bob は通りません。
以下の手順は、このフォークを導入した環境を前提としています。上流版への反映は未実施です。

2-1. まず個人環境で試す

(1) インストール

pipx install git+https://github.com/r-nakayamasan/bobotel-hooks.git@feat/bob-adapter

上流版(pipx install opentelemetry-hooks)には、現時点で Bob 対応は含まれていません。

(2) 送信先をローカルのフォルダにする(バックエンド不要)

~/.local/share/opentelemetry-hooks/otel_config.json を作ります。

{
  "IDE_OTEL_LOCAL_SPANS": "true"
}

(3) Bob に hook を登録して確認

otel-hook setup --agent bob
otel-hook diagnose --agent bob
#   ✓ [bob] 5 events registered (~/.bob/settings/settings.json)

この状態で Bob を1回動かすと、セッションごとに JSONL が1ファイルできます。

$ jq -r '[.attributes["gen_ai.client.hook.event"] // .name,
          .attributes["gen_ai.client.tool_name"] // "-"] | @tsv' \
    ~/.local/share/opentelemetry-hooks/.state/local_spans/*.jsonl
SessionStart              -
UserPromptSubmit          -
PreToolUse                write_file
PostToolUse               write_file
Stop                      -

登録した5イベントがそのまま並びます。依頼文まで見たい場合は
IDE_OTEL_CAPTURE_CONVERSATION_CONTENT を追加します(1-4 参照)。

1ターン完了させてから確認してください。
書き出しは Stop に到達した時点で行われます。途中のイベントだけではファイルが空のままになるため、
Stop まで到達した状態で確認します。

この一覧は IDE_OTEL_BATCH_ON_STOP の有無で変わります。(実測)

設定 記録される span
上記のまま(バッチ無効) 5イベントがそのまま並ぶ
IDE_OTEL_BATCH_ON_STOP=true(2-2 で追加) SessionStart が畳まれ、代わりに
ターン全体をまとめた gen_ai.client.generation が出る

バッチを有効にするとターン単位でまとめて送るため送信回数が減ります。
2-2 以降はこちらを前提にしています。

2-2. 送信先を OTLP バックエンドに向ける

otel_config.json を書き換えます。

{
  "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4317",
  "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
  "OTEL_SERVICE_NAME": "bob-agent",
  "IDE_OTEL_BATCH_ON_STOP": "true",
  "IDE_OTEL_STATE_TTL_SECONDS": "3600"
}

http/protobuf を使う場合はパスまで書いてください。
エンドポイントがそのままエクスポーターに渡るため、/v1/traces が自動補完されません。

設定値 実際の POST 先
http://collector:4318 / → 実コレクターでは 404
http://collector:4318/v1/traces 正常

既定の grpc では、この問題は発生しません。

ローカル出力から切り替えるときは IDE_OTEL_LOCAL_SPANS を消すか "false" にしてください
(残しておくと端末にもファイルが保存され続けます)。
IDE_OTEL_BATCH_ON_STOP はターン単位でまとめて送る設定で、hook 呼び出しごとの送信を減らせます。
これを入れると 2-1 で見た一覧の形が変わります(SessionStart が畳まれ、
代わりにターン全体をまとめた gen_ai.client.generation が出ます)。

IDE_OTEL_STATE_TTL_SECONDS を短くしているのは、Bob のイベント仕様に合わせるためです。
Bob には「セッション終了」のイベントが無いため、セッション全体をまとめる記録は
一定時間操作されなかった時点で書き出されます。既定は 24 時間のため、短く設定するとバックエンドへ反映されるまでの時間を短縮できます。

依頼文やコードを送信する場合は、通信経路と保管先を保護してください。
上のサンプルでは動作確認用に平文 HTTP を記載しています。本番環境では TLS と認証を設定します。

{
  "OTEL_EXPORTER_OTLP_ENDPOINT": "https://collector.example.com:4317",
  "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
  "OTEL_EXPORTER_OTLP_INSECURE": "false",
  "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer%20<token>"
}
  • OTEL_EXPORTER_OTLP_INSECURE: "false" で gRPC を TLS にする
    http/protobuf の場合は https:// スキームで判定されます)
  • OTEL_EXPORTER_OTLP_HEADERS で認証を付ける(値は URL エンコード)
  • バックエンド側のアクセス制御も設計に含める。依頼文を開けるなら、
    トレースの閲覧権限が、依頼文やコードを閲覧できる範囲になります

2-3. 組織全体へ適用する(EnforcedHooks)

組織展開では、2章冒頭の図に示した3つの対象をそれぞれ配布・管理します。
EnforcedHooks が担当するのは Bob 上の hook 登録であり、runner と送信設定は別途配布します。

(1) otel-hook と送信設定を配布する

MDM や構成管理ツールで、runner を全端末の同じ絶対パスに配置します。
以下では /opt/otel-hook/bin/otel-hook を例にします。

送信先とプライバシー設定もあわせて配布します。
Bob のポリシーに含まれるのは hook の登録情報だけです。

経路 パス スコープ
MDM / レジストリ macOS: /Library/Managed Preferences/dev.o11y.opentelemetry-hook.plist
Windows: HKLM\SOFTWARE\Policies\OpenTelemetryHook
端末単位
otel_config.json ~/.local/share/opentelemetry-hooks/otel_config.json ユーザー単位

otel_config.json はユーザープロファイル配下にあるため、共用端末や新規プロファイルでは配布漏れが生じる可能性があります。
組織展開では、MDM やレジストリによる端末単位の設定が適しています。

設定の優先順位は 環境変数 > MDM / レジストリ > otel_config.json > 既定値 です。
MDM / レジストリの値は otel_config.json より優先されますが、明示的な環境変数はさらに優先されます。
Bob の起動環境で利用者が環境変数を変更できる場合は、その制御も端末管理の対象に含めます。

端末または OS ユーザーに紐づく識別子を付与する方法は、3-1 に記載しています。

(2) ポリシーに設定する値を生成する

$ otel-hook policy --bob --hook-cmd /opt/otel-hook/bin/otel-hook --raw
{"PostToolUse":[{"hooks":[{"command":"/opt/otel-hook/bin/otel-hook --bob","timeout":30,"type":"command"}],"matcher":".*"}],"PreToolUse":[...],"SessionStart":[...],"Stop":[...],"UserPromptSubmit":[...]}

上の出力は表示のため一部を [...] で省略しています。
実際には5イベントすべてが展開された1行の JSON が出力されるため、手元でコマンドを実行した結果を使用してください。

オプション 用途
--raw ポリシー欄に設定する1行 JSON
(なし) 整形表示。レビューや差分確認用
--escaped 別の JSON / plist に入れ子で埋め込む場合
--timeout N タイムアウト秒数(既定 30)
--portable PATH に依存する形式。組織展開では非推奨

組織展開では、--portable ではなく絶対パスを指定する構成を推奨します。
PATH が通っていない端末では hook が失敗しますが、hook の失敗はエージェントの利用を停止しません。
そのため、利用者側に明確なエラーが表示されないまま、記録だけが欠ける可能性があります。

(3) EnforcedHooks を配布する

キー名は PascalCase の EnforcedHooks です。
Bob のグループポリシーは DisabledAutoApprovalGroups / UpdateMode /
GatewayUrl / EnforcedHooks と、すべて PascalCase です。

生成した1行を、Bob のグループポリシー EnforcedHooks の値として配布します。
配布先は OS ごとに異なります。

OS 配布先 配布方法
macOS managed preferences ドメイン com.ibm.bob .mobileconfig を MDM(Jamf Pro / Intune / Mosyle / Kandji)で配布
Windows レジストリ Software\Policies\IBM\Bob の値 EnforcedHooks ADMX/ADML を PolicyDefinitions に配置して GPO、または Intune
Linux /etc/bob/policy.json(root 所有・chmod 644 Ansible / Chef / Puppet / Salt、または手動配置

EnforcedHooks だけを設定した場合、ほかのグループポリシーには影響しません。
Bob は起動時にポリシーを読み込むため、OS を問わず、ポリシー変更後は Bob IDE を再起動して反映を確認します。

値が空、または JSON として不正な場合、EnforcedHooks は適用されず、利用者側の hook 設定のみが有効になります。
この動作はロールバックにも利用できますが、入力ミスによって記録が停止する可能性もあるため、配布後の確認が必要です。

ポリシーで定義した hook は、利用者定義の hook に追加して実行されます。
利用者側の hook 設定が削除されるわけではありません。
利用者がユーザー設定やワークスペース設定から削除・上書きできないのは、ポリシーで定義された hook 登録です。
runner の実行ファイルが存在すること、コマンドが正常に終了すること、OTLP 送信が成功することまでは保証されません。

2-4. 配布後に確認する

hook の失敗は利用者の作業を停止しないため、設定ミスは「エラー」ではなく「データが届かない」という形で現れます。
配布後は、端末側とバックエンド側の双方を確認します。

端末側 — 代表的な端末で登録状況を確認する

otel-hook diagnose --agent bob    # 5 イベントが登録されているか
otel-hook doctor --agent bob      # 送信の健全性と未送信データの滞留

doctor は、送信先が未設定であるなどの劣化状態で終了コード 1 を返します。
スクリプトで判定する場合は --json を利用できます。

バックエンド側 — 配布対象と受信状況を照合する

直近24時間などの期間を決めて、次の点を確認します。

  • enduser.id または host.name の distinct 数
  • gen_ai.client.name = bob の span が届いているか
  • 特定の端末や識別子だけデータが届いていない状態がないか

enduser.idhost.name の distinct 数は、データを送信した識別子の数です。
実際の利用者数と一致するとは限らず、Bob を利用していない端末と送信に失敗した端末も区別する必要があります。
配布対象、利用状況、バックエンドの受信状況を定期的に照合できると、欠損を把握しやすくなります。

2-5. ロールバック

EnforcedHooks の値を空にすると、ポリシーで定義した hook 登録は適用されなくなります。
不正な JSON も無視されますが、ロールバック手段としては意図が明確な空の値を使用する方が安全です。
変更後は Bob IDE を再起動し、代表端末でポリシーの反映を確認します。

完全に撤去する場合は、runner の配布と、各端末の MDM / レジストリ設定または otel_config.json の配布も取り消します。


3. 制限事項と補足

導入判断に関わる制限と、検証環境で確認した内容をまとめます。
仕様として記載されている内容と、実測に基づく内容は分けて扱う必要があります。

制限 影響 対応方法
Bob アカウントの利用者情報が既定で入らない 利用者との直接的な対応づけができない 構成管理側の識別子を付与(3-1)
hook 1回あたり約 150 ms ツール呼び出しごとに前後2回加算 matcher で対象を絞る(3-2)
SessionEnd イベントが無い セッション単位の記録が TTL 経過後になる IDE_OTEL_STATE_TTL_SECONDS を短縮
hook の失敗が非ブロッキング 設定ミスが「データが届かない」形で現れる 配布後の確認を運用に含める(2-4)
不正な JSON でポリシーが無視される 入力ミスで記録が停止する ポリシー更新後に確認(2-4)
ポリシーは Bob 起動時に読み込まれる 実行中の変更が直ちに反映される前提にできない Bob IDE を再起動して確認(2-3)
HTTP 送信でパスが補完されない /v1/traces 未指定の場合は 404 パスまで指定(2-2)
otel_config.json はユーザー単位 共用端末や新規プロファイルで配布漏れが生じる MDM/レジストリで配布(2-3)
本文の取得設定が対象ごとに分かれている 想定より広い範囲の本文を取得する可能性がある 対象を確認して有効化(1-4, 3-3)
本文に文字数上限がある 長い依頼文が途中で切れる IDE_OTEL_TEXT_MAX_CHARS(既定 4000)
ポリシー適用の確認は IDE で実施 headless bob run では未検証 IDE で1ターン実行して確認
サブエージェント専用イベントが無い 委譲を専用イベントとして追跡できない tool_name=spawn_subagent を確認

3-1. 利用者を示す情報は、既定では記録されません

Bob 2.0.2 で確認した hook ペイロードには、Bob アカウントの利用者 ID やメールアドレスに相当するフィールドは含まれていませんでした。
端末情報として確認できたのも、os.type / os.name / os.version / host.arch までで、ホスト名や OS ユーザー名は含まれていません。

IDE_OTEL_CAPTURE_USER_IDENTITY は、hook ペイロードに user_id / user_email が含まれる場合に利用する設定です。
今回の Bob 環境では、その設定だけで利用者情報が記録されることは確認できませんでした。

session_id によるセッション単位の紐づけと、cwd をもとにしたプロジェクト情報は自動で記録されます。
そのため、プロジェクト単位の利用状況は確認できますが、個人単位の対応づけが必要かどうかは監査要件や運用目的に応じて判断します。

識別子が必要な場合は、配布設定の OTEL_RESOURCE_ATTRIBUTES で付与できます。
以下は、検証環境で反映を確認した例です。

{ "OTEL_RESOURCE_ATTRIBUTES": "enduser.id=t.yamada,host.name=MBP-12345" }

ここで付与する enduser.idhost.name は、Bob の認証情報から取得した値ではなく、構成管理側で付与した属性です。
Bob が実際の利用者本人を認証・確認した結果ではありません。
共用端末、OS ユーザーの変更、プロファイルの再作成、設定更新の遅延などがある場合、属性と実際の利用者が一致しない可能性があります。

値は端末または OS ユーザーごとに異なるため、MDM や構成管理ツールで変数を差し替えて配布します。
2-4 で識別子の distinct 数を確認する運用を行う場合は、この属性付与が前提になります。

識別子を付与するかどうかは、収集目的に応じて決めます。
利用状況の集計だけで足りる場合は不要ですが、個人単位の追跡を要件とする場合は、属性の付与方法、更新手順、利用者への周知をあわせて設計します。

3-2. オーバーヘッドとデータ量

組織展開時の参考として、検証環境で測定した値を記載します。
Apple Silicon / macOS / Python 3.12 での参考値です。環境で変わります。

hook 1回あたりの実行時間: 約 150〜160 ms

PreToolUse / PostToolUse はツール呼び出しごとに走ります。つまり
1ツール呼び出しで前後2回、約 0.3 秒が加算されます。
ほとんどは Python インタプリタの起動時間で、送信の有無ではほぼ変わりませんでした
(ローカル出力のみ 160 ms / 送信先未設定 153 ms)。

エージェントの1ターン全体に対する割合は比較的小さいと考えられます。
ただし1ターンで10個のツールを呼ぶような使い方では数秒単位になります。
オーバーヘッドを抑える場合は、matcher で観測対象のツールを限定できます。

timeout: 30 はこの実行時間に対して余裕を持たせた値です。
実測 150 ms に対して大きいのは、初回起動時の依存解決や
送信先が遅い場合を吸収するためです(2-3 参照)。

データ量: 1ターンあたり 5 span / 約 9 KB

設定 1ターン 1 span あたり
既定(ハッシュのみ) 5 span / 約 8.7 KB 約 1.7 KB
本文取得あり 5 span / 約 9.2 KB 約 1.8 KB

ツール呼び出しが増えると span 数は増えます(1ツールにつき2 span)。
本文取得を有効にしても、短い依頼文であればデータ量の差は限定的でした。長い依頼文や
大きなツール入力は、IDE_OTEL_TEXT_MAX_CHARS(既定 4000 文字)で上限が設定されます。

単純計算では、1ユーザーが1日20ターン利用すると約 180 KB/日、100ユーザーで 18 MB/日 程度です。
監査目的で長期保管する場合は、保持期間もあわせて設計します。
「利用状況の集計データは長期、本文は短期」といった保持期間の分離も検討できます。

3-3. マスキングはどこまで効くか

この節は仕様書に記載のない挙動です。 検証環境で確認した結果に基づいており、
今後のバージョンで変わる可能性があります。実運用に入れる前に、
利用環境と対象データで確認してください。

IDE_OTEL_MASK_PROMPTS=true を設定した場合、検証した範囲では、
1-4 のどの本文取得設定を有効にしていてもマスキングが適用されました。
依頼文、応答、ツール入力、ツール応答で動作を確認しています。

入力: tanaka@example.com のキー ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345 を使って
記録: [REDACTED_EMAIL] のキー [REDACTED_TOKEN] を使って

ファイル内容: API_KEY=ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ012345
記録:         API_KEY=[REDACTED_TOKEN]

ただし、マスキングには次の制約があります。

  1. マスキングは明示的に有効化する必要があります。 IDE_OTEL_CAPTURE_TOOL_INPUT_CONTENT
    だけを有効にすると、ツール入力に含まれたシークレットが平文でバックエンドへ送られる可能性があります。
    本文を取得する場合は、IDE_OTEL_MASK_PROMPTS もあわせて設定します。
  2. マスキングはパターンマッチです。 メールアドレスや一般的なトークン形式はマスクできますが、
    社内独自の形式やコード内の機密値が残る可能性があります。
    マスキングだけで機密情報の除去を保証することはできません。
    収集対象に含められない情報がある場合は、本文取得を有効にしない構成が確実です。

4. 実装について

追加した実装の概要(クリックで展開)

本記事では、既存 OSS に Bob 固有の処理を追加しています。

土台は o11y-dev/opentelemetry-hooks(MIT)です。
AI コーディングエージェントの hook イベントを OpenTelemetry に変換する runner で、
8つのプロバイダー(cursor / claude / codex / copilot / gemini / windsurf / opencode / antigravity)に対応しています。
プロバイダーごとの差異をアダプターとして分離する構造になっているため、Bob も追加のアダプターとして実装しました。

主な追加点は次の3つです。

追加したもの 役割
BobEventAdapter Bob のフィールド名を共通形式に変換する
BobHookResponseAdapter stdout に処理結果を出力しないようにする
setup_bob() / policy コマンド hook 登録と EnforcedHooks 値の生成を行う

span 生成、セッション相関、バッチ送信、プライバシー制御、MDM 対応などは既存処理を再利用しています。
Bob 固有部分として追加した実装は 336 行です。

特に注意が必要だったのは stdout の扱いです。
Bob は SessionStartUserPromptSubmit の hook の stdout をモデルコンテキストへ渡します。
上流版は処理完了時に {"continue": true} を stdout へ出力するため、そのまま利用すると、この JSON がモデルコンテキストに含まれます。
Bob では hook の制御に終了コードを使用し、観測用途では stdout へ返す情報がないため、Bob 向けアダプターでは全イベントを無出力にしています。

Bob 2.0.2 の hook ペイロードでは、次のフィールドを確認しました。
Bob 対応アダプターは、これらを共通の OpenTelemetry 属性へ変換します。

Bob のフィールド 内容 アダプターでの扱い
hook_event_name イベント名 共通イベント名へ正規化
tool_name 利用したツール ツール名として記録
tool_input ツールへの入力 設定に応じて内容またはハッシュを記録
tool_response ツールの実行結果 設定に応じて内容またはハッシュを記録
last_assistant_message エージェントの最終応答 応答本文として記録

フィールド形式は Claude Code の hook ペイロードに近く、上流の共通処理を再利用しやすい構造でした。
また、アダプターは公開仕様で示される event / tool / input / output の形式にも対応しています。ペイロード形式の違いはアダプター側で吸収されるため、依頼文、ツール入出力、最終応答を同じデータモデルで扱えます。

実装の詳細は、リポジトリのコードとコミットログに記載しています。
otel_hook.py の差分、tests/test_bob.py、日本語セットアップガイド(BOB-SETUP.ja.md)を確認できます。


5. 参考:上流側で気づいた挙動

上流 v0.14.0 で確認した3点(クリックで展開)

検証の過程で、上流版 v0.14.0 の挙動についても3点確認しました。
いずれも Bob 固有ではなく、--claude などでも同様に再現しました。

確認した挙動 内容
PostToolUsegen_ai.client.namecodex になる tool_response の存在をプロバイダー推定のシグナルとして使用しているため。このフィールドは Claude Code・Bob・Codex が共通で送るため、1セッションの記録が複数のクライアント名に分かれる
gen_ai.request.model に Claude のモデル名が入る モデル属性のフォールバックが環境変数 CLAUDE_MODEL / ANTHROPIC_MODEL を参照するため。これらが設定された端末では、ほかのエージェントの記録にも Claude のモデル名が入る可能性がある
IDE_OTEL_DEBUG_CONSOLE が stdout に出力する stdout がモデルコンテキストへ渡される runner では、観測用の出力がモデル入力に混在する可能性がある

フォークでは、明示的に指定されたプロバイダー情報を、汎用フィールドからの推測で上書きしない方針で修正しています。


6. まとめ

  • Bob の lifecycle hooks を利用すると、依頼文、ツール利用、ツール入出力など、hook ペイロードに含まれる情報を OpenTelemetry 形式で記録できます
  • EnforcedHooks は、管理者が定義した hook 登録を Bob IDE に適用し、利用者設定から削除・上書きできない状態にします。ただし、runner の配置、設定、通信、保存先は別途管理します
  • 本文は既定で取得されません。必要に応じて、ハッシュのみ、マスキングを適用した本文、本文取得といった範囲を設定できます
  • Bob 対応アダプターは、依頼文、ツール入出力に加えて、エージェントの最終応答も共通形式へ変換して記録します。Bob アカウントの利用者情報は hook ペイロードに含まれないため、個人単位の対応づけには外部属性を利用します
  • hook の失敗は利用者の作業を停止しないため、端末への配布確認とバックエンドの受信確認を運用に含めます
  • 実装は既存 OSS のアダプター構造を利用し、Bob 固有のフィールド変換、stdout 制御、設定生成を追加しています

参考

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?