# 3-플랫폼 동기화 Phase 0 — 생성 엔진 + agents Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Claude의 9개 agent를 Codex CLI(`.codex/agents/*.toml`)와 Antigravity CLI(`.agents/agents//agent.json`)의 native 포맷으로 생성하는 멱등 스크립트 `scripts/sync-automation.py`를 만들고, 누락된 2개 agent(`branch-depth-auditor`·`coverage-auditor`)를 양 플랫폼에 추가한다. **Architecture:** Claude `.claude/agents/.md` frontmatter의 `tools:`를 **권한 SSOT**로 삼아 codex `sandbox_mode`와 antigravity `toolNames`를 기계적으로 파생한다. 프롬프트 본문은 플랫폼별 SSOT(`.codex/agents/.md` = codex 일반화 본문, `.agents/plugins/wiki-superpowers/agents/.md` = antigravity gated 본문)에서 가져와 native 머신 포맷으로 포장한다. 스크립트는 순수 함수(권한 파생·포맷 직렬화)와 I/O를 분리하고, `--check` 모드로 SSOT↔생성물 drift를 0으로 검증한다. **Tech Stack:** Python 3.12 (stdlib only — `tomllib` for TOML 검증, `json`, `pathlib`, `argparse`), pytest. --- ## 배경 / 현재 상태 (실측) - Claude agents (SSOT identity + 권한): `.claude/agents/*.md` — frontmatter `name`/`description`/`tools`(콤마 목록)/`model: sonnet`. 9개 존재. - Codex agents: `.codex/agents/*.md` — frontmatter `name`/`description`(tools/model 없음) + 일반화 본문. **7개** (branch-depth-auditor·coverage-auditor 누락). codex가 실제 읽는 native 포맷은 `*.toml`인데 **하나도 없음**. - Antigravity agents: `.agents/plugins/wiki-superpowers/agents/*.md` — frontmatter `name`/`description` + G1~G4 gate 본문. **7개** (동일 2개 누락). antigravity가 실제 읽는 `.agents/agents//agent.json` **하나도 없음** (디스크의 `~/.gemini/.../agent.json`은 stale·오류 생성물 — read-only agent에 write 도구가 들어있고 content가 요약됨. 신뢰 금지). **확정된 agent.json 스키마** (실 디스크 `~/.gemini/antigravity-cli/brain/.../wiki-research-lane/agent.json`에서 키 구조만 채택): ```json { "name": "", "description": "", "hidden": true, "config": { "customAgent": { "systemPromptSections": [ { "title": "Agent System Instructions", "content": "" } ], "toolNames": [ ... ], "systemPromptConfig": { "includeSections": ["user_information","mcp_servers","skills","subagent_reminder","messaging","artifacts","user_rules"] } } } } ``` **권한 파생 규칙** (Claude `tools:` → 플랫폼): | Claude tool | Antigravity `toolNames` | 비고 | |---|---|---| | (모든 agent 공통 baseline) | `send_message`, `view_file`, `find_by_name`, `grep_search`, `list_dir` | 9개 모두 Read+Grep+Glob 보유 | | `Bash` | `run_command` | | | `Edit` | `replace_file_content`, `multi_replace_file_content` | | | `Write` | `write_to_file` | | | `WebFetch` | `read_url_content` | | | `WebSearch` | `search_web` | | - Codex `sandbox_mode` = `workspace-write` (Claude tools에 `Edit` 또는 `Write` 포함 시) / else `read-only`. - 9개 agent 권한 (Claude frontmatter 실측): - read-only: `branch-depth-auditor`(Read,Grep,Glob), `coverage-auditor`·`wiki-adversarial-reviewer`·`wiki-diagram-reviewer`·`wiki-link-verifier`·`wiki-research-lane`(Read,Grep,Glob,Bash) - workspace-write: `wiki-doc-author`(+Edit,Write), `wiki-source-summarizer`(+Edit,Write,WebFetch), `wiki-decision-researcher`(+Write,WebSearch,WebFetch) --- ## File Structure - Create: `scripts/sync-automation.py` — 단일 진입점 CLI. 순수 함수 구역(파싱·권한 파생·직렬화) + I/O 구역(파일 read/write) + `argparse` CLI. - Create: `scripts/test_sync_automation.py` — pytest 단위 테스트 (순수 함수 + 생성물 유효성). - Create: `.codex/agents/branch-depth-auditor.md`, `.codex/agents/coverage-auditor.md` — codex 일반화 본문 SSOT (Claude에서 적응). - Create: `.agents/plugins/wiki-superpowers/agents/branch-depth-auditor.md`, `.agents/plugins/wiki-superpowers/agents/coverage-auditor.md` — antigravity gated 본문 SSOT. - Generate (스크립트 출력): `.codex/agents/.toml` ×9, `.agents/agents//agent.json` ×9. - Modify (Phase 0 말미, 최소): `.codex/agents/README.md`, `.agents/plugins/wiki-superpowers/README.md` — 생성 스크립트 사용법 1단락. (전체 문서 정리는 Phase 2.) > 책임 경계: `sync-automation.py`는 *권한 파생 + 포맷 포장*만 한다. 본문 프로즈의 플랫폼 적응(일반화·gate 작성)은 사람이 SSOT `.md`에 직접 한다. codex는 `.toml`만 로드하므로 `.codex/agents/*.md`는 우리 SSOT로 남고 codex는 무시한다. --- ## Task 1: 스크립트 골격 + frontmatter 파싱 + 권한 파생 (순수 함수) **Files:** - Create: `scripts/sync-automation.py` - Test: `scripts/test_sync_automation.py` - [ ] **Step 1: Write the failing test** ```python # scripts/test_sync_automation.py import json import tomllib import sync_automation as s def test_parse_frontmatter_extracts_fields(): md = ( "---\n" "name: wiki-link-verifier\n" "description: Audit the wiki for orphans.\n" "tools: Read, Grep, Glob, Bash\n" "model: sonnet\n" "---\n\n" "You are the Wiki Link Verifier.\n" ) fm, body = s.parse_frontmatter(md) assert fm["name"] == "wiki-link-verifier" assert fm["description"] == "Audit the wiki for orphans." assert fm["tools"] == "Read, Grep, Glob, Bash" assert body == "You are the Wiki Link Verifier.\n" def test_parse_tools_list(): assert s.parse_tools("Read, Grep, Glob, Bash") == ["Read", "Grep", "Glob", "Bash"] assert s.parse_tools("Read,Edit,Write") == ["Read", "Edit", "Write"] def test_sandbox_mode_read_only_when_no_write_tools(): assert s.codex_sandbox_mode(["Read", "Grep", "Glob", "Bash"]) == "read-only" def test_sandbox_mode_workspace_write_when_edit_or_write(): assert s.codex_sandbox_mode(["Read", "Edit", "Write", "Bash"]) == "workspace-write" assert s.codex_sandbox_mode(["Read", "Write", "WebSearch"]) == "workspace-write" def test_antigravity_toolnames_read_only_agent(): # Read,Grep,Glob,Bash -> baseline + run_command, no write tools assert s.antigravity_tool_names(["Read", "Grep", "Glob", "Bash"]) == [ "send_message", "view_file", "find_by_name", "grep_search", "list_dir", "run_command", ] def test_antigravity_toolnames_write_agent_with_web(): # source-summarizer: Read,Edit,Write,Bash,Grep,Glob,WebFetch assert s.antigravity_tool_names( ["Read", "Edit", "Write", "Bash", "Grep", "Glob", "WebFetch"] ) == [ "send_message", "view_file", "find_by_name", "grep_search", "list_dir", "write_to_file", "replace_file_content", "multi_replace_file_content", "run_command", "read_url_content", ] ``` - [ ] **Step 2: Run test to verify it fails** Run: `cd scripts && python3 -m pytest test_sync_automation.py -v` Expected: FAIL with `ModuleNotFoundError: No module named 'sync_automation'`. > 참고: 파일명이 `sync-automation.py`(하이픈)라 `import sync_automation`이 안 된다. 테스트 상단에서 모듈을 로드하도록 `conftest.py`로 별칭을 만든다(아래 Step 3에 포함). 또는 파일명을 `sync_automation.py`로 하고 CLI는 `python3 scripts/sync_automation.py`로 부른다. **결정: 파일명을 `scripts/sync_automation.py`(언더스코어)로 한다** — import 가능 + CLI 호출에 지장 없음. 본 계획의 이후 모든 경로에서 `sync_automation.py`로 읽는다. - [ ] **Step 3: Write minimal implementation** ```python # scripts/sync_automation.py """Generate Codex/Antigravity native agent files from Claude SSOT. Permission SSOT : .claude/agents/.md frontmatter `tools:` Codex body SSOT : .codex/agents/.md Antigravity SSOT : .agents/plugins/wiki-superpowers/agents/.md Outputs : .codex/agents/.toml , .agents/agents//agent.json """ from __future__ import annotations import argparse import json import sys from pathlib import Path REPO = Path(__file__).resolve().parent.parent CLAUDE_AGENTS = REPO / ".claude" / "agents" CODEX_AGENTS = REPO / ".codex" / "agents" ANTIGRAV_SSOT = REPO / ".agents" / "plugins" / "wiki-superpowers" / "agents" ANTIGRAV_OUT = REPO / ".agents" / "agents" AGENT_NAMES = [ "branch-depth-auditor", "coverage-auditor", "wiki-adversarial-reviewer", "wiki-decision-researcher", "wiki-diagram-reviewer", "wiki-doc-author", "wiki-link-verifier", "wiki-research-lane", "wiki-source-summarizer", ] ANTIGRAV_INCLUDE_SECTIONS = [ "user_information", "mcp_servers", "skills", "subagent_reminder", "messaging", "artifacts", "user_rules", ] _ANTIGRAV_BASELINE = ["send_message", "view_file", "find_by_name", "grep_search", "list_dir"] _ANTIGRAV_EXTRA_ORDER = [ ("Write", ["write_to_file"]), ("Edit", ["replace_file_content", "multi_replace_file_content"]), ("Bash", ["run_command"]), ("WebFetch", ["read_url_content"]), ("WebSearch", ["search_web"]), ] def parse_frontmatter(md: str) -> tuple[dict[str, str], str]: lines = md.splitlines(keepends=True) if not lines or lines[0].strip() != "---": raise ValueError("missing frontmatter open") fm: dict[str, str] = {} i = 1 while i < len(lines) and lines[i].strip() != "---": line = lines[i].rstrip("\n") if ":" in line: key, _, val = line.partition(":") fm[key.strip()] = val.strip() i += 1 if i >= len(lines): raise ValueError("missing frontmatter close") body = "".join(lines[i + 1:]).lstrip("\n") return fm, body def parse_tools(tools_csv: str) -> list[str]: return [t.strip() for t in tools_csv.split(",") if t.strip()] def codex_sandbox_mode(tools: list[str]) -> str: return "workspace-write" if ({"Edit", "Write"} & set(tools)) else "read-only" def antigravity_tool_names(tools: list[str]) -> list[str]: names = list(_ANTIGRAV_BASELINE) tset = set(tools) for claude_tool, mapped in _ANTIGRAV_EXTRA_ORDER: if claude_tool in tset: names.extend(mapped) return names ``` - [ ] **Step 4: Run test to verify it passes** Run: `cd scripts && python3 -m pytest test_sync_automation.py -v` Expected: PASS (6 tests). - [ ] **Step 5: Commit** ```bash git add scripts/sync_automation.py scripts/test_sync_automation.py git commit -m "feat(sync): frontmatter parse + permission derivation pure functions" ``` --- ## Task 2: Codex TOML 직렬화 **Files:** - Modify: `scripts/sync_automation.py` - Test: `scripts/test_sync_automation.py` - [ ] **Step 1: Write the failing test** ```python def test_codex_toml_is_valid_and_roundtrips(): body = "You are the Wiki Link Verifier.\nLine two with `backticks` and 'quotes'.\n" out = s.render_codex_toml( name="wiki-link-verifier", description='Audit "the wiki" for orphans.', sandbox_mode="read-only", body=body, ) parsed = tomllib.loads(out) assert parsed["name"] == "wiki-link-verifier" assert parsed["description"] == 'Audit "the wiki" for orphans.' assert parsed["sandbox_mode"] == "read-only" assert parsed["developer_instructions"].strip() == body.strip() def test_codex_toml_rejects_triple_single_quote_body(): import pytest with pytest.raises(ValueError): s.render_codex_toml("n", "d", "read-only", "bad ''' body") ``` - [ ] **Step 2: Run test to verify it fails** Run: `cd scripts && python3 -m pytest test_sync_automation.py -k codex_toml -v` Expected: FAIL with `AttributeError: module 'sync_automation' has no attribute 'render_codex_toml'`. - [ ] **Step 3: Write minimal implementation** ```python def _toml_basic_string(value: str) -> str: escaped = value.replace("\\", "\\\\").replace('"', '\\"') return f'"{escaped}"' def render_codex_toml(name: str, description: str, sandbox_mode: str, body: str) -> str: if "'''" in body: raise ValueError("body contains ''' which breaks TOML literal multiline string") return ( f"name = {_toml_basic_string(name)}\n" f"description = {_toml_basic_string(description)}\n" f"sandbox_mode = {_toml_basic_string(sandbox_mode)}\n" f"developer_instructions = '''\n" f"{body.rstrip()}\n" f"'''\n" ) ``` - [ ] **Step 4: Run test to verify it passes** Run: `cd scripts && python3 -m pytest test_sync_automation.py -k codex_toml -v` Expected: PASS (2 tests). - [ ] **Step 5: Commit** ```bash git add scripts/sync_automation.py scripts/test_sync_automation.py git commit -m "feat(sync): codex TOML serialization with literal multiline body" ``` --- ## Task 3: Antigravity agent.json 직렬화 **Files:** - Modify: `scripts/sync_automation.py` - Test: `scripts/test_sync_automation.py` - [ ] **Step 1: Write the failing test** ```python def test_antigravity_agent_json_schema(): obj = s.build_antigravity_agent( name="wiki-link-verifier", description="Audit the wiki.", body="You are the Wiki Link Verifier.\n", tools=["Read", "Grep", "Glob", "Bash"], ) assert obj["name"] == "wiki-link-verifier" assert obj["description"] == "Audit the wiki." assert obj["hidden"] is True ca = obj["config"]["customAgent"] assert ca["systemPromptSections"][0]["title"] == "Agent System Instructions" assert ca["systemPromptSections"][0]["content"] == "You are the Wiki Link Verifier.\n" assert "write_to_file" not in ca["toolNames"] # read-only agent assert ca["toolNames"][0] == "send_message" assert ca["systemPromptConfig"]["includeSections"] == s.ANTIGRAV_INCLUDE_SECTIONS def test_antigravity_json_render_is_valid_json(): obj = s.build_antigravity_agent("n", "d", "body\n", ["Read", "Grep", "Glob"]) text = s.render_json(obj) assert json.loads(text) == obj assert text.endswith("\n") ``` - [ ] **Step 2: Run test to verify it fails** Run: `cd scripts && python3 -m pytest test_sync_automation.py -k antigravity_agent_json -v` Expected: FAIL with `AttributeError: ... 'build_antigravity_agent'`. - [ ] **Step 3: Write minimal implementation** ```python def build_antigravity_agent(name: str, description: str, body: str, tools: list[str]) -> dict: return { "name": name, "description": description, "hidden": True, "config": { "customAgent": { "systemPromptSections": [ {"title": "Agent System Instructions", "content": body} ], "toolNames": antigravity_tool_names(tools), "systemPromptConfig": {"includeSections": list(ANTIGRAV_INCLUDE_SECTIONS)}, } }, } def render_json(obj: dict) -> str: return json.dumps(obj, indent=2, ensure_ascii=False) + "\n" ``` - [ ] **Step 4: Run test to verify it passes** Run: `cd scripts && python3 -m pytest test_sync_automation.py -k antigravity_agent_json -v` Expected: PASS (2 tests). - [ ] **Step 5: Commit** ```bash git add scripts/sync_automation.py scripts/test_sync_automation.py git commit -m "feat(sync): antigravity agent.json builder + stable JSON render" ``` --- ## Task 4: CLI 배선 (generate / check) + 기존 7개 검증 **Files:** - Modify: `scripts/sync_automation.py` - Test: `scripts/test_sync_automation.py` - [ ] **Step 1: Write the failing test** ```python def test_load_agent_inputs_for_existing_agent(): inp = s.load_agent_inputs("wiki-link-verifier") assert inp.tools == ["Read", "Grep", "Glob", "Bash"] assert inp.codex_description assert inp.antigrav_description assert "Wiki Link Verifier" in inp.codex_body assert inp.antigrav_body def test_generate_one_writes_both_outputs(tmp_path, monkeypatch): monkeypatch.setattr(s, "CODEX_AGENTS", tmp_path / "codex") monkeypatch.setattr(s, "ANTIGRAV_OUT", tmp_path / "antigrav") (tmp_path / "codex").mkdir() s.generate_one("wiki-link-verifier", check=False) toml_path = tmp_path / "codex" / "wiki-link-verifier.toml" json_path = tmp_path / "antigrav" / "wiki-link-verifier" / "agent.json" assert toml_path.exists() assert json_path.exists() assert tomllib.loads(toml_path.read_text())["sandbox_mode"] == "read-only" assert json.loads(json_path.read_text())["hidden"] is True ``` - [ ] **Step 2: Run test to verify it fails** Run: `cd scripts && python3 -m pytest test_sync_automation.py -k "load_agent_inputs or generate_one" -v` Expected: FAIL with `AttributeError: ... 'load_agent_inputs'`. - [ ] **Step 3: Write minimal implementation** ```python from dataclasses import dataclass @dataclass class AgentInputs: name: str tools: list[str] codex_description: str codex_body: str antigrav_description: str antigrav_body: str def load_agent_inputs(name: str) -> AgentInputs: claude_fm, _ = parse_frontmatter((CLAUDE_AGENTS / f"{name}.md").read_text()) codex_fm, codex_body = parse_frontmatter((CODEX_AGENTS / f"{name}.md").read_text()) ag_fm, ag_body = parse_frontmatter((ANTIGRAV_SSOT / f"{name}.md").read_text()) return AgentInputs( name=name, tools=parse_tools(claude_fm["tools"]), codex_description=codex_fm["description"], codex_body=codex_body, antigrav_description=ag_fm["description"], antigrav_body=ag_body, ) def _write_or_check(path: Path, content: str, check: bool, drift: list[str]) -> None: if check: current = path.read_text() if path.exists() else None if current != content: drift.append(str(path.relative_to(REPO))) else: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content) def generate_one(name: str, check: bool, drift: list[str] | None = None) -> None: drift = drift if drift is not None else [] inp = load_agent_inputs(name) toml_text = render_codex_toml( inp.name, inp.codex_description, codex_sandbox_mode(inp.tools), inp.codex_body ) json_text = render_json( build_antigravity_agent(inp.name, inp.antigrav_description, inp.antigrav_body, inp.tools) ) _write_or_check(CODEX_AGENTS / f"{name}.toml", toml_text, check, drift) _write_or_check(ANTIGRAV_OUT / name / "agent.json", json_text, check, drift) def main(argv: list[str] | None = None) -> int: ap = argparse.ArgumentParser(description="Sync Claude agents -> Codex/Antigravity native files") ap.add_argument("target", choices=["agents"], help="what to sync") ap.add_argument("--check", action="store_true", help="fail (exit 2) if outputs drift from SSOT") ap.add_argument("--only", help="single agent name (default: all)") args = ap.parse_args(argv) names = [args.only] if args.only else AGENT_NAMES drift: list[str] = [] for name in names: generate_one(name, check=args.check, drift=drift) if args.check and drift: print("DRIFT detected in:\n " + "\n ".join(drift), file=sys.stderr) return 2 action = "checked" if args.check else "generated" print(f"{action} {len(names)} agents (codex .toml + antigravity agent.json)") return 0 if __name__ == "__main__": raise SystemExit(main()) ``` - [ ] **Step 4: Run unit tests (still only 7 agents exist, so use --only)** Run: `cd scripts && python3 -m pytest test_sync_automation.py -v` Expected: PASS (all tests). `load_agent_inputs`/`generate_one` use `wiki-link-verifier` which exists. - [ ] **Step 5: Smoke-run on one existing agent** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private python3 scripts/sync_automation.py agents --only wiki-link-verifier python3 -c "import tomllib,pathlib; print(tomllib.loads(pathlib.Path('.codex/agents/wiki-link-verifier.toml').read_text())['sandbox_mode'])" python3 -c "import json,pathlib; o=json.loads(pathlib.Path('.agents/agents/wiki-link-verifier/agent.json').read_text()); print(o['hidden'], 'write_to_file' in o['config']['customAgent']['toolNames'])" ``` Expected output: ``` generated 1 agents (codex .toml + antigravity agent.json) read-only True False ``` (`True False` = hidden true + write_to_file absent for read-only agent — confirms the stale-disk bug is fixed.) - [ ] **Step 6: Commit** ```bash git add scripts/sync_automation.py scripts/test_sync_automation.py .codex/agents/wiki-link-verifier.toml .agents/agents/wiki-link-verifier/agent.json git commit -m "feat(sync): CLI generate/check + AgentInputs loader; verify on link-verifier" ``` --- ## Task 5: 누락 agent 2개의 codex SSOT 본문 작성 (`branch-depth-auditor`, `coverage-auditor`) > codex 본문 = Claude 본문의 일반화: frontmatter에서 `tools:`/`model:` 제거(name+description만 유지), 본문의 `Read tool`/`Edit tool`/`Write tool`/`Bash tool` → `Read`/`Edit`/`Write`/`shell`, `CLAUDE.md` 단독 언급 → `CLAUDE.md (또는 AGENTS.md)`. **Files:** - Create: `.codex/agents/branch-depth-auditor.md` - Create: `.codex/agents/coverage-auditor.md` - [ ] **Step 1: Learn the generalization convention** Read these two pairs side by side to learn the exact convention: - `.claude/agents/wiki-link-verifier.md` vs `.codex/agents/wiki-link-verifier.md` - Then Read `.claude/agents/branch-depth-auditor.md` and `.claude/agents/coverage-auditor.md` in full. - [ ] **Step 2: Create `.codex/agents/branch-depth-auditor.md`** Structure: ```markdown --- name: branch-depth-auditor description: --- "Read", "Grep tool"->"Grep", "Glob tool"->"Glob", "Bash tool"->"shell", "Edit tool"->"Edit", "Write tool"->"Write"; standalone "CLAUDE.md" reference -> "CLAUDE.md (또는 AGENTS.md)". Leave all rules/ and templates/ references, axes, and depth-ladder logic byte-identical.> ``` - [ ] **Step 3: Create `.codex/agents/coverage-auditor.md`** identically (verbatim description + generalized body). - [ ] **Step 4: Verify frontmatter parses for both** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private/scripts && python3 -c " import sync_automation as s for n in ['branch-depth-auditor','coverage-auditor']: fm,body=s.parse_frontmatter(open(f'../.codex/agents/{n}.md').read()) assert fm['name']==n and fm['description'] and body.strip(), n assert 'tool' not in fm and 'model' not in fm, 'frontmatter must be name+description only' print('ok', n) " ``` Expected: ``` ok branch-depth-auditor ok coverage-auditor ``` - [ ] **Step 5: Commit** ```bash git add .codex/agents/branch-depth-auditor.md .codex/agents/coverage-auditor.md git commit -m "feat(codex): add branch-depth-auditor + coverage-auditor SSOT bodies" ``` --- ## Task 6: 누락 agent 2개의 antigravity gated SSOT 본문 작성 > antigravity 본문 = codex 본문 + G1~G4 Gemini hard gate. 기존 read-only gated agent를 템플릿으로 사용한다. tool 참조는 antigravity 어휘(`view_file`/`grep_search`/`run_command`)로 쓴다. **Files:** - Create: `.agents/plugins/wiki-superpowers/agents/branch-depth-auditor.md` - Create: `.agents/plugins/wiki-superpowers/agents/coverage-auditor.md` - [ ] **Step 1: Study the gate template** Read `.agents/plugins/wiki-superpowers/agents/wiki-link-verifier.md` in full (read-only agent — closest analog). Extract the exact section structure of: G1 Pre-Read Proof, G2 Post-Write Validator, G3 Output Schema + V Counter, G4 Enumerated STOP Conditions. Also read `.agents/plugins/wiki-superpowers/agents/wiki-research-lane.md` if a longer analytical example helps. - [ ] **Step 2: Create `.agents/plugins/wiki-superpowers/agents/branch-depth-auditor.md`** ```markdown --- name: branch-depth-auditor description: --- state "read-only agent, no file writes; verification is the grep/sed verbatim-quote proofs inside the gap report (G3 V counter)". - G3 Output Schema + V Counter: {{ }} placeholder schema for the Ready/Not-ready verdict + per-axis gap rows; V = number of quote-grep commands actually run. - G4 Enumerated STOP Conditions: numbered list -> return NEEDS_CONTEXT (1: branch-note path missing/unreadable; 2: linked raw sources unreadable; 3: wiki_structure_lint not yet passed; 4: target is not a feature-*.md branch note). Use Antigravity tool names in any tool reference: view_file, grep_search, run_command.> ``` Mirror the axes/ladder language from `.claude/agents/branch-depth-auditor.md`; do NOT invent new audit criteria. - [ ] **Step 3: Create `.agents/plugins/wiki-superpowers/agents/coverage-auditor.md`** Same structure. Coverage = completeness (covered-here / delegated / missing per required concern) with a 3-tier verdict and optional project mode. G4 STOP conditions: governing_docs missing, `## Coverage` section absent, links unresolved, target not a branch note. tool refs use `run_command` for grep-based concern classification + `view_file` for governing docs. - [ ] **Step 4: Verify frontmatter parses + all four gates present** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private for n in branch-depth-auditor coverage-auditor; do f=.agents/plugins/wiki-superpowers/agents/$n.md echo "== $n ==" grep -c "G1 Pre-Read Proof" "$f" grep -c "G4" "$f" done ``` Expected: each `grep -c` prints `1` or more (gates present). If `0`, the gate section is missing — add it. - [ ] **Step 5: Commit** ```bash git add .agents/plugins/wiki-superpowers/agents/branch-depth-auditor.md .agents/plugins/wiki-superpowers/agents/coverage-auditor.md git commit -m "feat(antigravity): add branch-depth-auditor + coverage-auditor gated SSOT bodies" ``` --- ## Task 7: 전체 9개 생성 + 스키마 검증 + drift 0 확인 **Files:** - Generate: `.codex/agents/*.toml` ×9, `.agents/agents//agent.json` ×9 - Test: `scripts/test_sync_automation.py` (add a full-suite generation guard) - [ ] **Step 1: Add a test asserting all 9 generate and pass schema checks** ```python def test_all_nine_agents_generate_valid_artifacts(tmp_path, monkeypatch): monkeypatch.setattr(s, "CODEX_AGENTS", tmp_path / "codex") monkeypatch.setattr(s, "ANTIGRAV_OUT", tmp_path / "antigrav") # copy SSOT bodies the generator reads from real repo (CODEX_AGENTS is also the source dir), # so point the source dir explicitly: regenerate using real source via a fresh load. (tmp_path / "codex").mkdir() # NOTE: generate_one reads codex body from s.CODEX_AGENTS; for this test we only verify # the antigravity side (json) which reads from ANTIGRAV_SSOT (unchanged real dir). for name in s.AGENT_NAMES: obj = s.build_antigravity_agent( name, "d", s.parse_frontmatter((s.ANTIGRAV_SSOT / f"{name}.md").read_text())[1], s.parse_tools(s.parse_frontmatter((s.CLAUDE_AGENTS / f"{name}.md").read_text())[0]["tools"]), ) assert json.loads(s.render_json(obj))["name"] == name # read-only agents must NOT carry write tools ro = {"branch-depth-auditor", "coverage-auditor", "wiki-adversarial-reviewer", "wiki-diagram-reviewer", "wiki-link-verifier", "wiki-research-lane"} if name in ro: assert "write_to_file" not in obj["config"]["customAgent"]["toolNames"], name ``` > 위 테스트는 `CODEX_AGENTS`/`ANTIGRAV_SSOT`의 9개 `.md`가 모두 존재해야 통과한다(Task 5·6 완료 후). codex toml 본문은 실 디렉토리에서 직접 읽으므로 통합 스모크(Step 3)로 검증한다. - [ ] **Step 2: Run the unit suite** Run: `cd scripts && python3 -m pytest test_sync_automation.py -v` Expected: PASS (all, including the new 9-agent guard). - [ ] **Step 3: Generate all 9 and validate every artifact** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private python3 scripts/sync_automation.py agents echo "--- validate codex toml (9) ---" python3 -c " import tomllib, pathlib ns=['branch-depth-auditor','coverage-auditor','wiki-adversarial-reviewer','wiki-decision-researcher','wiki-diagram-reviewer','wiki-doc-author','wiki-link-verifier','wiki-research-lane','wiki-source-summarizer'] for n in ns: o=tomllib.loads(pathlib.Path(f'.codex/agents/{n}.toml').read_text()) assert o['name']==n and o['sandbox_mode'] in ('read-only','workspace-write') and o['developer_instructions'].strip() print('codex toml ok:', len(ns)) " echo "--- validate antigravity json (9) ---" python3 -c " import json, pathlib ns=['branch-depth-auditor','coverage-auditor','wiki-adversarial-reviewer','wiki-decision-researcher','wiki-diagram-reviewer','wiki-doc-author','wiki-link-verifier','wiki-research-lane','wiki-source-summarizer'] for n in ns: o=json.loads(pathlib.Path(f'.agents/agents/{n}/agent.json').read_text()) ca=o['config']['customAgent'] assert o['name']==n and o['hidden'] is True assert ca['systemPromptSections'][0]['content'].strip() assert ca['toolNames'][0]=='send_message' print('antigravity json ok:', len(ns)) " ``` Expected: ``` generated 9 agents (codex .toml + antigravity agent.json) --- validate codex toml (9) --- codex toml ok: 9 --- validate antigravity json (9) --- antigravity json ok: 9 ``` - [ ] **Step 4: Confirm idempotency / drift-0** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private python3 scripts/sync_automation.py agents --check && echo "DRIFT-FREE" ``` Expected: ``` checked 9 agents (codex .toml + antigravity agent.json) DRIFT-FREE ``` (exit 0). If it prints `DRIFT detected`, re-run without `--check` and re-commit the generated files. - [ ] **Step 5: Commit generated artifacts** ```bash cd /home/donghyeon/dev/llm-wiki-private git add scripts/test_sync_automation.py .codex/agents/*.toml .agents/agents/ git commit -m "feat(sync): generate all 9 agents for codex (.toml) + antigravity (agent.json)" ``` --- ## Task 8: 생성 스크립트 사용법 문서 1단락 (codex + antigravity README) > 전체 문서 정리(CLAUDE.md의 구식 '수동 cat' 서술 제거 등)는 Phase 2. 여기서는 Phase 0가 만든 스크립트/산출물이 고아가 되지 않도록 최소 포인터만 추가한다. **Files:** - Modify: `.codex/agents/README.md` - Modify: `.agents/plugins/wiki-superpowers/README.md` - [ ] **Step 1: Add a "Native generation" note to `.codex/agents/README.md`** 기존 README 상단(또는 "Pattern" 섹션 위)에 다음 취지의 1단락 추가 (정확한 문구는 기존 톤에 맞춰 작성): - codex는 이제 native subagent를 `.codex/agents/*.toml`로 자동 등록한다(`developer_instructions`+`sandbox_mode`). `.md`는 사람이 편집하는 SSOT이고 `.toml`은 `python3 scripts/sync_automation.py agents`로 생성된다. - `.md` 편집 후 반드시 `sync_automation.py agents`를 다시 돌려야 `.toml`에 반영된다. CI/hook에서는 `--check`로 drift를 검사한다. - [ ] **Step 2: Add the same note to `.agents/plugins/wiki-superpowers/README.md`** 기존 "⚠️ Loading model" 박스의 "Sync command" 줄을 실제 스크립트로 교체: - 구: `python3 .agents/scripts/convert-wiki-agents.py` (존재하지 않음) - 신: `python3 scripts/sync_automation.py agents` — `.agents/plugins/.../agents/*.md`(gated SSOT) + `.claude/agents/*.md`(권한 SSOT) → `.agents/agents//agent.json` 생성. `--check`로 drift 검사. - [ ] **Step 3: Verify the dead reference is gone** Run: ```bash cd /home/donghyeon/dev/llm-wiki-private grep -rn "convert-wiki-agents.py" .agents/ .codex/ CLAUDE.md || echo "no dead reference remaining in README scope" ``` Expected: `no dead reference remaining in README scope` (CLAUDE.md 본문의 언급은 Phase 2에서 처리하므로, 여기서 grep이 CLAUDE.md만 남기면 그 줄은 Phase 2 TODO로 남겨도 됨 — 단 README 2개에는 남지 않아야 함). - [ ] **Step 4: Commit** ```bash git add .codex/agents/README.md .agents/plugins/wiki-superpowers/README.md git commit -m "docs(sync): point READMEs at scripts/sync_automation.py (replaces missing convert script)" ``` --- ## Phase 0 완료 기준 (Definition of Done) - `scripts/sync_automation.py` + 테스트 통과(pytest green). - `.codex/agents/*.toml` 9개 + `.agents/agents//agent.json` 9개 생성·검증. - `sync_automation.py agents --check` 가 exit 0 (drift 0). - 누락 2개 agent(branch-depth-auditor·coverage-auditor)가 codex·antigravity 양쪽 SSOT + 생성물에 존재. - README 2개가 실제 생성 스크립트를 가리킴. - 검증된 부채 수정: read-only agent의 `agent.json`에 write 도구 없음(stale 디스크 버그 해소). 이후: **Phase 1**(commands → codex `.agents/skills/` + antigravity `.agents/workflows/`)는 별도 plan으로 작성한다. Phase 0의 `sync_automation.py`에 `commands` 타깃을 확장한다. --- ## Self-Review (작성자 체크) - **Spec coverage**: 설계 §4 Phase 0(엔진+agents)의 모든 항목 — 생성 엔진, 9개 agent 생성, 누락 2개 추가, antigravity 로딩 경로 복구(agent.json+스크립트), codex toml 현대화 — 각각 Task 1~8에 매핑됨. Phase 1·2는 범위 밖(별도 plan). - **Placeholder scan**: 코드 스텝은 실제 코드 포함. Task 5·6의 본문 작성은 "기존 파일을 템플릿으로 verbatim 적응"이라는 결정론적 절차 + 검증 grep을 제공(프로즈 자체는 SSOT 적응이라 코드처럼 박제 불가하나, 입력 파일·치환 규칙·검증 명령을 명시). - **Type consistency**: 함수 시그니처 일관 — `parse_frontmatter`→`(fm,body)`, `antigravity_tool_names(tools)`, `render_codex_toml(name,description,sandbox_mode,body)`, `build_antigravity_agent(name,description,body,tools)`, `generate_one(name,check,drift)`. 모든 Task에서 동일 이름 사용. 모듈명 `sync_automation`(언더스코어)로 통일. - **알려진 한계**: Task 7 Step 1 테스트는 codex toml 본문을 실디렉토리에서 읽어 통합 스모크(Step 3)로 보완. Task 6 Step 4의 grep 카운트는 게이트 "존재"만 보장하고 의미적 정확성은 보장하지 않음 → 실제 antigravity 실행 스모크는 Phase 1 검증과 함께 수행 권장.