34 KiB
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— frontmattername/description/tools(콤마 목록)/model: sonnet. 9개 존재. - Codex agents:
.codex/agents/*.md— frontmattername/description(tools/model 없음) + 일반화 본문. 7개 (branch-depth-auditor·coverage-auditor 누락). codex가 실제 읽는 native 포맷은*.toml인데 하나도 없음. - Antigravity agents:
.agents/plugins/wiki-superpowers/agents/*.md— frontmattername/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포함 시) / elseread-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)
- read-only:
File Structure
- Create:
scripts/sync-automation.py— 단일 진입점 CLI. 순수 함수 구역(파싱·권한 파생·직렬화) + I/O 구역(파일 read/write) +argparseCLI. - 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 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.mdvs.codex/agents/wiki-link-verifier.md -
Then Read
.claude/agents/branch-depth-auditor.mdand.claude/agents/coverage-auditor.mdin 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.mdidentically (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이고.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/<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/*.toml9개 +.agents/agents/<name>/agent.json9개 생성·검증.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 검증과 함께 수행 권장.