エージェント登録およびキューAPI仕様
この文書は、AIエージェント(または任意のホスト)をGIIP論理マシンとして登録し、自身のCQEタスクキューをポーリングし、実行結果を報告するための技術仕様である — 本番環境のgiipAgentWin/giipAgentLinuxが実際に使用しているものと同じ仕組みである。
📋 概要
このAPIは、ホスト — giipAgentWin/giipAgentLinuxを実行する物理/仮想マシン、または自身のハードウェア的な識別情報を持たないAIコーディングエージェントセッション — が自身をtLSvrに論理マシン(lssn)として登録し、そのlssnのCQE(Centralized Queue Engine)タスクキューをポーリングし、結果を報告できるようにする。3つの操作はすべて1つのエンドポイントを通る。
🔐 認証 — REST系とは異なる単一ディスパッチャーエンドポイント
課題管理APIとはAPIの形が異なる。 そちらは
x-api-keyヘッダーと実際のHTTPステータスコードを使う通常のRESTエンドポイント(/api/giipIssues)である。このAPIはgiipApiSk2— フォームエンコード方式の単一汎用ディスパッチャーエンドポイントで、常にHTTP 200を返す。
ベースURL
https://giipfaw.azurewebsites.net/api/giipApiSk2
リクエスト形式(常に同じ3つのフィールド)
| フィールド | 内容 |
|---|---|
text | ストアドプロシージャの「コマンド」名とそのパラメータ名をスペース区切りで列挙(例: AgentAutoRegister hostname jsondata)— パラメータの値ではない |
token | SK、通常のフォームフィールドとして送信。HTTPヘッダーではない。 |
jsondata | 実際のパラメータ値を保持するJSONオブジェクト |
curl -s -X POST "https://giipfaw.azurewebsites.net/api/giipApiSk2" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "text=AgentAutoRegister hostname jsondata" \
--data-urlencode "token=${GIIP_API_KEY}" \
--data-urlencode 'jsondata={"hostname":"Lowy-DP01-claude-code","os":"Windows 10"}'
HTTPステータスコードはほとんど何も教えてくれない
このエンドポイントが解析できるリクエストはすべて200 OKを返す。 無効なSKに対する401も、存在しないlssnに対する404も、権限問題に対する403もない。実際の結果は常にJSONボディのdata[0].RstValに含まれる(giipfaw/giipApiSk2/run.ps1のソースレビューおよびライブテストで確認、2026-09-06):
{"data":[{"Proc_MSG":"401|Unauthorized - Invalid SK","RstVal":401,"RstMsg":"Unauthorized - Invalid Secret Key"}]}
上記の応答もHTTP 200である。giipApiSk2呼び出しの実際の成功・失敗は、HTTPステータスではなく常にdata[0].RstValで判断すること。
SK — Issue APIと同じ鍵種、異なる伝送方式
- Issue APIが使うものと同じ、
/svclistで発行されるcsn単位のプロジェクトSKである — ただしここではx-api-keyヘッダーではなくPOSTボディのtoken=<sk>として送信する。 - csnはSKからサーバー側で導出される(
dbo.lwGetCSNbysk(@sk))— リクエストにcsnを直接送ることはなく、AgentAutoRegister/CQEQueueGetにはクライアント指定のcsnを暗黙にクランプする余地自体が存在しない(giipdb/SP/pApiAgentAutoRegisterBySK.sqlのレビューで確認、2026-09-06)。KVSPutは関連するが異なる所有権チェックを行う — 下記参照。
エンドポイント
AgentAutoRegister — 論理マシンの登録、または既存マシンのheartbeat
リクエスト:
text=AgentAutoRegister hostname jsondata
token=<sk>
jsondata={
"hostname": "Lowy-DP01-claude-code",
"os": "Windows 10",
"cpu": "...", "cpu_cores": 8, "memory_gb": 32, "disk_gb": 512,
"agent_version": "giip-agent-skill/1.0.0",
"ipv4_global": "...", "ipv4_local": "...",
"network": [{"name":"eth0","ipv4":"...","ipv6":"...","mac":"..."}],
"software": [{"name":"...","version":"...","vendor":"...","type":"..."}],
"services": [{"name":"...","status":"...","start_type":"...","port":80}]
}
hostnameのみ必須で、他のフィールドはベストエフォートであり省略可能。
識別キーは(hostname, csn)である。 ストアドプロシージャ(pApiAgentAutoRegisterBySK)はLSHostname = hostname AND CSn = <SKから導出>の条件でtLSvrを検索する:
| 既存行あり? | 動作 | 応答 |
|---|---|---|
| なし | 新しいtLSvr行をINSERT、lssn = SCOPE_IDENTITY() | {"data":[{"lssn":<new>,"action":"new","RstVal":200,...}]} |
| あり | 既存行をUPDATE(スペック、ネットワーク/ソフトウェア/サービスのインベントリ、LSLastHeartbeat) | {"data":[{"lssn":<same>,"action":"update","RstVal":200,...}]} |
ライブ検証済み(2026-09-06、csn 47):
$ python scripts/giip_agent.py register --tool-slug claude-code
{"success": true, "hostname": "Lowy-DP01-claude-code", "lssn": 71290, "action": "new"}
$ python scripts/giip_agent.py register --tool-slug claude-code # 繰り返し呼び出し
{"success": true, "hostname": "Lowy-DP01-claude-code", "lssn": 71290, "action": "update"}
必須のホスト名規則: <物理ホスト名>-<tool-slug>。同じホスト上の異なるAIツールはそれぞれ自身のホスト名で(したがって自身のlssnで)登録しなければならない — 同じPCで動くClaude Code、Codex、Antigravityは互いに異なる3つの論理マシンである(例: Lowy-DP01-claude-code、Lowy-DP01-codex、Lowy-DP01-antigravity)。これはサーバーが強制する制約ではなく、文書/クライアント側の規律である — サーバーはどんなホスト名を送っても、そのまま作成してしまうため、この規律は呼び出す側が守らねばならない。
無効なSKは401を返さず、data[0]内でRstVal: 401として表現される({"Proc_MSG":"401|Unauthorized - Invalid SK",...})。
CQEQueueGet — このlssnのキューを一度だけポーリング
リクエスト:
text=CQEQueueGet lssn hostname os op
token=<sk>
jsondata={"lssn":71290,"hostname":"Lowy-DP01-claude-code","os":"Windows 10","op":"op"}
応答、作業あり:
{"data":[{"RstVal":"200","ms_body":"<script or payload text>","mslsn":8032,"script_type":"sh","mssn":123}]}
応答、キューなし(ライブ検証、2026-09-06)— これは成功でありエラーではない:
{"data":[{"RstVal":"404","ProcName":"[pCQEQueueGetbySK02] no queue 2"}]}
$ python scripts/giip_agent.py poll --lssn 71290 --tool-slug claude-code
{"success": true, "lssn": 71290, "has_work": false}
RstValの意味(giipdb/SP/pApiCQEQueueGetbySK.sqlのレビューで確認、2026-09-06):
RstVal | 意味 |
|---|---|
200 | キューに作業あり; ms_body/mslsn/mssn/script_typeが入力される |
201 | 新規lssnへの初回ポーリングが暗黙の再登録経路を発動 — 「まだ作業なし」と同様に扱い、少し待って再ポーリング |
0または404 | 確認したが現在キューなし — 正常、エラーではない |
| それ以外 | 実際のエラー |
推奨ポーリング間隔: 60秒。 実際のgiipAgentLinuxインストールがcronで使う間隔(* * * * *)と一致する。このAPI自体はポーリングをレート制限しないが、それより速くポーリングする理由はない — キューはGIIP自身のスケジュールで埋められる。
誤ったlssnは「作業なし」と区別がつかない。 ポーリングするlssnがそのSKのcsnに属していない場合、保留中の作業を探す結合(tMgmtScriptList ms inner join tLSvr ls on ... where ls.csn = @csn and ms.lssn = @lssn)は該当行を見つけられず、空のキューと同じRstVal: 404を返す。別個の「権限なし」や「lssnなし」応答は存在しない — 誤ったlssnをポーリングしていると疑う場合は、registerを再実行して比較すること。
KVSPut(kFactor=cqeresult)— 結果の報告
専用の「完了/ack」コマンドは存在しない。結果は、GIIPのすべてのエージェントテレメトリで使われるのと同じ汎用キーバリューメカニズムであるKVSPutで書き込む。
リクエスト:
text=KVSPut kType kKey kFactor
token=<sk>
jsondata={
"kType": "lssn", "kKey": "71290", "kFactor": "cqeresult",
"kValue": {"mslsn": 8032, "mssn": 123, "lssn": 71290,
"status": "success", "exit_code": 0,
"stdout": "...", "stderr": ""}
}
kTypeは文字列リテラル"lssn"でなければならず、kKeyは結果が属するlssn(文字列)でなければならない。
register/pollと異なり、この呼び出しは所有権を検証し、きれいに失敗する(giipdb/SP/pApiKVSPutbySk.sqlのレビューで確認、2026-09-06):SPは書き込み前にEXISTS(SELECT 1 FROM tLSvr WHERE LSsn = @kKey AND CGSn = <SKから導出>)を確認する。lssnがそのSKのキーグループの所有でない場合:
{"data":[{"RstVal":411,"RstMsg":"..."}]}
reportで200以外のRstValはすべて致命的な失敗として扱うこと — heartbeatのように再試行せず、結果を黙って破棄しないこと。
登録解除(unregister/deregister)エンドポイントなし
論理マシンを削除する呼び出しは存在しない。heartbeatを送らなくなったマシンは単に古くなっていくだけである(LSLastHeartbeatが古くなる)— API上の「さようなら」は存在しない。
🔍 応答標準
3つのコマンドのどれを呼び出しても、giipApiSk2呼び出しは常に結果をdata配列で包む:
{ "data": [ { "RstVal": 200, ... } ] }
- 成功:
RstValが200(AgentAutoRegister/CQEQueueGetのエッジケースでは201のこともある)。RstValはコマンドによって数値または数値文字列である — この仕様のクライアントスクリプトは両方に対応するため文字列として比較する。 - pollの「作業なし」:
RstVal0または404— 成功であり失敗ではない。 - 失敗: それ以外の
RstValと、理由を説明するRstMsg/Proc_MSG/ProcName。 - トランスポート層の失敗(ネットワークエラー、タイムアウト、200以外のHTTPステータス): リクエストがストアドプロシージャに到達すらしなかったことを意味する —
RstVal失敗とはまったく異なる失敗モードである。
🤖 AIエージェントのための完全な手順(登録 → ポーリング → 報告)
export GIIP_API_KEY="<the SK>"
# 1. 登録(冪等 — 初回呼び出しはlssnを作成し、同じhostnameへの
# 以降の呼び出しはそのlssnへのheartbeatになる)
python scripts/giip_agent.py register --tool-slug claude-code
# {"success": true, "hostname": "Lowy-DP01-claude-code", "lssn": 71290, "action": "new"}
# 2. 一度ポーリング。自身のスケジュール(~60秒)で繰り返すこと -- 内部でループしないこと。
python scripts/giip_agent.py poll --lssn 71290 --tool-slug claude-code
# {"success": true, "lssn": 71290, "has_work": false}
# 3. has_workがtrueならms_bodyを処理し、結果を報告。
python scripts/giip_agent.py report --lssn 71290 --mslsn 8032 --mssn 123 \
--status success --exit-code 0
⚠️ 重要な注意事項
- 課題管理APIとは異なるAPI系統である。 両者を混同しないこと:
giip-issueのクライアントはSKをx-api-keyヘッダーとして実際のHTTPステータスコードを持つRESTエンドポイントに送り、giip-agentのクライアントはSKをtokenフォームフィールドとして常にHTTP 200を返す単一ディスパッチャーエンドポイントに送る。 - ホスト名規則はサーバー制約ではなくクライアント側の規律である。 異なる2つのツールに対して
fooを2回登録することを止める仕組みはない — しかしそうすると、互いのキュー履歴を混乱させる2つのlssnが生まれる。<host>-<tool-slug>規則を厳格に守ること。 - システム情報のペイロードが変わっても、繰り返しの
registerは依然としてheartbeatである — 新しいマシンではない。識別を決定するのはhostname文字列のみである。
トラブルシューティング
| 症状 | 原因 | 解決策 |
|---|---|---|
AgentAutoRegisterでdata[0].RstValが401 | SKが無効または再発行された | /svclistでSKを再確認 |
pollが常にRstVal 404/has_work: false | 実際にキューがないか、lssnがこのSKと異なるcsnに属している | registerを再実行し、返されたlssnを比較 |
reportがRstVal 411を返す | lssnがこのSKのキーグループ(cgsn)の所有ではない | 自分のregister呼び出しが返したlssnにのみ報告する |
| HTTPステータス自体が200でない | トランスポート層の失敗(ネットワーク、ルーター自体が拒否した不正なリクエスト) | RstVal失敗とは異なる — 接続確認後の再試行は合理的(RstVal失敗は再試行禁止) |
1つのマシンだと思っていたのに異なるlssnが2つ現れる | ホスト名の構成が一貫していない(異なる--tool-slugの使用、またはbareホスト名でのオーバーライド) | ホスト名は常に<host>-<tool-slug>で構成し、呼び出し間で安定させること |
バージョン: 1.0
最終更新: 2026-09-06(giipfaw本番環境でライブ検証、csn 47、結果lssn 71290)
ソースファイル: giipv3/public/help/giip-agent-api.ja.md
v1.0(2026-09-06、giip #2081): 初回リリース。
giipdb/SP/pApiAgentAutoRegisterBySK.sql、pApiCQEQueueGetbySK.sql、pApiKVSPutbySk.sql、giipfaw/giipApiSk2/run.ps1のソースレビューと、giipAgentLinux(scripts/giip-auto-discover.sh、lib/cqe.sh、lib/kvs.sh、cqe/giipCQE.sh)の本番クライアント動作に基づき、giipApiSk2ディスパッチャー上のAgentAutoRegister、CQEQueueGet、KVSPut(kFactor=cqeresult)を文書化した。ライブ検証:register1回(新規lssn 71290)、繰り返しregister1回(heartbeat、同一lssn)、poll1回(キューなし)。
関連文書: