giip
SES 안건 등록
5분 읽기

에이전트 등록 및 큐 API 명세

이 문서는 AI 에이전트(또는 임의의 호스트)를 GIIP 논리 머신으로 등록하고, 자신의 CQE 태스크 큐를 폴링하며, 실행 결과를 보고하는 기술 명세다 — 프로덕션의 giipAgentWin/giipAgentLinux가 실제로 사용하는 것과 동일한 메커니즘이다.

🔌 giip-agent 스킬 번들로 이동 →

📋 개요

이 API는 호스트 — giipAgentWin/giipAgentLinux를 실행 중인 물리/가상 머신, 또는 자체 하드웨어 정체성이 없는 AI 코딩 에이전트 세션 — 가 자신을 tLSvr에 논리 머신(lssn)으로 등록한 뒤, 그 lssn의 CQE(Centralized Queue Engine) 태스크 큐를 폴링하고 결과를 보고할 수 있게 한다. 세 동작 모두 하나의 엔드포인트를 통한다.


🔐 인증 — 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) — 파라미터 이 아님
tokenSK, 일반 폼 필드로 전송. 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만 필수이고 나머지 필드는 best-effort이며 생략 가능하다.

식별 키는 (hostname, csn)이다. 스토어드 프로시저(pApiAgentAutoRegisterBySK)는 LSHostname = hostname AND CSn = <SK로부터 도출> 조건으로 tLSvr을 조회한다:

기존 행 존재?동작응답
없음tLSvrINSERT, 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 도구는 각자의 hostname으로(따라서 각자의 lssn으로) 등록해야 한다 — 같은 PC에서 돌아가는 Claude Code, Codex, Antigravity는 서로 다른 세 논리 머신이다(예: Lowy-DP01-claude-code, Lowy-DP01-codex, Lowy-DP01-antigravity). 이는 서버가 강제하는 제약이 아니라 문서/클라이언트 차원의 규율이다 — 서버는 어떤 hostname을 보내든 그대로 생성하므로, 규율은 호출하는 쪽에서 지켜야 한다.

잘못된 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 차원의 "작별 인사"는 없다.


🔍 응답 표준

세 명령 중 무엇을 호출하든 giipApiSk2 호출은 항상 결과를 data 배열로 감싼다:

{ "data": [ { "RstVal": 200, ... } ] }
  • 성공: RstVal200(가끔 AgentAutoRegister/CQEQueueGet의 엣지 케이스에서 201). RstVal은 명령에 따라 숫자 또는 숫자 문자열이다 — 이 명세의 클라이언트 스크립트는 둘 다 처리하기 위해 문자열로 비교한다.
  • poll의 "작업 없음": RstVal 0 또는 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을 반환하는 단일 디스패처 엔드포인트에 보낸다.
  • 호스트명 규칙은 서버 제약이 아니라 클라이언트 측 규율이다. 서로 다른 두 도구에 대해 foo를 두 번 등록하는 것을 막는 장치는 없다 — 하지만 그렇게 하면 서로의 큐 이력을 헷갈리게 하는 두 개의 lssn이 생긴다. <host>-<tool-slug> 규칙을 엄격히 지킬 것.
  • 시스템 정보 페이로드가 바뀌어도 반복 register는 여전히 heartbeat다 — 새 머신이 아니다. 정체성을 결정하는 것은 오직 hostname 문자열이다.

문제 해결

증상원인해결
AgentAutoRegister에서 data[0].RstVal401SK가 유효하지 않거나 재발급됨/svclist에서 SK 재확인
poll이 계속 RstVal 404/has_work: false실제로 큐가 없거나, lssn이 이 SK와 다른 csn 소속register를 재실행해 반환된 lssn을 비교
reportRstVal 411 반환lssn이 이 SK의 키 그룹(cgsn) 소유가 아님자신의 register 호출이 반환한 lssn에만 보고
HTTP 상태 자체가 200이 아님전송 계층 실패(네트워크, 라우터 자체가 거부한 잘못된 요청)RstVal 실패와는 다름 — 연결 확인 후 재시도가 합리적일 수 있음(RstVal 실패는 재시도 금지)
한 머신이라고 생각했는데 서로 다른 lssn 두 개가 나타남hostname 구성이 일관되지 않음(다른 --tool-slug 사용, 또는 bare hostname으로 오버라이드)hostname은 항상 <host>-<tool-slug>로 구성하고 호출 간 안정적으로 유지

버전: 1.0 최종 갱신: 2026-09-06 (giipfaw 프로덕션 라이브 검증, csn 47, 결과 lssn 71290) 소스 파일: giipv3/public/help/giip-agent-api.ko.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)을 문서화했다. 라이브 검증: register 1회(신규 lssn 71290), 반복 register 1회(heartbeat, 동일 lssn), poll 1회(큐 없음).


관련 문서: