# Google Antigravity CLI (`agy`) 정본 — 설치 · 인증 · Headless 실행 > **이 문서의 역할**: 이 프로젝트가 채택한 유일한 AI 에이전트 CLI 인 `agy` 에 대한 단일 정본(SSOT). 설치·인증·비대화형 실행·설정·권한·함정을 여기 한 곳에 모은다. 다른 문서는 이 문서를 참조하고 중복 서술하지 않는다. **작성 기준일**: 2026-09-02 **검증 방식**: 공식 문서 직접 열람(WebFetch) + 로컬 머신 실측(Windows 11 Pro 10.0.26220, `agy` v1.1.22) **실측 머신 경로**: `C:\Users\encep\AppData\Local\agy\bin\agy.exe` --- ## 0. 한눈에 보기 - `agy` 는 Google Antigravity 의 터미널 에이전트 CLI 다. **Go 로 작성된 단일 실행 파일**이며 Windows 에서 `%LOCALAPPDATA%\agy\bin\agy.exe` 에 설치된다. 실측 바이너리 크기 약 **186 MB**. - **Headless 는 1급 기능이다.** `agy -p "<프롬프트>" --output-format json` 으로 완전한 비대화형 실행이 되고, `status` / `response` / `usage` / `error` 를 담은 JSON 봉투를 stdout 으로 뱉는다. 종료 코드도 규약이 있다. - **인증 토큰은 파일에 저장된다.** 실측 결과 `~/.gemini/antigravity-cli/antigravity-oauth-token` 평문 JSON. 공식 문서는 OS 키링(Windows Credential Manager)을 말하지만, 실측 머신의 `cmdkey /list` 에는 관련 항목이 없었다. **이는 작업 스케줄러 무인 실행에 결정적으로 유리하다** (키링 잠금 문제를 피함). 대신 파일 유출 = 계정 탈취이므로 보안 취급 주의. - **최초 1회는 대화형 로그인이 필수다.** 헤드리스는 캐시된 자격증명을 쓴다. 따라서 부트스트랩 설계에 "미인증 감지 → 사용자에게 프롬프트 창 띄우기" 경로가 반드시 필요하다. - **`--json-schema` 는 신뢰할 수 없다(실측).** 문서상 `structured_output` 필드로 검증된 객체가 온다고 하지만, 실측에서는 `structured_output` 이 없고 `response` 안에 JSON 조각이 4번 반복되어 섞여 나왔다. **파이프라인은 반드시 자체 파싱·검증 계층을 둬야 한다.** - **첫 호출 오버헤드가 크다(실측).** "OK 한 단어만 답하라"는 프롬프트에 **input_tokens 28,317 / 33.7초**. 시스템 프롬프트와 워크스페이스 인덱싱 비용이다. 짧은 작업을 여러 번 호출하는 설계는 비싸다. **호출을 묶어라.** - 기본 `--print-timeout` 은 **5분**. 배치에서는 명시적으로 늘려 잡는다. - 자동 백그라운드 self-update 가 돌기 때문에 배치 실행 중 업데이트 충돌 위험이 있다. `AGY_CLI_DISABLE_AUTO_UPDATE=true` 로 끄고 주 1회 계획 업데이트하는 것을 권한다. --- ## 1. 목차 1. [제품 정체성과 위치](#2-제품-정체성과-위치) 2. [설치](#3-설치) 3. [인증](#4-인증) 4. [Headless(비대화형) 실행 정본](#5-headless비대화형-실행-정본) 5. [출력 포맷 3종 상세](#6-출력-포맷-3종-상세) 6. [구조화 출력과 그 함정](#7-구조화-출력과-그-함정) 7. [모델 · 에이전트 · 추론 강도](#8-모델--에이전트--추론-강도) 8. [권한 모델](#9-권한-모델) 9. [실행 모드](#10-실행-모드) 10. [설정 파일 전체 키](#11-설정-파일-전체-키) 11. [디렉터리·파일 레이아웃 실측](#12-디렉터리파일-레이아웃-실측) 12. [종료 코드와 오류 처리](#13-종료-코드와-오류-처리) 13. [크레딧·쿼터](#14-크레딧쿼터) 14. [트러블슈팅](#15-트러블슈팅) 15. [배치·스케줄러 관점 체크리스트](#16-배치스케줄러-관점-체크리스트) 16. [주변 생태계](#17-주변-생태계) 17. [부록 A. 출처 목록](#부록-a-출처-목록) 18. [부록 B. 미해결 질문 / 실측 필요 항목](#부록-b-미해결-질문--실측-필요-항목) --- ## 2. 제품 정체성과 위치 공식 문서 원문 인용: > "The Antigravity CLI is the lightweight Terminal User Interface (TUI) surface of Antigravity. It brings the same core agentic capabilities as Antigravity 2.0 (such as multi-step reasoning, multi-file editing, tool calling, and conversation history) directly to your terminal." | 항목 | 내용 | |---|---| | 명령어 이름 | `agy` (Windows: `agy.exe`) | | 문서 기준 버전 | v1.1.22 | | 실측 설치 버전 | **1.1.22** (`agy --version`) | | winget 최신 | 1.1.23 (`Google.AntigravityCLI`) | | 구현 언어 | Go | | 발표 | 2026-05-19 Google I/O | | 위치 | Antigravity 2.0(데스크톱/IDE)과 **동일한 에이전트 코어**, 설정 동기화, 대화 상호 export | | Gemini CLI 와의 관계 | **후속 제품**. `/docs/cli/gcli-migration` 에 확장·스킬·설정 일괄 마이그레이션 가이드 존재 | | 형제 제품 | Antigravity IDE (`agy-ide`, winget `Google.AntigravityIDE` v2.5.5), Antigravity 데스크톱 (`Google.Antigravity` v2.11.0) | **혼동 주의**: `agy` (CLI) 와 `agy-ide` (IDE 런처) 는 다른 명령이다. 2026년 5월에 IDE 런처가 `agy-ide` 로 이름이 바뀌었다. 주요 기능(공식 개요 페이지): - 키보드 중심 인터페이스 - 다단계 추론, 다중 파일 편집 - 도구 호출, 대화 이력 - **헤드리스 모드 및 백그라운드 작업 실행** - 샌드박스 환경, 서브에이전트 - MCP, 플러그인, 스킬 확장 --- ## 3. 설치 ### 3.1 공식 설치 명령 (OS별) ```bash # macOS / Linux curl -fsSL https://antigravity.google/cli/install.sh | bash ``` ```powershell # Windows PowerShell irm https://antigravity.google/cli/install.ps1 | iex ``` ```cmd :: Windows CMD curl -fsSL https://antigravity.google/cli/install.cmd -o install.cmd && install.cmd && del install.cmd ``` ### 3.2 설치 위치 | OS | 경로 | |---|---| | macOS / Linux | `~/.local/bin/agy` | | Windows | `C:\Users\\AppData\Local\agy\bin\agy.exe` | 실측 확인: ``` $ where.exe agy C:\Users\encep\AppData\Local\agy\bin\agy.exe C:\Users\encep\AppData\Local\Microsoft\WinGet\Links\agy.EXE ``` > **함정**: `where` 에 두 경로가 잡힌다. winget 으로도 설치된 이력이 있으면 WinGet Links 심볼릭이 함께 잡힌다. **배치 스크립트는 절대 경로를 고정해서 쓰는 것이 안전하다.** ### 3.3 `install.ps1` 동작 해부 (전문 확인 완료) 설치 스크립트를 직접 내려받아 전문을 읽었다. 동작 순서: 1. **TLS 1.2 강제** (ConstrainedLanguage 모드가 아닐 때만) 2. **인자 파싱**: `-d` / `--dir` 로 설치 디렉터리 커스터마이즈. 나머지 인자는 뒤의 `agy install` 로 패스스루 3. **기존 설치 감지**: `agy.exe` 가 이미 있으면 **아무 것도 하지 않고 종료 코드 0** 으로 빠진다. 메시지: > `Notice: 'agy.exe' is already installed at .` > `The Antigravity CLI automatically self-updates in the background.` > `If you want to perform a fresh installation, delete the binary first:` > ` Remove-Item "" -Force` 4. **아키텍처 감지**: `PROCESSOR_ARCHITEW6432` 우선, 없으면 `PROCESSOR_ARCHITECTURE`. `AMD64` → `windows_amd64`, `ARM64` → `windows_arm64`. 그 외는 치명적 오류. 5. **매니페스트 다운로드**: `https://antigravity-cli-auto-updater-974169037036.us-central1.run.app/manifests/.json` → `version`, `url`, `sha512` 획득 6. **스테이징 다운로드**: `%LOCALAPPDATA%\antigravity\staging\agy.exe` 7. **SHA512 검증**: `Get-FileHash` 우선, 실패 시 `certutil -hashfile ... SHA512` 폴백. 불일치 시: > `Security Halt: Checksum verification failed. The downloaded file may be corrupted or compromised.` 8. **배치 및 Unblock**: `Copy-Item` 후 `Unblock-File` (Mark-of-the-Web 제거) 9. **네이티브 셋업 핸드오프**: `& $binaryPath install $setupFlags` 실행. 실패해도 흡수(Unix 의 `|| true` 와 동일). 10. **finally 블록에서 스테이징 파일 정리** **배치 관점 시사점**: - 이미 설치돼 있으면 재실행이 **안전(idempotent)** 하다. 부트스트랩 스크립트에서 무조건 호출해도 된다. - **업데이트 목적으로는 쓸 수 없다.** 기존 바이너리가 있으면 그냥 빠진다. 업데이트는 자동 self-update 또는 `agy update` 담당. - 무결성 검증이 내장돼 있어 별도 검증 불필요. - `-d/--dir` 로 설치 경로를 프로젝트 전용으로 고정할 수 있다. ### 3.4 `agy install` 서브커맨드 (실측) ``` $ agy install --help Usage: agy.exe install [flags] Configure environment paths and shell settings Flags: --dir Custom directory target to configure PATH for -h Show help --help Show help --skip-aliases Bypasses shell profile alias purging --skip-path Bypasses shell profile PATH appending ``` 즉 `agy install` 은 **바이너리 설치가 아니라 환경 구성**(PATH 추가, 셸 프로필 별칭 정리)이다. install.ps1 의 9단계가 이걸 호출한다. ### 3.5 winget 경로 ``` $ winget list --name antigravity 이름 장치 ID 버전 사용 가능 원본 -------------------------------------------------------------------- Antigravity 2.11.0 Google.Antigravity 2.11.0 winget Antigravity CLI Google.AntigravityCLI 1.1.10 1.1.23 winget Antigravity IDE (User) Google.AntigravityIDE 2.5.5 winget ``` 무인 설치 명령(권장 형태): ```powershell winget install --id Google.AntigravityCLI --silent --accept-package-agreements --accept-source-agreements ``` > ⚠️ **미검증 / 조사 필요**: winget 은 SYSTEM 계정·서비스 세션에서 동작하지 않는 것으로 알려져 있다. 작업 스케줄러가 사용자 계정으로 실행될 때는 문제없지만, SYSTEM 으로 실행하면 실패할 수 있다. → `docs/research/09-agy-bootstrap-and-provisioning.md` 에서 결론. ### 3.6 자동 업데이트 - 공식 문서: "The Antigravity CLI automatically self-updates in the background." - 비활성화 환경변수: **`AGY_CLI_DISABLE_AUTO_UPDATE=true`** - 업데이터 락 파일: `~/.gemini/antigravity-cli/updater/update.lock` - 락 충돌 경고 문자열: `Warning: another background updater process is already active (update.lock)` - 수동 업데이트 서브커맨드: `agy update` (실측: `agy update --help` 는 `Usage of update:` 만 출력하고 플래그 목록이 비어 있음 — 인자 없이 쓰는 명령) **배치 정책 권고**: 06:00 배치 실행 시 `AGY_CLI_DISABLE_AUTO_UPDATE=true` 를 설정해 업데이트가 끼어들지 않게 하고, 별도 주간 작업에서 `agy update` 를 돌린다. 배치 도중 바이너리가 교체되면 실행 실패 또는 예측 불가 동작이 발생한다. --- ## 4. 인증 ### 4.1 공식 문서상 인증 경로 | 방식 | 동작 | 비대화형 적합성 | |---|---|---| | **로컬 키링 로그인** | OS 네이티브 보안 키링(Apple Keychain, Linux Secret Service/dbus, **Windows Credential Manager**) 접근. 유효한 자격증명이 있으면 조용히 인증, 없으면 기본 브라우저로 OAuth 로그인 | 최초 1회 대화형 필요 | | **원격 SSH OAuth** | SSH 감지 시 "manual URL loop" — 인증 URL 을 로컬 브라우저에 붙여넣고, 받은 영숫자 코드를 터미널에 다시 붙여넣기 | 대화형 | | **Gemini API 키** | `~/.gemini/antigravity-cli/settings.json` 에 `modelProvider: "gemini"` 설정 + `GEMINI_API_KEY` 환경변수 export. 문서 원문: "The CLI skips the sign-in screen and opens the main interface directly." | **완전 비대화형 가능** | | **커스텀 엔드포인트** | `GOOGLE_GEMINI_BASE_URL` 환경변수로 Gemini 호환 대체 엔드포인트 지정 | 부가 | | 로그아웃 | CLI 안에서 `/logout` — 계정 연결 해제 및 OS 키링의 저장된 인증 프로필 삭제 | — | ### 4.2 실측: 토큰은 파일에 있다 ``` $ ls ~/.gemini/antigravity-cli/ -rw-r--r-- antigravity-oauth-token # 504 바이트 ``` 파일 내용 형태 (값은 마스킹): ```json {"token":{"access_token":"ya29.","token_type":"...", ...}} ``` 한편 Windows 자격증명 관리자에는 관련 항목이 없었다: ``` $ cmdkey /list | grep -i -E "antigrav|agy|google" (결과 없음) ``` **결론과 시사점**: | 사실 | 배치 운영에 대한 함의 | |---|---| | 토큰이 사용자 프로필 아래 **평문 파일**로 존재 | 작업 스케줄러가 **동일 사용자 계정**으로 실행되면 키링 잠금 문제 없이 인증이 통과한다. 이것이 이 프로젝트의 인증 전략의 근거다. | | Windows Credential Manager 를 쓰지 않음(실측) | S4U(암호 저장 안 함) 방식으로 실행해도 키링 접근 실패 위험이 낮다. 다만 **사용자 프로필이 로드돼야** 파일에 접근 가능 — SYSTEM 계정 실행은 금지. | | 토큰 = 계정 접근 권한 | 이 파일을 백업·전송·로그에 남기지 않는다. 리포지토리에 절대 커밋 금지. `.gitignore` 에 명시. | | access_token 은 만료된다 | refresh 실패 시 배치가 인증 오류로 죽는다. **미인증 감지 → 사용자 알림 경로가 반드시 필요하다.** | ### 4.3 인증 상태 비대화형 확인 방법 권장 헬스체크(가장 저렴한 형태): ```powershell $env:AGY_CLI_DISABLE_AUTO_UPDATE = "true" $out = & "$env:LOCALAPPDATA\agy\bin\agy.exe" -p "Reply with exactly: PONG" --output-format json --print-timeout 90s 2>&1 $obj = $out | ConvertFrom-Json if ($obj.status -ne "SUCCESS") { Write-Error $obj.error } ``` 실측 결과(정상 인증 상태): ```json {"conversation_id":"eab39b4e-0a09-494f-9ded-87aaf2b9c6e1","status":"SUCCESS","response":"OK\n","duration_seconds":33.6771974,"num_turns":1,"usage":{"input_tokens":28317,"output_tokens":44,"thinking_tokens":43,"cache_read_tokens":0,"total_tokens":28361}} ``` 종료 코드 `0`. > ⚠️ **비용 주의**: 이 헬스체크 한 번에 input 28k 토큰이 든다. 매 배치마다 별도 헬스체크를 돌리지 말고, **실제 작업 호출의 결과로 인증 실패를 판정**하라. --- ## 5. Headless(비대화형) 실행 정본 ### 5.1 전체 플래그 표 (실측 `agy --help` 원문 기준) | 플래그 | 기본값 | 설명 | |---|---|---| | `-p`, `--print`, `--prompt` | — | 단일 프롬프트를 비대화형으로 실행하고 응답을 출력 | | `-i`, `--prompt-interactive` | — | 초기 프롬프트를 실행하고 대화형 세션을 계속 | | `--output-format` | `text` | 출력 포맷: `text` \| `json` \| `stream-json` | | `--input-format` | `text` | 입력 포맷: `text` \| `stream-json`. `stream-json` 은 stdin 에서 NDJSON 을 한 줄에 하나씩 읽어 턴마다 실행하며, **`--output-format stream-json` 을 요구** | | `--json-schema` | — | 구조화 출력 강제용 JSON 스키마 문자열 또는 스키마 파일 경로. stream-json 에서는 최종 result 에만 적용 | | `--model` | — | 이 세션의 모델 (`agy models` 참조) | | `--effort` | — | 추론 강도: `low` \| `medium` \| `high` | | `--agent` | — | 이 세션의 에이전트 (`agy agents` 참조) | | `-c`, `--continue` | `false` | 가장 최근 대화 이어가기 | | `--conversation` | — | 대화 ID 로 이전 대화 재개 | | `--dangerously-skip-permissions` | `false` | 모든 도구 권한 요청을 자동 승인 | | `--disable-slash-commands` | — | print 모드에서 슬래시 명령·스킬 확장 비활성화 | | `--print-timeout` | `5m0s` | print 모드 응답 대기 제한 시간 | | `--mode` | — | 에이전트 실행 모드 (`accept-edits`, `plan`) | | `--sandbox` | `false` | 터미널 제한이 걸린 샌드박스로 실행 | | `--add-dir` | `[]` | 워크스페이스에 디렉터리 추가 (반복 가능) | | `--project` | — | 이 세션의 프로젝트 ID 또는 이름 | | `--new-project` | — | 이 세션용 새 프로젝트 생성 | | `--log-file` | — | CLI 로그 파일 경로 재정의 | ### 5.2 서브커맨드 (실측) | 서브커맨드 | 설명 | |---|---| | `agent` / `agents` | 사용 가능한 에이전트 목록 | | `changelog` | 변경 로그·릴리스 노트 | | `help` | 서브커맨드 도움말 | | `install` | 환경 경로·셸 설정 구성 | | `mcp` | MCP 서버 관리 (add, remove, list, enable, disable) | | `mic-serve` | 이 머신의 마이크를 다른 호스트의 CLI 에 제공 | | `models` | 사용 가능한 모델 목록 | | `plugin` / `plugins` | 플러그인 관리 (install, uninstall, list, enable, disable) | | `update` | CLI 업데이트 | ### 5.3 표준 스트림 규약 공식 문서 원문: > Output goes to `stdout`; diagnostics (errors, auth prompts, progress) go to `stderr`. **배치 설계**: `stdout` 만 파싱하고, `stderr` 는 통째로 로그 파일에 남긴다. 둘을 섞으면(`2>&1`) JSON 파싱이 깨진다. ### 5.4 인증 전제 공식 문서 원문: > "Headless mode uses your cached credentials. Authenticate once with an interactive `agy` session first." --- ## 6. 출력 포맷 3종 상세 ### 6.1 `text` (기본) ```bash agy -p "In one sentence, what does the command git bisect do?" ``` 응답 본문만 평문으로 나온다. 배치에서는 오류 판별이 어려우므로 **사용하지 않는다.** ### 6.2 `json` — 단일 봉투 (**이 프로젝트의 기본 선택**) ```bash agy -p "In one sentence, what is a git rebase?" --output-format json | jq ``` 봉투 필드: | 필드 | 타입 | 설명 | |---|---|---| | `conversation_id` | string | 대화 ID (재개용) | | `status` | string | `SUCCESS` \| `ERROR` \| `CANCELED` \| `INTERRUPTED` \| `INVALID` \| `WAITING` \| `RUNNING` | | `response` | string | 응답 본문 | | `error` | string | 실패 시에만 존재 | | `duration_seconds` | number | 소요 시간 | | `num_turns` | number | 턴 수 | | `usage` | object | `input_tokens`, `output_tokens`, `thinking_tokens`, `cache_read_tokens`, `total_tokens` | | `structured_output` | object | `--json-schema` 사용 시 (⚠️ 6.3/7 절 참조 — 실측에서 누락됨) | | `json_schema` | object | 적용된 스키마 에코백 | `status` 값 의미: | 값 | 의미 | |---|---| | `SUCCESS` | 응답과 함께 정상 완료 | | `ERROR` | 오류로 종료 | | `CANCELED` | 취소됨 | | `INTERRUPTED` | 인터럽트(예: SIGINT) | | `INVALID` | 유효하지 않은 상태에 도달 | | `WAITING` | 입력 대기 중 종료 | | `RUNNING` | 종료 상태에 도달하지 못함 | ### 6.3 `stream-json` — NDJSON 이벤트 스트림 ```bash agy -p "In one sentence, what is a git rebase?" --output-format stream-json ``` 이벤트 종류: `init`(1회) → `step_update`(여러 번) → `result`(1회) `init` 이벤트 예: ```json {"event":"init","conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","init":{"cwd":"/home/user/project","tools":["ask_permission","run_command","write_to_file","..."],"permission_mode":"request-review"}} ``` `step_update` (에이전트 응답 델타): ```json {"event":"step_update","step_update":{"conversation_id":"c3b66b04-872b-4fbe-a3a4-058a026ef20a","step_index":3,"state":"DONE","step_type":"agent_response","text_delta":"Git rebase destructively rewrites...","duration_seconds":6.28,"usage":{"input_tokens":10302,"output_tokens":582,"thinking_tokens":551,"cache_read_tokens":8113,"total_tokens":10884}}} ``` `step_update` (도구 호출 — **감사 로그로 매우 유용**): ```json {"event":"step_update","step_update":{"conversation_id":"edb1c8c1-50ba-4f3f-87eb-412d0e9d47c3","step_index":4,"state":"DONE","step_type":"tool","tool_name":"run_command","duration_seconds":0.07,"tool_info":{"name":"run_command","parameters":{"CommandLine":"echo hello_headless_demo"},"output":"hello_headless_demo\r\n"}}} ``` `tool_info` 는 `name`, `parameters`, `output`, 실패 시 `error` 를 담는다. `result` 이벤트: ```json {"event":"result","result":{"conversation_id":"...","status":"SUCCESS","response":"Git rebase...","duration_seconds":6.88,"num_turns":1,"usage":{"input_tokens":10418,"output_tokens":589,"thinking_tokens":551,"cache_read_tokens":8113,"total_tokens":11007}}} ``` `jq` 파싱 레시피: ```bash # 응답 텍스트만 추출 agy -p "Name three popular version control systems, comma-separated." --output-format json | jq -r '.response' # 스트리밍 텍스트 이어붙이기 agy -p "Explain merge conflicts in two sentences." --output-format stream-json \ | jq -j 'select(.event=="step_update") | .step_update.text_delta // empty' # 토큰 사용량만 agy -p "In one sentence, what is a git rebase?" --output-format stream-json \ | jq 'select(.event=="result") | .result.usage' ``` ### 6.4 stdin 스트리밍 입력 (`--input-format stream-json`) 여러 프롬프트를 한 세션에서 연속 실행한다. **`--output-format stream-json` 과 반드시 짝**이어야 한다. ```bash printf '%s\n' \ '{"event":"user","message":{"content":"Reply with exactly the word: apple. Nothing else."}}' \ '{"event":"user","message":{"content":"What word did I ask you to reply with? Answer with just that word."}}' \ | agy --input-format stream-json --output-format stream-json ``` `content` 는 문자열 또는 텍스트 블록 리스트 둘 다 허용: ```json { "event": "user", "message": { "content": "Reply with exactly: banana" } } { "event": "user", "message": { "content": [{ "type": "text", "text": "Reply with exactly: banana" }] } } ``` **메타데이터 범위 주의**: `response` 는 현재 턴의 것이지만, `num_turns` / `usage` / `duration_seconds` 는 **세션 누적**이다. 세션 종료: stdin 을 닫으면 현재 턴 완료 후 프로세스가 종료된다. 정상 종료는 코드 `0`. 지원하지 않는 입력과 그 결과: | 입력 | 결과 | 종료 코드 | |---|---|---| | 인식되지 않는 `event` 이름 | 건너뜀, stderr 에 경고 | — | | `control_request` / `control_response` 이벤트 | `ERROR` result, 세션 종료 | `2` | | CLI 가 처리하는 슬래시 명령(`/model`, `/usage`) | `ERROR` result, 세션 종료 | `2` | | `event` 필드 누락 | `ERROR` result, 세션 종료 | `1` | | 잘못된 JSON 줄 | `ERROR` result, 세션 종료 | `1` | | `text` 외의 content block 타입 | `ERROR` result, 세션 종료 | `1` | 슬래시 명령 오류 메시지 원문: ```json { "event": "result", "result": { "conversation_id": "4fae3a70-409d-42a4-86ea-9de206a49ff4", "status": "ERROR", "response": "", "error": "/model is answered by the CLI itself and is unavailable with --input-format stream-json; run it as its own --print /model invocation", "duration_seconds": 0, "num_turns": 0, "usage": { "input_tokens": 0, "output_tokens": 0, "thinking_tokens": 0, "cache_read_tokens": 0, "total_tokens": 0 } } } ``` 흔한 실수 표(공식 문서): | 실수 | 왜 실패하나 | 해결 | |---|---|---| | `--output-format json` 또는 `text` 와 조합 | 종료 시 단일 봉투만 나와 턴이 유실됨 | `--output-format stream-json` 사용 | | `-p` 로 프롬프트 전달 | 스트리밍 모드는 stdin 만 수신 | 프롬프트를 stdin 의 `user` 메시지로 전송 | | `/model`, `/usage` 를 스트림에 전송 | CLI 내부 처리라 JSON 흐름이 깨짐 | 별도 `agy -p /model` 로 실행 | | `num_turns` 를 턴별 카운트로 오해 | 세션 누적 값 | 현재 턴은 `response` 필드 사용 | | stdout 을 프로세스 종료 후 읽으려 함 | stdin 닫을 때까지 세션 유지 | 줄 단위로 즉시 읽기 | 파이썬으로 세션을 구동하는 공식 예제: ```python import json import subprocess proc = subprocess.Popen( ["agy", "--input-format", "stream-json", "--output-format", "stream-json"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True, bufsize=1, ) def ask(prompt): """Send one prompt and return the response for that turn.""" message = {"event": "user", "message": {"content": prompt}} proc.stdin.write(json.dumps(message) + "\n") proc.stdin.flush() for line in proc.stdout: event = json.loads(line) if event["event"] == "result": return event["result"]["response"] first = ask("Name one popular version control system. Answer with one word.") print(ask(f"Name a competitor to {first.strip()}. Answer with one word.")) proc.stdin.close() proc.wait() ``` ### 6.5 대화 이어가기 ```bash # 가장 최근 대화 이어가기 agy -p "Now explain your previous answer in more detail" --continue # 특정 대화 ID 재개 agy -p "Summarize what we discussed" --conversation 055a398f-db14-4c5f-abbb-1bf03f8120a7 ``` **배치에서는 `--continue` 를 쓰지 마라.** 배치는 매번 독립적이어야 하며, 최근 대화가 무엇인지 예측할 수 없다. 필요하면 `conversation_id` 를 명시적으로 저장·전달한다. --- ## 7. 구조화 출력과 그 함정 ### 7.1 문서상 동작 ```bash agy -p "Parse v2.14.3 into major, minor, patch." \ --output-format json \ --json-schema '{"type":"object","properties":{"major":{"type":"integer"},"minor":{"type":"integer"},"patch":{"type":"integer"}},"required":["major","minor","patch"]}' | jq ``` 스키마는 **문자열, 파일 경로, 또는 원시 타입**(string, number, integer, boolean)을 받는다. 결과는 봉투의 `structured_output` 필드에 담긴다. ### 7.2 실측 결과 — 기대와 다르다 ⚠️ 명령: ```bash agy -p "Return today's weekday name in Korean." --output-format json \ --json-schema '{"type":"object","properties":{"weekday":{"type":"string"}},"required":["weekday"]}' \ --print-timeout 90s ``` 실제 출력: ```json {"conversation_id":"cb636581-e8de-4375-8542-4f83fca1db9c","status":"SUCCESS","response":"{\"toolAction\":\"Finishing task\",\"toolSummary\":\"Return weekday in Korean\",\"weekday\":\"수요일\"}\n오늘(2026년 9월 2일)의 요일은 **수요일**입니다.\n{\"toolAction\":\"Finish task\",\"toolSummary\":\"Task completion\",\"weekday\":\"수요일\"}\n오늘의 요일은 **수요일**입니다.\n{\"toolAction\":\"Finish task\",\"toolSummary\":\"Finish task\",\"weekday\":\"수요일\"}\n오늘(2026년 9월 2일)의 요일은 **수요일**입니다.\n{\"toolAction\":\"Finish task\",\"toolSummary\":\"Finish task\",\"weekday\":\"수요일\"}\n오늘(2026-09-02)의 요일은 **수요일**입니다.\n","duration_seconds":52.9313561,"num_turns":4,"json_schema":{"type":"object","properties":{"weekday":{"type":"string"}},"required":["weekday"]},"usage":{"input_tokens":86038,"output_tokens":2378,"thinking_tokens":2169,"cache_read_tokens":163370,"total_tokens":88416}} ``` **관찰된 문제**: | 증상 | 상세 | |---|---| | `structured_output` 필드 부재 | 봉투에 `json_schema` 는 에코백됐지만 `structured_output` 이 없다 | | `response` 오염 | JSON 조각과 한국어 산문이 뒤섞여 있다 | | 4회 반복 | `num_turns: 4` — 모델이 스키마를 만족시키려 4번 시도했다 | | 스키마에 없는 필드 | `toolAction`, `toolSummary` 가 섞여 나왔다 (내부 도구 래퍼로 추정) | | 비용 폭증 | input 86k, output 2.4k, 총 88k 토큰, 52.9초. 같은 답을 얻는 단순 호출의 3배 | **설계 결론 (이 프로젝트의 규칙)**: 1. `--json-schema` 를 **1차 수단으로 신뢰하지 않는다.** 2. 프롬프트 자체에 출력 형식을 강하게 못박는다: "오직 JSON 객체 하나만 출력하고, 코드 펜스·설명·서문을 붙이지 마라." 3. 파이프라인은 **`response` 에서 JSON 을 견고하게 추출**한다: 코드 펜스 제거 → 첫 `{` 부터 균형 잡힌 마지막 `}` 까지 슬라이스 → `json.loads` → **jsonschema 로 자체 검증**. 4. 검증 실패 시 최대 N회 재시도하고, 그래도 실패하면 **AI 결과 없이 리포트를 생성**한다(graceful degradation). 5. `--json-schema` 를 쓰더라도 **보조 수단**으로만 병행하고, `structured_output` 이 있으면 우선 사용하되 없으면 4번 경로로 폴백한다. 권장 추출 함수: ```python import json, re _FENCE = re.compile(r"^\s*```(?:json)?\s*|\s*```\s*$", re.MULTILINE) def extract_json_object(text: str) -> dict | None: """agy 의 response 문자열에서 첫 번째 완결 JSON 객체를 견고하게 추출한다.""" if not text: return None s = _FENCE.sub("", text) start = s.find("{") while start != -1: depth, in_str, esc = 0, False, False for i in range(start, len(s)): ch = s[i] if in_str: if esc: esc = False elif ch == "\\": esc = True elif ch == '"': in_str = False continue if ch == '"': in_str = True elif ch == "{": depth += 1 elif ch == "}": depth -= 1 if depth == 0: try: return json.loads(s[start:i + 1]) except json.JSONDecodeError: break start = s.find("{", start + 1) return None ``` --- ## 8. 모델 · 에이전트 · 추론 강도 ### 8.1 모델 목록 (실측 `agy models`, 2026-09-02) | 슬러그 | 표시 이름 | |---|---| | `gemini-3.7-flash-high` | Gemini 3.7 Flash (High) | | `gemini-3.7-flash-medium` | Gemini 3.7 Flash (Medium) | | `gemini-3.7-flash-low` | Gemini 3.7 Flash (Low) | | `gemini-3.6-flash-high` | Gemini 3.6 Flash (High) | | `gemini-3.6-flash-medium` | Gemini 3.6 Flash (Medium) | | `gemini-3.6-flash-low` | Gemini 3.6 Flash (Low) | | `gemini-3.1-pro-high` | Gemini 3.1 Pro (High) | | `gemini-3.1-pro-low` | Gemini 3.1 Pro (Low) | | `claude-sonnet-4-6` | Claude Sonnet 4.6 (Thinking) | | `claude-opus-4-6-thinking` | Claude Opus 4.6 (Thinking) | | `gpt-oss-120b-medium` | GPT-OSS 120B (Medium) | > 참고: 공식 문서 예시에는 `gemini-3.5-flash-medium` 도 등장하지만 실측 목록에는 없었다. **모델 슬러그는 하드코딩하지 말고, 부트스트랩 때 `agy models` 로 검증**하는 것이 안전하다. ```bash # 모델 고정 agy -p "Reverse the string antigravity." --model gemini-3.5-flash-medium # 추론 강도 agy -p "Outline a plan to add caching to this service." --effort high # 에이전트 선택 agy -p "Review this function for edge cases." --agent ``` 알 수 없는 모델을 주면 종료 코드 비0 + `status: ERROR`: ```bash agy -p "hi" --model does-not-exist-model --output-format json; echo "exit=$?" ``` ```json {"conversation_id":"","status":"ERROR","response":"","error":"invalid model selection (--model \"does-not-exist-model\" --effort \"\"): model does-not-exist-model is not recognized as a known model or custom model in settings\nAvailable models:\n Gemini 3.6 Flash (High)\n ...","duration_seconds":0,"num_turns":0,"usage":{...}} ``` ``` exit=1 ``` ### 8.2 이 프로젝트의 모델 선택 지침 | 유스케이스 | 권장 모델 | 이유 | |---|---|---| | 일일 변경사항 한국어 요약 | `gemini-3.7-flash-medium` | 정형 입력의 요약, 속도·비용 우위 | | 셀렉터 자가 복구 제안 | `gemini-3.1-pro-high` 또는 `claude-sonnet-4-6` | HTML 구조 추론은 난도가 높음 | | 이상 탐지 해석 | `gemini-3.7-flash-high` | 짧은 추론 | | 주간 트렌드 코멘터리 | `gemini-3.1-pro-high` | 종합·서술 품질 | ### 8.3 에이전트 (실측 `agy agents`) ``` flutter_a11y_agent ``` 현재 머신에는 커스텀 에이전트가 하나 등록돼 있다. 이 프로젝트는 커스텀 에이전트를 만들지 않고 기본 에이전트 + 프롬프트 파일로 간다(단순성 우선). --- ## 9. 권한 모델 ### 9.1 세밀 권한 엔진 리소스 표기는 `action(target)` 형식이며 세 목록으로 통제한다. | 목록 | 동작 | |---|---| | `deny` | 즉시 차단 | | `ask` | 명시적 승인 대기 | | `allow` | 프롬프트 없이 자동 승인 | **우선순위: Deny > Ask > Allow** (충돌 시 엄격하게 이 순서로 평가) ### 9.2 지원 액션과 타깃 | 액션 | 형식 | 동작 | |---|---|---| | `read_file` | 경로 또는 `*` | 절대 경로 또는 워크스페이스 루트 기준 상대 경로 매칭. **재귀적** 읽기 권한 부여 | | `write_file` | 경로 또는 `*` | 같은 타깃에 대해 `read_file` 을 **암묵적으로 함께 부여** | | `read_url` | 도메인 또는 `*` | 호스트명과 서브도메인 매칭 (예: `google.com` 은 `mail.google.com` 포함) | | `execute_url` | 도메인 또는 `*` | 웹 액추에이션(클릭, 타이핑) | | `command` | 접두사/정규식 또는 `*` | **공백으로 분리된 각 토큰이 앵커된 정규식으로 평가됨** | | `unsandboxed` | 접두사 또는 `*` | 컨테이너 격리 밖에서 명령 실행 | | `mcp` | `server/tool` 또는 `*` | MCP 도구 접근 | 암묵 규칙: - 파일 쓰기 권한은 그 경로의 읽기 권한을 자동 부여 - 경로에 읽기를 거부하면 그 경로 쓰기도 차단 기본 동작: 1. **워크스페이스 자동 허용**: 활성 프로젝트 디렉터리 안의 파일 읽기·쓰기는 자동 허용 2. **웹은 기본 ask** 3. **설정되지 않은 액션은 기본 ask** ### 9.3 헤드리스에서의 권한 공식 문서 원문 요지: 헤드리스에는 대화형 프롬프트가 없고 정책으로 처리된다. **워크스페이스 파일 읽기/쓰기는 자동 허용되지만, 셸 명령은 기본 Ask 이며 권한이 없으면 soft-deny 된다.** 이것이 배치에서 가장 흔한 실패 원인이다. 반드시 사전 허용 규칙을 넣어라. 설정 예시 (`~/.gemini/antigravity-cli/settings.json`): ```json { "permissions": { "allow": [ "command(git)", "command(npm run (build|lint|test))", "read_url(google.com)", "mcp(linter/*)", "write_file(src/)" ], "deny": [ "command(sudo)", "write_file(.git/)" ], "ask": ["command(*)", "mcp(sql/execute_mutation)"] } } ``` 전부 자동 승인(위험): ```bash agy -p "Run the test suite and report failures" --dangerously-skip-permissions ``` 공식 경고 원문: > "`--dangerously-skip-permissions` approves all tool calls, including file writes and command execution. Prefer scoped `permissions.allow` rules unless you fully trust the prompt and environment." **이 프로젝트의 결론**: `--dangerously-skip-permissions` 를 **쓰지 않는다.** 이유는 크롤링한 외부 텍스트가 프롬프트에 들어가므로 프롬프트 인젝션 표면이 존재하기 때문이다. 대신 이 프로젝트 전용 `permissions.allow` 를 최소 범위로 설정한다. 상세는 `docs/research/10-agy-agent-integration-patterns.md`. ### 9.4 크로스 플랫폼 경로 정규화 공식 문서 원문: > "Antigravity automatically normalizes paths prior to rule evaluation by stripping drive letters (e.g., C:) and converting all backslashes (\) to forward slashes (/)." **즉 규칙에 `D:\workspace\DMF_Crawler` 대신 `workspace/DMF_Crawler` 형태를 쓴다.** 드라이브 문자는 제거되고 슬래시로 변환된다. ### 9.5 대화형 프롬프트에서의 범위 확장 승인 카드에서 타깃 문자열을 직접 편집해 권한 범위를 넓힐 수 있다. CLI 가 편집을 검증하고 그 세션 동안 확장된 권한을 적용한다. --- ## 10. 실행 모드 | 모드 | 동작 | |---|---| | `default` | 파일 수정·생성 전에 대화형 diff 리뷰로 일시정지 | | `accept-edits` | 파일 편집·생성(`mkdir`, `touch`, 파일 쓰기)을 자동 승인 | | `plan` | `/plan` 지시 접두사를 붙여 코드 작성 전 단계 분석·개요 작성 | `accept-edits` 에서는 `write_to_file`, `replace_file_content`, `multi_replace_file_content` 가 자동 실행되며, **세션 중 생성된 서브에이전트도 이 설정을 상속**한다. 설정 방법: ```bash agy --mode=accept-edits agy --mode=plan ``` ```json {"agentMode": "accept-edits"} ``` 대화형에서는 `/settings` 로 기본 모드를 고르거나 `Shift+Tab` 으로 순환한다. **권한과 모드는 독립적이다.** 공식 문서 원문: > "Tool permission rules configured via `/permissions` or `--dangerously-skip-permissions` continue to govern shell commands (`run_command`) across all execution modes." 즉 모드는 **파일 작업**을, 권한은 **셸 명령**을 각각 통제한다. --- ## 11. 설정 파일 전체 키 ### 11.1 위치 | 파일 | 경로 | |---|---| | 설정 | `~/.gemini/antigravity-cli/settings.json` (Windows 도 `%USERPROFILE%\.gemini\antigravity-cli\settings.json`) | | 키바인딩 | `~/.gemini/antigravity-cli/keybindings.json` | **희소 저장(sparse persistence)**: 기본값과 다른 값만 디스크에 기록한다. **프로젝트 단위 설정은 문서화돼 있지 않다** — 사용자 단위 설정만 존재. 프로젝트별 차이는 CLI 플래그로 준다. ### 11.2 전체 키 표 | 키 | 타입 | 기본값 | 값/설명 | |---|---|---|---| | `colorScheme` | string | `"terminal"` | `"light"`, `"solarized light"`, `"colorblind-friendly light"`, `"dark"`, `"solarized dark"`, `"colorblind-friendly dark"`, `"tokyo night"`, `"terminal"` | | `altScreenMode` | string | `"default"` | `"default"`(적응형), `"always"`(대체 화면 버퍼 강제), `"never"`(인라인 강제) | | `toolPermission` | string | `"request-review"` | `"request-review"`, `"proceed-in-sandbox"`, `"always-proceed"`, `"strict"` | | `artifactReviewPolicy` | string | `"asks-for-review"` | `"asks-for-review"`, `"agent-decides"`, `"always-proceed"` | | `notifications` | boolean | `false` | 작업 완료 시 시스템 데스크톱 알림 및 터미널 벨 | | `showTips` | boolean | `true` | 생성 중 프롬프트 패널 위에 팁 표시 | | `showFeedbackSurvey` | boolean | `true` | 주기적 품질 피드백 설문 표시 | | `editor` | string | `"auto"` | `"auto"`, `"vim"`, `"emacs"`, 커스텀 | | `editorMode` | string | `"default"` | `"default"`(평문 편집), `"vim"`(모달 편집) | | `vimInsertFirst` | boolean | `false` | Vim 편집을 Insert 모드로 시작하고 `Enter` 로 제출 | | `allowNonWorkspaceAccess` | boolean | `false` | 에이전트 파일 도구가 Git/워크스페이스 루트 밖으로 나갈 수 있게 허용 | | `enableTerminalSandbox` | boolean | `false` | 에이전트가 실행하는 로컬 명령을 OS 격리 링으로 제한 | | `useG1Credits` | boolean | `false` | 플랜 쿼터 소진 후 개인 AI 크레딧 사용 | | `enableTelemetry` | boolean | `true` | 메트릭 수집·크래시 로그 전송 허용 | | `verbosity` | string | `"high"` | `"high"`(전체 사고·출력), `"low"`(최소 표시) | | `runningLightSpeed` | string | `"medium"` | `"fast"`, `"medium"`, `"slow"`, `"off"` | | `agentMode` | string | `"default"` | `"accept-edits"`, `"plan"` (모드 문서 기준) | | `permissions` | object | — | `allow` / `deny` / `ask` 배열 (9절 참조) | | `statusLine` | object | — | `{"type":"command","command":"<경로>"}` (실측 확인) | | `trustedWorkspaces` | array | — | 신뢰 워크스페이스 경로 목록 (실측 확인) | | `modelProvider` | string | — | `"gemini"` 로 설정 시 `GEMINI_API_KEY` 사용, 로그인 화면 건너뜀 (설치 문서 기준) | | `model` | string | — | 실측 파일에는 슬러그가 아니라 **표시 이름**(`"Gemini 3.7 Flash (High)"`)으로 저장돼 있었다 | 문서 예시: ```json { "colorScheme": "tokyo night", "altScreenMode": "always", "toolPermission": "request-review", "notifications": true, "enableTerminalSandbox": true } ``` ### 11.3 `toolPermission` 값 의미 (베스트 프랙티스 문서) | 값 | 동작 | |---|---| | `request-review` (기본) | 쓰기 작업, bash 명령, 원격 네트워크 호출 전에 매번 확인 | | `proceed-in-sandbox` | 모든 터미널 실행을 보안 샌드박스 격리 링으로 제한. 안전한 명령은 자율 실행, 위험한 명령은 리뷰 요청 | | `always-proceed` | 자동 진행 | | `strict` | 모든 비읽기 작업에 대해 항상 확인, 완전한 라인별 투명성 | ### 11.4 환경변수 | 변수 | 용도 | |---|---| | `GEMINI_API_KEY` | `modelProvider: "gemini"` 와 함께 사용하는 API 키 | | `GOOGLE_GEMINI_BASE_URL` | 대체 Gemini 호환 엔드포인트 | | `AGY_CLI_DISABLE_AUTO_UPDATE` | `true` 로 자동 업데이트 비활성화 | | `LOCALAPPDATA` | Windows 설치 경로 결정에 사용 | | `PROCESSOR_ARCHITEW6432` / `PROCESSOR_ARCHITECTURE` | 설치 스크립트의 아키텍처 감지 | > ⚠️ 공식 설정 문서는 "환경변수로 설정을 덮어쓰는 방법은 문서화돼 있지 않다"고 명시한다. 런타임 재정의는 CLI 플래그로만 한다. --- ## 12. 디렉터리·파일 레이아웃 실측 `~/.gemini/antigravity-cli/` 실측 목록: | 항목 | 종류 | 설명 | |---|---|---| | `settings.json` | 파일 | 사용자 설정 | | `keybindings.json` | 파일 | 키바인딩(문서 기준) | | `antigravity-oauth-token` | 파일 | **OAuth 토큰 평문 JSON (보안 주의)** | | `installation_id` | 파일 | 설치 식별자 | | `history.jsonl` | 파일 | 프롬프트 이력 (실측 213 KB) | | `conversation_summaries.db` | 파일 | 대화 요약 SQLite (실측 140 KB) | | `conversations/` | 디렉터리 | 대화 저장소 | | `log/` | 디렉터리 | 로그 (`cli-YYYYMMDD_HHMMSS.log` 형식) | | `cli.log` | 심볼릭 링크 | 최신 로그 파일로의 링크 | | `crashes/` | 디렉터리 | 크래시 덤프 | | `cache/` | 디렉터리 | 캐시 | | `brain/` | 디렉터리 | 세션별 작업 공간 (하위에 `scratch/`) | | `knowledge/` | 디렉터리 | 지식 저장소 | | `rules/` | 디렉터리 | 규칙 파일 | | `skills/` | 디렉터리 | 스킬 | | `mcp/` | 디렉터리 | MCP 설정 | | `plugins`/`bin`/`builtin`/`implicit`/`presence`/`annotations` | 디렉터리 | 내부 | | `updater/` | 디렉터리 | 자동 업데이터 (`update.lock` 포함) | | `last_check.timestamp` | 파일 | 업데이트 확인 시각 | | `statusline.cmd`, `statusline.py` | 파일 | 커스텀 상태줄 (사용자 설정) | **로그 경로 규약**: 실행마다 새 로그 파일이 생기고 `cli.log` 가 최신을 가리킨다. `--log-file` 로 재정의 가능 → **배치에서는 실행 ID별 로그 파일을 지정**하는 것을 권장한다. --- ## 13. 종료 코드와 오류 처리 | 코드 | 의미 | |---|---| | `0` | 성공 | | `1` | 일반 실패 (잘못된 모델, 잘못된 JSON 입력, event 필드 누락, 잘못된 content block 타입) | | `2` | 스트림 입력에서 `control_request`/`control_response` 또는 CLI 처리 슬래시 명령 수신 | | 비0 (기타) | 실패, 사유는 stderr 로 | `json` / `stream-json` 모드에서는 실패가 `status` 와 `error` 필드에도 나타난다. **배치는 종료 코드와 `status` 를 둘 다 확인**해야 한다. CI 실행 공식 예제: ```bash #!/usr/bin/env bash set -euo pipefail result=$(agy -p "Name three popular version control systems, comma-separated." \ --output-format json \ --print-timeout 10m) status=$(echo "$result" | jq -r '.status') if [[ "$status" != "SUCCESS" ]]; then echo "Agent run failed: $(echo "$result" | jq -r '.error')" >&2 exit 1 fi echo "$result" | jq -r '.response' > result.txt ``` 타임아웃 늘리기: ```bash agy -p "Summarize the design tradeoffs of optimistic locking." --print-timeout 15m ``` --- ## 14. 크레딧·쿼터 | 항목 | 내용 | |---|---| | 상태줄 표시 | 남은 크레딧 표시 (예: `AI Credits: 42`) | | `/credits` | 상세 통계 패널, 구매 링크 | | `/usage` (별칭 `/quota`) | 모델별 API 쿼터 조회 | | `useG1Credits` 설정 | `true` 면 플랜 쿼터 소진 시 개인 크레딧으로 폴백, `false` 면 차단 | > ⚠️ 공식 크레딧 문서에는 **무료/유료 티어 구분, 일일·주간 한도, 모델별 단가, 쿼터 소진 시 오류 메시지·종료 동작, `GEMINI_API_KEY` 과금 차이, 레이트 리밋, 자동화 사용 가이드가 없다.** `/docs/plans` 페이지를 참조하라고만 안내한다. → 부록 B 미해결 항목. **배치 관점 대응**: `usage.total_tokens` 를 매 호출 로깅하고, 일일 누적 상한을 파이프라인 자체에서 강제한다. 쿼터 소진은 `status: ERROR` + `error` 문자열로 감지하고, 감지되면 **AI 단계를 건너뛰고 리포트를 생성**한다. --- ## 15. 트러블슈팅 | 증상 | 오류 문자열 | 해결 | |---|---|---| | 명령을 찾을 수 없음 | `bash: agy: command not found` | `~/.local/bin` 을 PATH 에 추가(`~/.bashrc`/`~/.zshrc`), Windows 는 레지스트리 PATH 등록. **배치는 절대 경로 사용으로 회피** | | 키링 접근 실패 | `Error: failed to retrieve token: secret keyring is locked` | 키체인 잠금 해제, 앱 권한 확인, 헤드리스 Linux 는 D-Bus 세션 초기화 | | SSH 클립보드 실패 | `Error: local pasteboard is empty or unreachable over SSH connection` | iTerm2/Ghostty 사용, OSC 52 쓰기 채널 활성화, tmux 클립보드 설정 | | 업데이터 락 | `Warning: another background updater process is already active (update.lock)` | `~/.gemini/antigravity-cli/updater/update.lock` 삭제 또는 `AGY_CLI_DISABLE_AUTO_UPDATE=true` | | 설치 디렉터리 권한 | — | `~/.local/bin/`(Unix) 또는 `%LOCALAPPDATA%\agy\bin`(Windows) 소유권·쓰기 권한 확인 | | 체크섬 실패 | `Security Halt: Checksum verification failed.` | 네트워크·프록시 문제 또는 변조. 재시도, 실패 시 중단 | | 알 수 없는 모델 | `invalid model selection (--model "..." --effort "")` | `agy models` 로 슬러그 확인 | --- ## 16. 배치·스케줄러 관점 체크리스트 이 프로젝트가 06:00 무인 실행에서 반드시 지켜야 할 규칙. - [ ] **절대 경로로 호출한다.** `%LOCALAPPDATA%\agy\bin\agy.exe` — 스케줄러 세션의 PATH 를 신뢰하지 않는다. - [ ] **작업은 로그인한 사용자 계정으로 실행한다.** SYSTEM 계정은 `~/.gemini/antigravity-cli/antigravity-oauth-token` 에 접근할 수 없다. - [ ] **`AGY_CLI_DISABLE_AUTO_UPDATE=true`** 를 작업 환경에 설정해 실행 중 자동 업데이트를 막는다. - [ ] **`--output-format json`** 을 쓰고 `stdout` 만 파싱한다. `stderr` 는 로그로 분리 저장한다. - [ ] **종료 코드와 `status` 를 둘 다 검사**한다. - [ ] **`--print-timeout` 을 명시**한다. 기본 5분은 긴 요약 작업에 부족할 수 있다. 권장 `10m`. - [ ] **`--json-schema` 결과를 맹신하지 않는다.** 자체 JSON 추출 + jsonschema 검증을 반드시 통과시킨다. - [ ] **`--continue` 를 쓰지 않는다.** 매 실행은 독립적이어야 한다. - [ ] **`--dangerously-skip-permissions` 를 쓰지 않는다.** 대신 `permissions.allow` 를 최소 범위로 설정한다. - [ ] **`--disable-slash-commands`** 를 붙여, 크롤링한 텍스트에 우연히 들어간 `/명령` 이 확장되는 것을 막는다. - [ ] **호출 횟수를 최소화한다.** 첫 호출 오버헤드가 input 28k 토큰이다. 여러 질문을 한 프롬프트로 묶는다. - [ ] **`usage` 를 매번 로깅**하고 일일 토큰 상한을 코드로 강제한다. - [ ] **`--log-file` 로 실행 ID별 로그 경로를 지정**한다. - [ ] **AI 실패가 배치 실패가 되지 않게 한다.** agy 가 죽어도 xlsx 리포트는 생성돼야 한다. - [ ] **미인증 감지 시 사용자에게 알린다.** 토스트 알림 + 재로그인용 콘솔 창 띄우기 경로를 준비한다. 권장 호출 형태(PowerShell): ```powershell $agy = Join-Path $env:LOCALAPPDATA 'agy\bin\agy.exe' $env:AGY_CLI_DISABLE_AUTO_UPDATE = 'true' $runId = (Get-Date -Format 'yyyyMMdd_HHmmss') $logDir = 'D:\workspace\DMF_Crawler\logs' New-Item -ItemType Directory -Force -Path $logDir | Out-Null $stdout = Join-Path $logDir "agy_$runId.stdout.json" $stderr = Join-Path $logDir "agy_$runId.stderr.log" $args = @( '-p', (Get-Content -Raw 'D:\workspace\DMF_Crawler\prompts\daily_summary.md'), '--output-format', 'json', '--model', 'gemini-3.7-flash-medium', '--effort', 'medium', '--print-timeout', '10m', '--disable-slash-commands', '--log-file', (Join-Path $logDir "agy_cli_$runId.log") ) $proc = Start-Process -FilePath $agy -ArgumentList $args -NoNewWindow -Wait -PassThru ` -RedirectStandardOutput $stdout -RedirectStandardError $stderr if ($proc.ExitCode -ne 0) { throw "agy exited with $($proc.ExitCode). See $stderr" } $envelope = Get-Content -Raw $stdout | ConvertFrom-Json if ($envelope.status -ne 'SUCCESS') { throw "agy status=$($envelope.status): $($envelope.error)" } ``` --- ## 17. 주변 생태계 npm 레지스트리 검색 결과 — `agy` 를 감싸는 서드파티 어댑터가 활발하다. 이 프로젝트가 직접 쓰지는 않지만, **호출 규약의 참고 구현**으로 가치가 있다. | 패키지 | 설명 | 최근 게시 | |---|---|---| | `@claudexor/harness-agy` | "Google Antigravity CLI adapter (`agy -p --output-format stream-json`)" — **stream-json 어댑터 참고 구현** | 2026-09-01 | | `@aibridge/driver-agy` | Antigravity (agy) CLI driver for aibridge | 2026-08-22 | | `dsh-agy-provider` | 로컬 인증된 AGY CLI 를 DSH 모델 프로바이더로 노출 | 2026-08-24 | | `dsh-agy-link` | thinking, tool activity, token usage 포함 연동 | 2026-08-28 | | `dsh-agy` | OAuth 인증 + 멀티 계정 풀 | 2026-08-22 | | `agy-auth` | AGY CLI 멀티 계정 관리 도구 | 2026-08-12 | | `agy-multi` | 멀티 Google 계정 OAuth (login, quota, rotate) | 2026-08-13 | | `@anthonyhaussman/opencode-agy-auth` | OpenCode 인증 플러그인 (OAuth, quota, 모델 조회) | 2026-09-02 | | `opencode-agy-plugin` | OpenCode 프롬프트를 agy 로 라우팅 | 2026-08-15 | | `agy-pi`, `@bacnh85/pi-agy`, `@tian.zuo/pi-antigravity` | Pi 코딩 에이전트 브리지 | 2026-08 | | `agy-plugin-cc` | Claude Code 에서 agy 를 쓰는 플러그인 설치기 | 2026-08-26 | | `n8n-nodes-agy` | **n8n 커뮤니티 노드 — agy 명령 실행 통합** (워크플로 자동화 참고) | 2026-08-18 | | `@bash0816/agy-termux` | Termux(Android ARM64) 용 agy | 2026-09-01 | | `linkgravity` | Discord/Telegram 봇 브리지 (음성 지원) | 2026-08-26 | **시사점**: 멀티 계정 로테이션 도구(`agy-auth`, `agy-multi`, `dsh-agy`)가 여럿 존재한다는 것은 **쿼터 제약이 실제로 존재하고 사용자들이 부딪히고 있다**는 신호다. 이 프로젝트의 일일 토큰 상한 설계는 필수다. 로컬에 등록된 MCP 서버 실측: ``` NAME TYPE STATUS COMMAND/URL chrome-devtools stdio enabled npx -y chrome-devtools-mcp@latest --browser-url=http://localhost:9222 data-agent-kit stdio enabled node ...\mcp_proxy_bundle.js dataAgentKit-antigravityide haramlog-ops stdio enabled node d:\workspace\HaramLog\tools\mcp\haramlog-ops-mcp.mjs notebooks stdio enabled node ...\mcp_proxy_bundle.js notebooks-antigravityide unityMCP http enabled http://localhost:8080/mcp visualization stdio enabled node ...\mcp_proxy_bundle.js visualization-antigravityide ``` > ⚠️ **배치 관점 위험**: 등록된 MCP 서버는 `agy` 실행 시 함께 기동을 시도한다. `chrome-devtools` 는 `npx` 를 호출하고 `unityMCP` 는 localhost:8080 을 찾는다. 무인 배치에서 이들이 없으면 기동 지연이나 오류가 날 수 있다. **배치 전용으로 MCP 를 비활성화**하는 방안을 검토하라 (`agy mcp disable `). → 부록 B. --- ## 부록 A. 출처 목록 | 제목 | URL | 확인 | |---|---|---| | Antigravity CLI — Overview | https://antigravity.google/docs/cli/overview | ✅ 직접 열람 | | Antigravity CLI — Getting Started | https://antigravity.google/docs/cli/getting-started | ✅ 직접 열람 | | Antigravity CLI — Installation & Auth | https://antigravity.google/docs/cli/install | ✅ 직접 열람 | | Antigravity CLI — Headless | https://antigravity.google/docs/cli/headless | ✅ 직접 열람 (핵심 출처) | | Antigravity CLI — Reference | https://antigravity.google/docs/cli/reference | ✅ 직접 열람 | | Antigravity CLI — Settings | https://antigravity.google/docs/cli/settings | ✅ 직접 열람 | | Antigravity CLI — Permissions | https://antigravity.google/docs/cli/permissions | ✅ 직접 열람 | | Antigravity CLI — Modes | https://antigravity.google/docs/cli/modes | ✅ 직접 열람 | | Antigravity CLI — Credits | https://antigravity.google/docs/cli/credits | ✅ 직접 열람 | | Antigravity CLI — Troubleshooting | https://antigravity.google/docs/cli/troubleshooting | ✅ 직접 열람 | | Antigravity CLI — Best Practices | https://antigravity.google/docs/cli/best-practices | ✅ 직접 열람 | | Windows 설치 스크립트 (전문) | https://antigravity.google/cli/install.ps1 | ✅ 전문 확인 | | macOS/Linux 설치 스크립트 | https://antigravity.google/cli/install.sh | 미열람 | | Windows CMD 설치 스크립트 | https://antigravity.google/cli/install.cmd | 미열람 | | 자동 업데이터 매니페스트 엔드포인트 | https://antigravity-cli-auto-updater-974169037036.us-central1.run.app/manifests/windows_amd64.json | install.ps1 에서 확인 | | npm 레지스트리 검색 `agy` | https://registry.npmjs.org/-/v1/search?text=agy&size=20 | ✅ 직접 열람 | | 한국어 튜토리얼 — Antigravity CLI (agy) | https://antigravity.todaycode.kr/antigravity-cli.html | 부분 열람 (IDE 중심) | | 한국어 블로그 — Antigravity CLI 기초·마이그레이션 | https://goddaehee.tistory.com/ | 검색 결과로만 확인 | | 한국어 블로그 — agy 명령어 총정리 | https://infotake.tistory.com/ | 검색 결과로만 확인 | | 참조 문서 (미열람) — 마이그레이션 | https://antigravity.google/docs/cli/gcli-migration | 미열람 | | 참조 문서 (미열람) — 서브에이전트 | https://antigravity.google/docs/cli/subagents | 미열람 | | 참조 문서 (미열람) — 샌드박스 | https://antigravity.google/docs/cli/sandbox | 미열람 | | 참조 문서 (미열람) — MCP | https://antigravity.google/docs/cli/mcp | 미열람 | | 참조 문서 (미열람) — 플러그인 | https://antigravity.google/docs/cli/plugins | 미열람 | | 참조 문서 (미열람) — 프로젝트 | https://antigravity.google/docs/cli/projects | 미열람 | | 참조 문서 (미열람) — 대화 | https://antigravity.google/docs/cli/conversations | 미열람 | | 참조 문서 (미열람) — 아티팩트 | https://antigravity.google/docs/cli/artifacts | 미열람 | | 참조 문서 (미열람) — 플랜/쿼터 | https://antigravity.google/docs/plans | 미열람 | 전체 문서 사이드바 목록(향후 참조용): `overview`, `getting-started`, `install`, `tutorial`, `using`, `features`, `gcli-migration`, `prompting`, `artifacts`, `conversations`, `modes`, `headless`, `subagents`, `sandbox`, `permissions`, `projects`, `settings`, `vim-editor-mode`, `credits`, `mcp`, `plugins`, `statusline`, `title`, `commands/agents`, `commands/codesearch`, `commands/credits`, `commands/diff`, `commands/permissions`, `commands/resume`, `commands/statusline`, `commands/title`, `commands/usage`, `commands/voice`, `best-practices`, `troubleshooting`, `reference` --- ## 부록 B. 미해결 질문 / 실측 필요 항목 - [ ] `--json-schema` 의 `structured_output` 필드가 어떤 조건에서 채워지는가? 모델별 차이인가, 프롬프트 형식 문제인가? (실측에서 누락됨) - [ ] 쿼터 소진 시 정확한 `error` 문자열과 종료 코드는? 감지 로직을 정확히 쓰려면 필요하다. `/docs/plans` 확인 필요. - [ ] `agy update` 의 정확한 동작과 종료 코드. 실행 중 다른 인스턴스가 있으면 어떻게 되는가? - [ ] winget 이 작업 스케줄러(사용자 계정 / SYSTEM 계정)에서 동작하는가? - [ ] `modelProvider: "gemini"` + `GEMINI_API_KEY` 경로에서 사용 가능한 모델 목록이 OAuth 경로와 다른가? Claude 모델도 쓸 수 있는가? - [ ] 등록된 MCP 서버를 배치 실행에서만 비활성화하는 방법이 있는가? (프로젝트 단위 설정이 없다면 전역 비활성화뿐인가) - [ ] `--project` / `--new-project` 의 정확한 의미와 배치에서의 활용 가치. - [ ] `--sandbox` 가 Windows 에서 실제로 무엇을 제한하는가? - [ ] 첫 호출 input_tokens 28k 의 구성 — 시스템 프롬프트인가 워크스페이스 인덱싱인가? 빈 디렉터리에서 실행하면 줄어드는가? (배치 비용 최적화 직결) - [ ] `--add-dir` 로 워크스페이스를 좁히면 토큰 사용량이 감소하는가? - [ ] OAuth access_token 만료 주기와 자동 갱신 실패 시 정확한 오류 표면. - [ ] `conversations/` 와 `history.jsonl` 이 무한히 커지는가? 배치 장기 운영 시 정리 정책 필요. --- *이 문서는 프로젝트의 SSOT 다. 새로운 사실을 확인하면 여기를 갱신하고, 다른 문서는 여기를 링크로 참조한다.*