Files
llm-wiki/docs/superpowers/plans/2026-06-04-three-platform-sync-phase0-engine-agents.md
T

34 KiB
Raw Blame History

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/<name>/agent.json)의 native 포맷으로 생성하는 멱등 스크립트 scripts/sync-automation.py를 만들고, 누락된 2개 agent(branch-depth-auditor·coverage-auditor)를 양 플랫폼에 추가한다.

Architecture: Claude .claude/agents/<name>.md frontmatter의 tools:권한 SSOT로 삼아 codex sandbox_mode와 antigravity toolNames를 기계적으로 파생한다. 프롬프트 본문은 플랫폼별 SSOT(.codex/agents/<name>.md = codex 일반화 본문, .agents/plugins/wiki-superpowers/agents/<name>.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/<name>/agent.json 하나도 없음 (디스크의 ~/.gemini/.../agent.json은 stale·오류 생성물 — read-only agent에 write 도구가 들어있고 content가 요약됨. 신뢰 금지).

확정된 agent.json 스키마 (실 디스크 ~/.gemini/antigravity-cli/brain/.../wiki-research-lane/agent.json에서 키 구조만 채택):

{
  "name": "<name>",
  "description": "<desc>",
  "hidden": true,
  "config": {
    "customAgent": {
      "systemPromptSections": [ { "title": "Agent System Instructions", "content": "<body>" } ],
      "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/<name>.toml ×9, .agents/agents/<name>/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

# 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
# scripts/sync_automation.py
"""Generate Codex/Antigravity native agent files from Claude SSOT.

Permission SSOT  : .claude/agents/<name>.md frontmatter `tools:`
Codex body SSOT  : .codex/agents/<name>.md
Antigravity SSOT : .agents/plugins/wiki-superpowers/agents/<name>.md
Outputs          : .codex/agents/<name>.toml , .agents/agents/<name>/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
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

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
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
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

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
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
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

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
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:

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
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 toolRead/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:

---
name: branch-depth-auditor
description: <verbatim copy of the description line from .claude/agents/branch-depth-auditor.md>
---

<Claude body copied verbatim, then these substitutions applied:
  "Read tool"->"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:

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
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
---
name: branch-depth-auditor
description: <verbatim copy from .claude/agents/branch-depth-auditor.md frontmatter>
---

<body = the codex branch-depth-auditor body content (audit axes + L0~L3 depth ladder
 + Ready/Not-ready verdict logic), PLUS the four gates:
 - G1 Pre-Read Proof: table quoting the first line of each Mandatory First Read
   (CLAUDE.md/AGENTS.md, rules/branch-depth-gate.md, the target branch note).
 - G2 Post-Write Validator: read-only -> 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:

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
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/<name>/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

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:

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:

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
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이고 .tomlpython3 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/<name>/agent.json 생성. --check로 drift 검사.

  • Step 3: Verify the dead reference is gone

Run:

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
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/<name>/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.pycommands 타깃을 확장한다.


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 검증과 함께 수행 권장.