Files
llm-wiki/docs/superpowers/specs/2026-06-09-deep-research-codex-antigravity-port-design.md

17 KiB

Deep-Research 하네스 → Codex / Antigravity CLI 이식 설계

  • 상태: design (구현 전)
  • 작성일: 2026-06-09
  • 원본 하네스: Claude Code Workflow 도구 기반 JS 스크립트 ~/.claude/projects/-home-donghyeon-dev-llm-wiki-private/88afa9ca-1e45-4353-9ff0-6361812d9053/workflows/scripts/deep-research-wf_aecef33f-4cc.js
  • 목표: claude code의 deep-research를 codex-cli와 antigravity-cli 각각이 그대로 수행할 수 있도록 단일 외부 Python 드라이버로 이식. 완전 충실(원본 동작·상수·퇴화 경로 1:1).

0. 한 줄 요약

원본 deep-research는 Claude Workflow 도구 위에서 도는 결정론적 JS 오케스트레이터다. Codex/Antigravity는 이 도구가 없고 오케스트레이션이 모델 주도이므로, 결정론 제어 로직을 외부 Python 드라이버 1벌에 이식하고, 각 플랫폼은 run_agent() backend 어댑터로 흡수한다. 에이전트 실행기는 각 CLI의 headless 모드(codex exec, agy -p)이며, 웹 조사는 각 CLI의 네이티브 web_search·webfetch 도구가 수행한다(별도 검색 API·비용 없음). 포팅 = 프롬프트 3벌 복제가 아니라 backend flag 하나로 분기하는 1벌 도구.


1. 배경 / 문제

1.1 원본 하네스의 2층 구조

내용 이식 난이도
층1 — 결정론 제어 (JS 코드, 모델이 못 건드림) URL 정규화·dedup, fetch 예산 회계, claim 랭킹, 3-vote 정족수 산식, barrier 동기화, stats 플랫폼 무관 — 코드로 1:1 이식
층2 — 에이전트 프롬프트 + 스키마 + 페이즈 Scope→Search→Fetch→Verify→Synthesize 6단계 프롬프트, 5개 JSON 스키마, 3-vote adversarial 패턴 플랫폼 무관 콘텐츠 — 그대로 이식

1.2 플랫폼 능력 검증 결과 (공식 소스 기반)

능력 Claude Code Codex CLI (codex exec) Antigravity CLI (agy)
결정론적 코드 제어 Workflow 네이티브 (모델 주도) → 외부 드라이버 필요 (모델 주도) → 외부 드라이버 필요
병렬 실행 parallel() subprocess 병렬 Async Subagent / subprocess 병렬
headless 단발 실행 codex exec agy -p "prompt" (Command Mode)
네이티브 웹검색 WebSearch codex exec --json에 web_search 항목 harness 내 web/research 도구
네이티브 웹페치 WebFetch webfetch
스키마 강제 출력 tool-layer 검증+재시도 --output-schema <jsonschema> ⚠️ 미확인 → 드라이버 검증·재시도로 보강
설정 포맷 JS .toml agent / CLI flag agent.json / CLI flag

검증 메모: 초기 조사 때 "Codex/Antigravity 서브에이전트는 웹·스키마 없음"이라 판단했으나, 그건 interactive subagent 문서만 본 오판이었다. codex exec headless 모드에는 --json(web_search 이벤트 포함) + --output-schema가 있고, agy -p도 동일 harness의 웹 도구를 쓴다. 따라서 별도 검색 API(Tavily 등)·bare SDK는 불필요하며, 사용자가 이미 구독으로 쓰는 CLI 네이티브 도구를 그대로 활용한다.

출처:

1.3 왜 SDK가 아니라 CLI headless인가

  • 비용: CLI는 구독제 → 호출당 추가 과금 없음. bare SDK + 검색 API는 중복 비용.
  • 충실도: 원본은 에이전트가 직접 WebSearch/WebFetch를 호출한다. CLI headless도 에이전트가 네이티브 웹도구를 호출 → 동일 의미.
  • 스키마: Codex --output-schema가 tool-layer 검증을 대체. Antigravity는 드라이버가 Pydantic 검증·재시도로 보강.

2. 목표 / 비목표

목표

  1. 원본 6페이즈·상수·퇴화 경로를 1:1 충실 이식.
  2. python -m deep_research --backend {codex|antigravity} "<질문>" 단일 진입점으로 두 플랫폼에서 동일 동작.
  3. 결정론 제어 로직을 순수 함수로 분리 → 단위테스트로 원본 동작 회귀 검증.
  4. 웹·스키마를 각 CLI 네이티브 기능으로 충족(추가 비용 0).

비목표

  • Claude를 backend로 추가하지 않음(원본 그 자체이므로 불필요).
  • repo의 .claude/.codex/.agents 프롬프트 미러 체계에 편입하지 않음(이 드라이버는 그 밖의 새 카테고리 — 1벌 도구).
  • 원본 상수·페이즈 구조 변경/최적화 없음(충실 우선).
  • GUI·서버·스케줄러 없음(단발 CLI 실행만).

3. 아키텍처

scripts/deep-research/
├── pyproject.toml              # deps: pydantic>=2, (stdlib asyncio/subprocess/json)
├── README.md                   # 사용법, 인증 전제, backend별 주의
├── deep_research/
│   ├── __init__.py
│   ├── __main__.py             # CLI 진입점, argparse, .env/키 점검, report 출력
│   ├── config.py               # 상수 (원본과 동일): VOTES_PER_CLAIM 등 + 동시성 cap
│   ├── schemas.py              # 5 Pydantic v2 모델 + JSON Schema export 헬퍼
│   ├── core.py                 # 결정론 순수함수 (JS 1:1): dedup/budget/rank/tally/assemble
│   ├── pipeline.py             # asyncio 오케스트레이션 (무배리어 pipeline / verify 배리어)
│   ├── prompts.py              # 6단계 프롬프트 (원본 문자열 이식)
│   ├── backends/
│   │   ├── base.py             # AgentBackend ABC: async run_agent(prompt, schema) -> BaseModel
│   │   ├── codex.py            # codex exec --json --output-schema 호출·파싱
│   │   ├── antigravity.py      # agy -p 호출·파싱 + Pydantic 검증·재시도
│   │   └── mock.py             # 테스트 더블 (고정 응답 주입)
│   └── report.py               # Report → markdown + JSON dump
└── tests/
    ├── test_core.py            # dedup/budget/tally/rank 단위테스트
    └── test_pipeline_mock.py   # MockBackend 통합 스모크 + 퇴화 경로 3종

3.1 모듈 책임 (단일 책임 / 격리)

  • core.py — 네트워크·LLM·플랫폼 의존 0. 입력 dict/list → 출력 dict/list 순수 변환. 단위테스트 100% 가능. 충실도의 심장.
  • backends/ — 유일하게 플랫폼을 아는 곳. interface run_agent(prompt, schema) -> 검증된 Pydantic 객체. 한 backend 교체가 core·pipeline에 무영향.
  • pipeline.py — core 함수 + backend 호출을 asyncio로 엮는 곳. 원본 pipeline()(무배리어) / parallel()(배리어) 의미를 asyncio로 재현.
  • web 계층 없음 — 웹은 backend가 호출하는 CLI의 네이티브 도구가 수행. 드라이버는 URL 문자열만 다룬다(정규화·dedup).

3.2 backend 인터페이스 계약

class AgentBackend(ABC):
    @abstractmethod
    async def run_agent(self, prompt: str, schema: type[BaseModel],
                        *, label: str) -> BaseModel | None:
        """프롬프트를 1개 CLI headless 에이전트로 실행, schema로 검증된 객체 반환.
        실패/사용자-skip → None (원본 .filter(Boolean) 의미)."""
  • codex.py: codex exec --json --output-schema <tmp.json> --cd <neutral_dir> -s read-only "<prompt>" subprocess. JSONL stdout에서 최종 메시지 파싱 → Pydantic 검증. 웹은 codex 네이티브 web_search.
  • antigravity.py: agy -p "<prompt>" ... subprocess. 출력 파싱 → Pydantic 검증, 실패 시 "스키마에 맞춰 JSON만" 재프롬프트 N회(기본 2). 웹은 agy 네이티브 도구.
  • mock.py: 생성자에 {label_prefix: 응답객체} 주입. 네트워크·subprocess 없이 즉답. 테스트 전용.

중립 작업 디렉터리: CLI executor는 repo가 아닌 임시/중립 --cd에서 호출 → 코드베이스 컨텍스트(AGENTS.md/CLAUDE.md)를 안 물고 순수 리서치 에이전트로 동작. read-only 샌드박스.


4. 상수 (원본과 동일 — config.py)

VOTES_PER_CLAIM      = 3      # claim당 verifier 수
REFUTATIONS_REQUIRED = 2      # 2/3 refute면 kill
MAX_FETCH            = 15     # fetch 예산 (전체 novel URL 상한)
MAX_VERIFY_CLAIMS    = 25     # 검증 대상 claim 상한
ANGLES_TARGET        = 5      # scope 분해 목표(스키마 minItems3/maxItems6)
CONCURRENCY          = 10     # asyncio.Semaphore (원본 Workflow cap 대응, 설정 가능)
ANTIGRAVITY_RETRIES  = 2      # 스키마 검증 실패 시 재프롬프트 횟수

5. 스키마 (schemas.py — 5 Pydantic v2 모델)

원본 5 SCHEMA를 Pydantic으로 1:1. model_json_schema()로 Codex --output-schema용 JSON Schema export.

  • Scope: question:str, summary:str, angles: list[Angle](min 3, max 6) / Angle{label, query, rationale?}
  • Search: results: list[SearchResult](max 6) / SearchResult{url, title, snippet?, relevance: Enum[high|medium|low]}
  • Extract: sourceQuality: Enum[primary|secondary|blog|forum|unreliable], publishDate?, claims: list[Claim](max 5) / Claim{claim, quote, importance: Enum[central|supporting|tangential]}
  • Verdict: refuted:bool, evidence:str, confidence: Enum[high|medium|low], counterSource?
  • Report: summary, findings: list[Finding] / Finding{claim, confidence, sources:list[str], evidence, vote?}, caveats, openQuestions?: list[str]

6. 데이터 흐름 (6 페이즈 — 원본 충실)

6.0 Scope (1 agent)

질문 → 5개 상보적 검색 각도(Scope). 빈 질문이면 즉시 에러 반환(원본과 동일).

6.1 Search (각도별 1 agent, 무배리어 pipeline 1단계)

  • 에이전트가 CLI 네이티브 web_search로 검색(쿼리 정제 가능) → 원질문 기준 관련도 재랭킹·SEO 스팸 제거 → top 4-6(Search).
  • 드라이버는 검색을 직접 하지 않음. 에이전트의 인지 단계(관련도 판단) 보존.

6.2 Dedup (순수 드라이버 — core.dedup)

원본 로직 1:1:

  • normURL(u): hostname www. 제거 + pathname 후행 / 제거 + lowercase. 파싱 실패 시 u.lower().
  • seen: set, relevance 순(high<medium<low) 정렬 후 순회.
  • 이미 본 키 → dupes에 적재, 스킵.
  • fetchSlots<=0 이고 relevance가 medium/low(rank≥1) → budgetDropped에 적재, 스킵.
  • 통과 시 seen에 추가, fetchSlots--.

6.3 Fetch + Extract (novel URL별 1 agent, pipeline 2단계 parallel)

  • 에이전트가 CLI 네이티브 webfetch로 본문 취득 → 출처품질 평가 + falsifiable claim 2-5개(직접 인용 포함) 추출(Extract).
  • fetch 실패/무관/페이월 → claims:[], sourceQuality:"unreliable"(원본과 동일).
  • backend가 None 반환(실패/skip) → 드롭(원본 .filter(Boolean)).

6.4 Rank (순수 — core.rank_claims)

importance(central<supporting<tangential) → sourceQuality(primary<…<unreliable) 순 정렬 → 상위 MAX_VERIFY_CLAIMS=25.

6.5 Verify (배리어 — claim당 3 agent 병렬)

  • claim당 VOTES_PER_CLAIM=3 verifier를 병렬, "refute 우선" 프롬프트(Verdict).
  • 정족수 산식 (core.tally, 원본 1:1, abstention 엣지 포함):
    • valid = [v for v in verdicts if v is not None] (None=기권)
    • refuted = sum(v.refuted for v in valid)
    • survives = (len(valid) >= REFUTATIONS_REQUIRED) and (refuted < REFUTATIONS_REQUIRED)
    • ⚠️ all-abstain → refuted=0 → 거짓 생존 금지: len(valid) >= 2 조건이 이를 차단(원본 주석과 동일 의도). 이 엣지는 단위테스트로 고정.

6.6 Synthesize (1 agent)

생존 claim → 의미중복 병합·findings 그룹화·confidence 부여·3-5문장 요약·caveats·open questions(Report). refuted 목록은 투명성 위해 첨부.

6.7 퇴화 경로 3종 (원본 1:1 — 반드시 보존)

  1. claim 0개: 검증 0건 요약 + sources/stats 반환.
  2. 전건 refute: "adversarial verification에서 전부 기각, 결론 불가" 요약 + refuted 목록 반환.
  3. synthesis 실패/skip: 보고서 대신 생존 claim raw salvage 반환(전체 run 폐기 금지).

6.8 stats (원본 키 보존)

angles, sourcesFetched, claimsExtracted, claimsVerified, confirmed, killed, afterSynthesis, urlDupes, budgetDropped, agentCalls(=1+angles+sources+voted*3+1).


7. 동시성 (pipeline.py)

  • asyncio.Semaphore(CONCURRENCY)로 동시 CLI subprocess 수 제한.
  • 무배리어 pipeline (Search→Dedup→Fetch): 각도별 async 체인 — A각도가 Fetch 도는 동안 B각도는 Search 가능. 단, dedup의 seen/fetchSlots는 공유 상태이므로 각 Search 완료 직후 dedup을 적용하는 지점에서만 갱신(원본은 pipeline 2단계 진입 시 순차 도착하며 갱신). → asyncio에서는 dedup 임계구역을 단일 코루틴/락으로 직렬화해 경쟁 제거.
  • 배리어 (Verify): 전체 claim 풀이 모인 뒤 asyncio.gather로 일괄 검증(원본 의도적 barrier).
  • agent 호출 1개 = CLI subprocess 1개. 콜드스타트 ~97콜/run → 구독제라 비용 무관, 속도는 동시성으로 완화.

8. 에러 처리

상황 처리 (원본 의미)
backend run_agent 실패/타임아웃 None 반환 → 상위에서 filter
fetch 실패/페이월 unreliable + claims:[]
verifier 기권(None) valid에서 제외, 정족수 미달 시 미생존
Codex --output-schema 위반 codex 재시도; 그래도 실패 시 None
Antigravity 스키마 검증 실패 드라이버가 "JSON만" 재프롬프트 ANTIGRAVITY_RETRIES회 후 None
빈 질문 / scope 실패 즉시 에러 dict 반환
키/CLI 미설치 시작 시 명확한 에러로 중단

9. 인증 / 설정 전제

  • codex backend: codex CLI 설치 + 로그인(구독). 웹검색 활성(--json web_search).
  • antigravity backend: agy CLI 설치 + 로그인(구독). 웹 도구 활성.
  • 별도 검색 API 키 불필요.
  • 시작 시 선택된 backend의 CLI 존재·로그인 점검, 미충족 시 안내 후 종료.

10. 테스트 전략

10.1 core 순수함수 단위테스트 (test_core.py)

  • normURL: www/trailing-slash/대소문자/파싱실패 케이스.
  • dedup: 중복 적재, budget-drop(slot 소진 시 medium/low만), high는 slot 무시 통과 여부(원본 relRank>=1 조건 정확 재현).
  • tally: 3-0/2-1/1-2/0-3, all-abstain(생존 금지), 1 valid+2 abstain(미달 미생존), 2 valid 0 refute(생존).
  • rank_claims: importance·quality 2차 정렬 순서.

10.2 MockBackend 통합 스모크 (test_pipeline_mock.py)

  • 고정 응답으로 6페이즈 정상 흐름 1건 + 퇴화 경로 3종 재현. 네트워크·키·subprocess 0.
  • stats 키·agentCalls 계산식 검증.

10.3 실 backend 스모크 (수동, 선택)

  • 짧은 질문 1건을 --backend codex / --backend antigravity로 각 1회 실행, 보고서·stats 육안 확인.

11. 리스크 / 미해결 (구현 1차에서 확인)

리스크 영향 완화
agy output-schema 플래그 유무 미확인 Antigravity 스키마 보장 약함 드라이버 Pydantic 검증·재시도로 보강; 플래그 있으면 채택
CLI 콜드스타트 누적 지연 run 시간 증가 동시성 cap 상향, Antigravity Go 런타임, (후속) 세션 재사용/spawn_agents_on_csv
codex exec JSONL 최종 메시지 추출 형식 파싱 취약 이벤트 타입 기반 파서 + 스키마 검증으로 방어
무배리어 pipeline의 dedup 공유 상태 경쟁 dedup 비결정성 dedup 임계구역 직렬화(락/단일 코루틴)
repo 내 scripts/ 부재(기존 메모) 신규 디렉터리 scripts/deep-research/ 신설 — sync 생성기와 무관(별 카테고리)

12. 거버넌스 / repo 정합

  • 이 드라이버는 프롬프트 미러(.claude/.codex/.agents) 대상이 아님 — backend 어댑터로 분기하는 1벌 도구.
  • 위치: scripts/deep-research/. 구현 완료 후 CLAUDE.md에 "외부 도구: deep-research 드라이버" 한 줄 등재 검토(별 카테고리, 3-플랫폼 패리티 예외 — invest/project 파이프라인과 유사한 비미러 항목).
  • 원본 JS 경로를 README에 명시해 충실도 대조 기준 보존.

13. 구현 순서(개요 — 상세는 plan 단계)

  1. schemas.py + config.py + prompts.py(원본 문자열 이식).
  2. core.py 순수함수 + test_core.py(원본 동작 고정).
  3. backends/base.py + mock.py + test_pipeline_mock.py(퇴화 경로 포함) — 여기까지 네트워크 0으로 충실도 검증 완료.
  4. pipeline.py(asyncio, dedup 임계구역 직렬화) — MockBackend로 통과.
  5. backends/codex.py(codex exec --json --output-schema) → 실 스모크.
  6. backends/antigravity.py(agy -p + 검증·재시도) → 실 스모크.
  7. report.py + __main__.py + README.