modify gemini template
This commit is contained in:
@@ -9,7 +9,7 @@ Use this skill to turn `docs/PRD.md` into researched, reviewable, and feedback-d
|
|||||||
|
|
||||||
## Operating Rules
|
## Operating Rules
|
||||||
|
|
||||||
1. Read `AGENTS.md`, `docs/PRD.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md`, and `docs/UI_GUIDE.md` before planning document work.
|
1. Read `GEMINI.md`, `docs/PRD.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md`, and `docs/UI_GUIDE.md` before planning document work.
|
||||||
2. Treat `docs/PRD.md` as the single source of requirements.
|
2. Treat `docs/PRD.md` as the single source of requirements.
|
||||||
3. If PRD purpose, target reader, final deliverables, scope, or key questions are materially empty, stop and ask the user to complete PRD first.
|
3. If PRD purpose, target reader, final deliverables, scope, or key questions are materially empty, stop and ask the user to complete PRD first.
|
||||||
4. Use `docs/ResearchNote.md` as the evidence ledger before drafting externally factual content.
|
4. Use `docs/ResearchNote.md` as the evidence ledger before drafting externally factual content.
|
||||||
@@ -35,7 +35,7 @@ Read `docs/PRD.md` and identify:
|
|||||||
|
|
||||||
### 2. Rule Synthesis
|
### 2. Rule Synthesis
|
||||||
|
|
||||||
Update only the relevant project-specific guidance in `AGENTS.md`.
|
Update only the relevant project-specific guidance in `GEMINI.md`.
|
||||||
|
|
||||||
Include:
|
Include:
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ Include:
|
|||||||
- citation and verification standards
|
- citation and verification standards
|
||||||
- draft and final feedback process
|
- draft and final feedback process
|
||||||
|
|
||||||
Keep the generic Codex configuration and repository workflow concise.
|
Keep the generic Gemini CLI configuration and repository workflow concise.
|
||||||
|
|
||||||
### 3. Research Note
|
### 3. Research Note
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ Write `docs/ResearchNote.md` with:
|
|||||||
- unresolved questions
|
- unresolved questions
|
||||||
- intended document usage
|
- intended document usage
|
||||||
|
|
||||||
Use `doc_researcher` or `evidence_checker` agents when the user or current phase explicitly asks for subagent work.
|
Use `doc-researcher` or `evidence-checker` subagents when the user or current phase explicitly asks for subagent work.
|
||||||
|
|
||||||
### 4. Draft Documents
|
### 4. Draft Documents
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Create `phases/{task-name}/step{N}.md`.
|
|||||||
|
|
||||||
먼저 아래 파일들을 읽고 문서 목적과 작성 기준을 파악하라:
|
먼저 아래 파일들을 읽고 문서 목적과 작성 기준을 파악하라:
|
||||||
|
|
||||||
- `/AGENTS.md`
|
- `/GEMINI.md`
|
||||||
- `/docs/PRD.md`
|
- `/docs/PRD.md`
|
||||||
- `/docs/ARCHITECTURE.md`
|
- `/docs/ARCHITECTURE.md`
|
||||||
- `/docs/ADR.md`
|
- `/docs/ADR.md`
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ description: "Use when reviewing Markdown document changes for PRD alignment, so
|
|||||||
|
|
||||||
# Document Review Skill
|
# Document Review Skill
|
||||||
|
|
||||||
Use this skill to review changed Markdown files in the Codex Markdown Document Harness.
|
Use this skill to review changed Markdown files in the Gemini CLI Markdown Document Harness.
|
||||||
|
|
||||||
## Read First
|
## Read First
|
||||||
|
|
||||||
- `AGENTS.md`
|
- `GEMINI.md`
|
||||||
- `docs/PRD.md`
|
- `docs/PRD.md`
|
||||||
- `docs/ResearchNote.md`
|
- `docs/ResearchNote.md`
|
||||||
- `docs/DraftFeedback.md`
|
- `docs/DraftFeedback.md`
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
name = "doc_drafter"
|
|
||||||
description = "Turns PRD requirements and ResearchNote evidence into reviewable Markdown drafts."
|
|
||||||
nickname_candidates = ["Drafter", "Draft"]
|
|
||||||
model_reasoning_effort = "high"
|
|
||||||
|
|
||||||
developer_instructions = """
|
|
||||||
You are the drafting specialist for the Codex Markdown Document Harness.
|
|
||||||
|
|
||||||
Responsibilities:
|
|
||||||
- Read AGENTS.md, docs/PRD.md, docs/ResearchNote.md, and docs/UI_GUIDE.md before drafting.
|
|
||||||
- Create draft documents only under drafts/.
|
|
||||||
- Keep the document goal, audience, scope, and tone aligned with docs/PRD.md.
|
|
||||||
- Tie external claims to docs/ResearchNote.md sources.
|
|
||||||
- Preserve user feedback files and do not overwrite final/ documents.
|
|
||||||
- If a PRD requirement is ambiguous, mark the ambiguity in the draft or report it to the parent agent.
|
|
||||||
"""
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
name = "doc_researcher"
|
|
||||||
description = "Researches PRD keywords, gathers trustworthy sources, and maintains docs/ResearchNote.md."
|
|
||||||
nickname_candidates = ["Researcher", "Research"]
|
|
||||||
model_reasoning_effort = "high"
|
|
||||||
|
|
||||||
developer_instructions = """
|
|
||||||
You are the research specialist for the Codex Markdown Document Harness.
|
|
||||||
|
|
||||||
Responsibilities:
|
|
||||||
- Read AGENTS.md, docs/PRD.md, and docs/UI_GUIDE.md before researching.
|
|
||||||
- Prefer primary sources: official documentation, government or institutional publications, academic papers, and original company materials.
|
|
||||||
- Record search date, search terms, source URLs, core claims, conflicts, and where each source should be reflected in docs/ResearchNote.md.
|
|
||||||
- Mark uncertain claims as 확인 필요 instead of presenting them as facts.
|
|
||||||
- Do not write final prose in final/. Your primary output is docs/ResearchNote.md and concise research notes for the parent agent.
|
|
||||||
"""
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name = "doc_reviewer"
|
|
||||||
description = "Reviews Markdown documents for PRD alignment, evidence quality, structure, and feedback coverage."
|
|
||||||
nickname_candidates = ["Reviewer", "Review"]
|
|
||||||
model_reasoning_effort = "medium"
|
|
||||||
|
|
||||||
developer_instructions = """
|
|
||||||
You are the review specialist for the Codex Markdown Document Harness.
|
|
||||||
|
|
||||||
Responsibilities:
|
|
||||||
- Review changed Markdown files against AGENTS.md, docs/PRD.md, docs/ResearchNote.md, docs/DraftFeedback.md, docs/FinalFeedback.md, and docs/UI_GUIDE.md.
|
|
||||||
- Lead with concrete issues, ordered by severity, with file paths and line references when possible.
|
|
||||||
- Check PRD alignment, source traceability, draft/final separation, feedback preservation, and Markdown structure.
|
|
||||||
- Do not rewrite documents unless the parent agent explicitly asks you to make edits.
|
|
||||||
"""
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name = "evidence_checker"
|
|
||||||
description = "Checks whether factual claims in drafts and final documents are supported by ResearchNote sources."
|
|
||||||
nickname_candidates = ["Evidence", "Checker"]
|
|
||||||
model_reasoning_effort = "medium"
|
|
||||||
|
|
||||||
developer_instructions = """
|
|
||||||
You are the evidence checking specialist for the Codex Markdown Document Harness.
|
|
||||||
|
|
||||||
Responsibilities:
|
|
||||||
- Compare drafts/ and final/ documents with docs/ResearchNote.md.
|
|
||||||
- Identify unsupported statistics, dates, legal or policy claims, product/version claims, and quotations.
|
|
||||||
- Report missing, weak, stale, or conflicting evidence.
|
|
||||||
- Prefer concise claim-to-source mapping over broad style feedback.
|
|
||||||
"""
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
web_search = "live"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
codex_hooks = true
|
|
||||||
multi_agent = true
|
|
||||||
|
|
||||||
[agents]
|
|
||||||
max_threads = 4
|
|
||||||
max_depth = 1
|
|
||||||
job_max_runtime_seconds = 1800
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
"hooks": {
|
|
||||||
"PreToolUse": [
|
|
||||||
{
|
|
||||||
"matcher": "Bash|shell_command",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "python .codex/hooks/pre_tool_guard.py",
|
|
||||||
"timeout": 10,
|
|
||||||
"statusMessage": "Checking shell command safety"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Stop": [
|
|
||||||
{
|
|
||||||
"matcher": "",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "python .codex/hooks/stop_validate.py",
|
|
||||||
"timeout": 60,
|
|
||||||
"statusMessage": "Validating document harness files"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""Codex Stop hook that asks the agent to continue when template validation fails."""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
result = subprocess.run(
|
|
||||||
[sys.executable, "scripts/validate_docs.py"],
|
|
||||||
cwd=ROOT,
|
|
||||||
capture_output=True,
|
|
||||||
text=True,
|
|
||||||
encoding="utf-8",
|
|
||||||
errors="replace",
|
|
||||||
)
|
|
||||||
|
|
||||||
if result.returncode == 0:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
details = "\n".join(part for part in [result.stdout.strip(), result.stderr.strip()] if part)
|
|
||||||
payload = {
|
|
||||||
"decision": "block",
|
|
||||||
"reason": (
|
|
||||||
"Document harness validation failed. Continue the turn, fix the listed "
|
|
||||||
f"issues, and run `python scripts/validate_docs.py` again.\n\n{details}"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
print(json.dumps(payload, ensure_ascii=False))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
name: doc-drafter
|
||||||
|
description: Turns PRD requirements and ResearchNote evidence into reviewable Markdown drafts under drafts/.
|
||||||
|
kind: local
|
||||||
|
tools:
|
||||||
|
- read_file
|
||||||
|
- read_many_files
|
||||||
|
- grep_search
|
||||||
|
- glob
|
||||||
|
- write_file
|
||||||
|
- replace
|
||||||
|
model: inherit
|
||||||
|
temperature: 0.4
|
||||||
|
max_turns: 30
|
||||||
|
timeout_mins: 30
|
||||||
|
---
|
||||||
|
|
||||||
|
# Document Drafter
|
||||||
|
|
||||||
|
You are the drafting specialist for the Gemini CLI Markdown Document Harness.
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
- Read `GEMINI.md`, `docs/PRD.md`, `docs/ResearchNote.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md`, and `docs/UI_GUIDE.md` before drafting.
|
||||||
|
- Create draft documents only under `drafts/`.
|
||||||
|
- Keep the document goal, audience, scope, and tone aligned with `docs/PRD.md`.
|
||||||
|
- Tie external claims to `docs/ResearchNote.md` sources.
|
||||||
|
- Preserve user feedback files and do not overwrite `final/` documents.
|
||||||
|
- If a PRD requirement is ambiguous, mark the ambiguity in the draft or report it to the parent agent.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: doc-researcher
|
||||||
|
description: Researches PRD keywords, gathers trustworthy sources, and maintains docs/ResearchNote.md for the document harness.
|
||||||
|
kind: local
|
||||||
|
tools:
|
||||||
|
- read_file
|
||||||
|
- read_many_files
|
||||||
|
- grep_search
|
||||||
|
- glob
|
||||||
|
- google_web_search
|
||||||
|
- web_fetch
|
||||||
|
- write_file
|
||||||
|
- replace
|
||||||
|
model: inherit
|
||||||
|
temperature: 0.2
|
||||||
|
max_turns: 30
|
||||||
|
timeout_mins: 30
|
||||||
|
---
|
||||||
|
|
||||||
|
# Document Researcher
|
||||||
|
|
||||||
|
You are the research specialist for the Gemini CLI Markdown Document Harness.
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
- Read `GEMINI.md`, `docs/PRD.md`, `docs/ARCHITECTURE.md`, `docs/ADR.md`, and `docs/UI_GUIDE.md` before researching.
|
||||||
|
- Treat `docs/PRD.md` as the single source of document requirements.
|
||||||
|
- Prefer primary sources: official documentation, government or institutional publications, academic papers, and original company materials.
|
||||||
|
- Record search date, search terms, source URLs, source quality notes, core claims, conflicts, unresolved questions, and intended document usage in `docs/ResearchNote.md`.
|
||||||
|
- Mark uncertain claims as `확인 필요` instead of presenting them as facts.
|
||||||
|
- Do not write final prose in `final/`. Your primary output is `docs/ResearchNote.md` and concise research notes for the parent agent.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: doc-reviewer
|
||||||
|
description: Reviews Markdown documents for PRD alignment, evidence quality, structure, and feedback coverage.
|
||||||
|
kind: local
|
||||||
|
tools:
|
||||||
|
- read_file
|
||||||
|
- read_many_files
|
||||||
|
- grep_search
|
||||||
|
- glob
|
||||||
|
model: inherit
|
||||||
|
temperature: 0.1
|
||||||
|
max_turns: 20
|
||||||
|
timeout_mins: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
# Document Reviewer
|
||||||
|
|
||||||
|
You are the review specialist for the Gemini CLI Markdown Document Harness.
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
- Review changed Markdown files against `GEMINI.md`, `docs/PRD.md`, `docs/ResearchNote.md`, `docs/DraftFeedback.md`, `docs/FinalFeedback.md`, and `docs/UI_GUIDE.md`.
|
||||||
|
- Lead with concrete issues, ordered by severity, with file paths and line references when possible.
|
||||||
|
- Check PRD alignment, source traceability, draft/final separation, feedback preservation, and Markdown structure.
|
||||||
|
- Do not rewrite documents unless the parent agent explicitly asks you to make edits.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
name: evidence-checker
|
||||||
|
description: Checks whether factual claims in drafts and final documents are supported by docs/ResearchNote.md sources.
|
||||||
|
kind: local
|
||||||
|
tools:
|
||||||
|
- read_file
|
||||||
|
- read_many_files
|
||||||
|
- grep_search
|
||||||
|
- glob
|
||||||
|
model: inherit
|
||||||
|
temperature: 0.1
|
||||||
|
max_turns: 20
|
||||||
|
timeout_mins: 20
|
||||||
|
---
|
||||||
|
|
||||||
|
# Evidence Checker
|
||||||
|
|
||||||
|
You are the evidence checking specialist for the Gemini CLI Markdown Document Harness.
|
||||||
|
|
||||||
|
## Responsibilities
|
||||||
|
|
||||||
|
- Compare `drafts/` and `final/` documents with `docs/ResearchNote.md`.
|
||||||
|
- Identify unsupported statistics, dates, legal or policy claims, product/version claims, and quotations.
|
||||||
|
- Report missing, weak, stale, or conflicting evidence.
|
||||||
|
- Prefer concise claim-to-source mapping over broad style feedback.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
description = "Create review drafts under drafts/ from PRD and ResearchNote."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Use the document-harness Skill. Create all PRD deliverables under drafts/.
|
||||||
|
|
||||||
|
Drafts must stay inside PRD scope, answer the key questions, use the requested tone, and connect external factual claims to docs/ResearchNote.md. Mark weak or missing evidence instead of inventing support.
|
||||||
|
|
||||||
|
Use @doc-drafter when a focused drafting subagent is useful.
|
||||||
|
|
||||||
|
Additional user instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ResearchNote.md}
|
||||||
|
@{docs/DraftFeedback.md}
|
||||||
|
@{docs/UI_GUIDE.md}
|
||||||
|
"""
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
description = "Create final documents under final/ after draft feedback."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Use the document-harness Skill. Read docs/DraftFeedback.md and create final deliverables under final/.
|
||||||
|
|
||||||
|
If docs/DraftFeedback.md contains no actionable feedback or approval, mark the relevant phase step blocked instead of creating final documents. Do not overwrite drafts/. Preserve feedback files.
|
||||||
|
|
||||||
|
Additional user instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ResearchNote.md}
|
||||||
|
@{docs/DraftFeedback.md}
|
||||||
|
@{docs/FinalFeedback.md}
|
||||||
|
@{docs/UI_GUIDE.md}
|
||||||
|
"""
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
description = "Inspect docs/PRD.md and design or update a document harness phase."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Use the document-harness Skill.
|
||||||
|
|
||||||
|
Read the project context and determine whether docs/PRD.md is complete enough to start document work. If it is materially incomplete, explain the missing fields and stop. If it is complete enough, create or update an appropriate phase under phases/ using the template in .agents/skills/document-harness/references/phase-templates.md.
|
||||||
|
|
||||||
|
Additional user instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ARCHITECTURE.md}
|
||||||
|
@{docs/ADR.md}
|
||||||
|
@{docs/UI_GUIDE.md}
|
||||||
|
"""
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
description = "Research PRD keywords and update docs/ResearchNote.md."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Use the document-harness Skill. Research the topics required by docs/PRD.md and update docs/ResearchNote.md.
|
||||||
|
|
||||||
|
Prefer official, academic, government, institutional, or other primary sources. Record search date, search terms, source URLs, source quality notes, core findings, conflicts, unresolved questions, and intended document usage.
|
||||||
|
|
||||||
|
Use @doc-researcher when the task benefits from a focused research subagent.
|
||||||
|
|
||||||
|
Additional user instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ResearchNote.md}
|
||||||
|
@{docs/UI_GUIDE.md}
|
||||||
|
"""
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
description = "Review harness documents for PRD alignment, evidence, structure, and feedback coverage."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Use the document-review Skill. Review the current Markdown document harness outputs.
|
||||||
|
|
||||||
|
Lead with findings. Check PRD alignment, source traceability, heading structure, feedback preservation, draft/final separation, style quality, and validation readiness. Use @doc-reviewer or @evidence-checker if a focused subagent would improve the review.
|
||||||
|
|
||||||
|
Review target or extra instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ResearchNote.md}
|
||||||
|
@{docs/DraftFeedback.md}
|
||||||
|
@{docs/FinalFeedback.md}
|
||||||
|
@{docs/UI_GUIDE.md}
|
||||||
|
"""
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
description = "Summarize the current harness state and next required action."
|
||||||
|
|
||||||
|
prompt = """
|
||||||
|
Summarize the current Gemini CLI Markdown Document Harness state and identify the next required action.
|
||||||
|
|
||||||
|
Check PRD completeness, ResearchNote status, draft/final outputs, feedback files, and phase status files if present. Do not modify files unless explicitly requested.
|
||||||
|
|
||||||
|
Additional user instructions:
|
||||||
|
{{args}}
|
||||||
|
|
||||||
|
Required context:
|
||||||
|
@{GEMINI.md}
|
||||||
|
@{docs/PRD.md}
|
||||||
|
@{docs/ResearchNote.md}
|
||||||
|
@{docs/DraftFeedback.md}
|
||||||
|
@{docs/FinalFeedback.md}
|
||||||
|
@{docs/ARCHITECTURE.md}
|
||||||
|
"""
|
||||||
+6
-14
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Codex PreToolUse guard for obviously destructive shell commands."""
|
"""Gemini CLI BeforeTool hook for obviously destructive shell commands."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
@@ -31,35 +31,27 @@ def iter_strings(value: Any):
|
|||||||
yield from iter_strings(item)
|
yield from iter_strings(item)
|
||||||
|
|
||||||
|
|
||||||
def deny(reason: str) -> None:
|
def emit(payload: dict) -> None:
|
||||||
payload = {
|
|
||||||
"hookSpecificOutput": {
|
|
||||||
"permissionDecision": "deny",
|
|
||||||
"permissionDecisionReason": reason,
|
|
||||||
},
|
|
||||||
"decision": "block",
|
|
||||||
"reason": reason,
|
|
||||||
}
|
|
||||||
print(json.dumps(payload, ensure_ascii=False))
|
print(json.dumps(payload, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
raw = sys.stdin.read()
|
raw = sys.stdin.read()
|
||||||
haystack = raw
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = json.loads(raw) if raw.strip() else {}
|
data = json.loads(raw) if raw.strip() else {}
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
haystack = raw
|
||||||
if data:
|
if data:
|
||||||
haystack += "\n" + "\n".join(iter_strings(data))
|
haystack += "\n" + "\n".join(iter_strings(data.get("tool_input", data)))
|
||||||
|
|
||||||
for pattern, reason in DANGEROUS_PATTERNS:
|
for pattern, reason in DANGEROUS_PATTERNS:
|
||||||
if re.search(pattern, haystack, flags=re.IGNORECASE | re.DOTALL):
|
if re.search(pattern, haystack, flags=re.IGNORECASE | re.DOTALL):
|
||||||
deny(reason)
|
emit({"decision": "deny", "reason": reason, "suppressOutput": True})
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
emit({})
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Gemini CLI AfterAgent hook that requests a retry when validation fails."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def emit(payload: dict) -> None:
|
||||||
|
print(json.dumps(payload, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
try:
|
||||||
|
data = json.loads(raw) if raw.strip() else {}
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, "scripts/validate_docs.py"],
|
||||||
|
cwd=ROOT,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
emit({})
|
||||||
|
return 0
|
||||||
|
|
||||||
|
details = "\n".join(part for part in [result.stdout.strip(), result.stderr.strip()] if part)
|
||||||
|
reason = (
|
||||||
|
"Document harness validation failed. Continue the turn, fix the listed "
|
||||||
|
f"issues, and run `python scripts/validate_docs.py` again.\n\n{details}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if data.get("stop_hook_active"):
|
||||||
|
emit({"continue": False, "stopReason": reason, "suppressOutput": True})
|
||||||
|
else:
|
||||||
|
emit({"decision": "deny", "reason": reason, "suppressOutput": True})
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"context": {
|
||||||
|
"fileName": "GEMINI.md"
|
||||||
|
},
|
||||||
|
"skills": {
|
||||||
|
"enabled": true,
|
||||||
|
"disabled": []
|
||||||
|
},
|
||||||
|
"hooksConfig": {
|
||||||
|
"enabled": true,
|
||||||
|
"disabled": [],
|
||||||
|
"notifications": true
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"BeforeTool": [
|
||||||
|
{
|
||||||
|
"matcher": "run_shell_command",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"name": "pre-tool-guard",
|
||||||
|
"type": "command",
|
||||||
|
"command": "python .gemini/hooks/pre_tool_guard.py",
|
||||||
|
"timeout": 5000,
|
||||||
|
"description": "Block obviously destructive shell commands."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"AfterAgent": [
|
||||||
|
{
|
||||||
|
"matcher": "*",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"name": "validate-docs-after-agent",
|
||||||
|
"type": "command",
|
||||||
|
"command": "python .gemini/hooks/validate_docs_after_agent.py",
|
||||||
|
"timeout": 60000,
|
||||||
|
"description": "Run document harness validation after each agent response."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
# 프로젝트: Codex Markdown Document Harness Template
|
# 프로젝트: Gemini CLI Markdown Document Harness Template
|
||||||
|
|
||||||
## 목적
|
## 목적
|
||||||
이 템플릿은 Codex와 Harness Engineering 방식을 이용해 사용자의 목표에 맞는 Markdown 문서를 단계적으로 작성하기 위한 작업 환경이다.
|
이 템플릿은 Gemini CLI와 Harness Engineering 방식을 이용해 사용자의 목표에 맞는 Markdown 문서를 단계적으로 작성하기 위한 작업 환경이다.
|
||||||
|
|
||||||
사용자는 `docs/PRD.md`에 문서의 목적, 개요, 대상 독자, 중요 키워드, 참고 자료를 입력한다. 이후 Codex는 이 정보를 기준으로 작성 규칙을 구체화하고, 조사 노트, 초안, 피드백 반영본, 최종 문서를 순차적으로 만든다.
|
사용자는 `docs/PRD.md`에 문서의 목적, 개요, 대상 독자, 중요 키워드, 참고 자료를 입력한다. 이후 Gemini CLI는 이 정보를 기준으로 작성 규칙을 구체화하고, 조사 노트, 초안, 피드백 반영본, 최종 문서를 순차적으로 만든다.
|
||||||
|
|
||||||
## Codex 구성
|
## Gemini CLI 구성
|
||||||
- `AGENTS.md`: Codex가 항상 참고하는 프로젝트 규칙.
|
- `GEMINI.md`: Gemini CLI가 읽는 프로젝트 규칙.
|
||||||
- `.agents/skills/document-harness/`: 문서 작성 Harness의 단계별 실행 절차.
|
- `.agents/skills/document-harness/`: 문서 작성 Harness의 단계별 실행 절차.
|
||||||
- `.agents/skills/document-review/`: 문서 변경 사항 리뷰 절차.
|
- `.agents/skills/document-review/`: 문서 변경 사항 리뷰 절차.
|
||||||
- `.codex/agents/`: 조사, 초안, 리뷰에 특화된 Codex custom agents.
|
- `.gemini/settings.json`: context, skills, hooks 설정.
|
||||||
- `.codex/hooks.json`: 문서 검증과 위험 명령 방지를 위한 lifecycle hooks.
|
- `.gemini/commands/`: Harness workflow용 custom slash commands.
|
||||||
- `.codex/config.toml`: hooks, multi-agent, live web search 등 이 템플릿에서 권장하는 Codex 기능 설정.
|
- `.gemini/agents/`: 조사, 초안, 리뷰에 특화된 Gemini CLI subagents.
|
||||||
|
- `.gemini/hooks/`: 문서 검증과 위험 명령 방지를 위한 lifecycle hook scripts.
|
||||||
|
|
||||||
## 기본 산출물
|
## 기본 산출물
|
||||||
- `docs/PRD.md`: 사용자가 작성하는 문서 요구사항의 원천.
|
- `docs/PRD.md`: 사용자가 작성하는 문서 요구사항의 원천.
|
||||||
@@ -32,20 +33,20 @@
|
|||||||
- 문서 구조는 제목 계층을 유지한다. `#`는 문서 제목에만 사용하고, 본문 구조는 `##`, `###`를 사용한다.
|
- 문서 구조는 제목 계층을 유지한다. `#`는 문서 제목에만 사용하고, 본문 구조는 `##`, `###`를 사용한다.
|
||||||
- 사용자의 피드백은 삭제하지 말고 별도 피드백 문서에 보존한다.
|
- 사용자의 피드백은 삭제하지 말고 별도 피드백 문서에 보존한다.
|
||||||
|
|
||||||
## Codex 작업 규칙
|
## Gemini CLI 작업 규칙
|
||||||
- 반복 가능한 절차는 `.agents/skills/`의 Skill에 둔다. `AGENTS.md`에는 지속적으로 적용할 짧은 규칙만 유지한다.
|
- 반복 가능한 절차는 `.agents/skills/`의 Skill에 둔다. `GEMINI.md`에는 지속적으로 적용할 짧은 규칙만 유지한다.
|
||||||
- 문서 작성 Harness를 실행하거나 설계할 때는 `$document-harness` Skill을 우선 사용한다.
|
- 문서 작성 Harness를 실행하거나 설계할 때는 `document-harness` Skill을 우선 사용한다.
|
||||||
- 문서 변경 사항을 검토할 때는 `$document-review` Skill을 사용한다.
|
- 문서 변경 사항을 검토할 때는 `document-review` Skill을 사용한다.
|
||||||
- 병렬 조사나 독립 리뷰가 필요한 경우 `.codex/agents/`의 custom agents를 명시적으로 선택한다.
|
- 병렬 조사나 독립 리뷰가 필요한 경우 `.gemini/agents/`의 subagent를 명시적으로 선택한다.
|
||||||
- `scripts/execute.py`가 step 실행 후 git commit을 처리하므로, step을 수행하는 Codex 세션은 직접 commit하지 않는다.
|
- `scripts/execute.py`가 step 실행 후 git commit을 처리하므로, step을 수행하는 Gemini CLI 세션은 직접 commit하지 않는다.
|
||||||
|
|
||||||
## 권장 워크플로우
|
## 권장 워크플로우
|
||||||
1. 사용자가 `docs/PRD.md`를 채운다.
|
1. 사용자가 `docs/PRD.md`를 채운다.
|
||||||
2. Codex가 PRD를 읽고 `AGENTS.md`의 프로젝트별 작성 규칙을 구체화한다.
|
2. Gemini CLI가 PRD를 읽고 `GEMINI.md`의 프로젝트별 작성 규칙을 구체화한다.
|
||||||
3. Codex 또는 Codex subagents가 웹 검색을 수행하고 `docs/ResearchNote.md`를 작성한다.
|
3. Gemini CLI 또는 subagents가 웹 검색을 수행하고 `docs/ResearchNote.md`를 작성한다.
|
||||||
4. Codex가 `drafts/`에 초안을 만들고 사용자 검토를 요청한다.
|
4. Gemini CLI가 `drafts/`에 초안을 만들고 사용자 검토를 요청한다.
|
||||||
5. 사용자가 `docs/DraftFeedback.md`에 피드백을 남긴다.
|
5. 사용자가 `docs/DraftFeedback.md`에 피드백을 남긴다.
|
||||||
6. Codex가 피드백을 반영해 `final/`에 최종 문서를 작성한다.
|
6. Gemini CLI가 피드백을 반영해 `final/`에 최종 문서를 작성한다.
|
||||||
7. 사용자가 `docs/FinalFeedback.md`에 최종 피드백 또는 승인 여부를 남긴다.
|
7. 사용자가 `docs/FinalFeedback.md`에 최종 피드백 또는 승인 여부를 남긴다.
|
||||||
|
|
||||||
## 명령어
|
## 명령어
|
||||||
+40
-47
@@ -1,8 +1,8 @@
|
|||||||
# Codex Markdown Document Harness Template
|
# Gemini CLI Markdown Document Harness Template
|
||||||
|
|
||||||
Codex 환경에서 Harness Engineering 방식으로 Markdown 문서를 단계적으로 작성하기 위한 템플릿입니다.
|
Gemini CLI 환경에서 Harness Engineering 방식으로 Markdown 문서를 단계적으로 작성하기 위한 템플릿입니다.
|
||||||
|
|
||||||
사용자는 `docs/PRD.md`에 만들고 싶은 문서의 목적, 대상 독자, 개요, 중요 키워드, 조사 요구사항을 작성합니다. 이후 Codex는 PRD를 기준으로 작성 규칙을 구체화하고, 웹 조사, 조사 노트, 초안, 사용자 피드백, 최종 문서를 순서대로 만들어 갑니다.
|
사용자는 `docs/PRD.md`에 만들고 싶은 문서의 목적, 대상 독자, 개요, 중요 키워드, 조사 요구사항을 작성합니다. 이후 Gemini CLI는 PRD를 기준으로 작성 규칙을 구체화하고, 웹 조사, 조사 노트, 초안, 사용자 피드백, 최종 문서를 순서대로 만들어 갑니다.
|
||||||
|
|
||||||
## 핵심 아이디어
|
## 핵심 아이디어
|
||||||
|
|
||||||
@@ -20,20 +20,20 @@ PRD 작성
|
|||||||
|
|
||||||
목표는 빠른 초안 작성보다 사용자의 의도, 출처, 피드백, 최종 산출물을 분리해 관리하는 것입니다.
|
목표는 빠른 초안 작성보다 사용자의 의도, 출처, 피드백, 최종 산출물을 분리해 관리하는 것입니다.
|
||||||
|
|
||||||
## Codex 구성
|
## Gemini CLI 구성
|
||||||
|
|
||||||
```text
|
```text
|
||||||
.
|
.
|
||||||
├── AGENTS.md # Codex가 읽는 프로젝트 기본 규칙
|
├── GEMINI.md # Gemini CLI가 읽는 프로젝트 기본 규칙
|
||||||
├── .agents/
|
├── .agents/
|
||||||
│ └── skills/
|
│ └── skills/
|
||||||
│ ├── document-harness/ # 단계적 문서 작성 Skill
|
│ ├── document-harness/ # 단계적 문서 작성 Skill
|
||||||
│ └── document-review/ # 문서 리뷰 Skill
|
│ └── document-review/ # 문서 리뷰 Skill
|
||||||
├── .codex/
|
├── .gemini/
|
||||||
│ ├── config.toml # hooks, multi-agent, live web search 설정
|
│ ├── settings.json # context, skills, hooks 설정
|
||||||
│ ├── hooks.json # Stop/PreToolUse hook 연결
|
│ ├── commands/ # Harness custom slash commands
|
||||||
│ ├── hooks/ # hook 실행 스크립트
|
│ ├── hooks/ # hook 실행 스크립트
|
||||||
│ └── agents/ # 조사, 초안, 리뷰, 근거 점검 custom agents
|
│ └── agents/ # 조사, 초안, 리뷰, 근거 점검 subagents
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── PRD.md # 사용자가 채우는 문서 요구사항
|
│ ├── PRD.md # 사용자가 채우는 문서 요구사항
|
||||||
│ ├── ResearchNote.md # 조사 결과와 출처 장부
|
│ ├── ResearchNote.md # 조사 결과와 출처 장부
|
||||||
@@ -46,7 +46,7 @@ PRD 작성
|
|||||||
├── final/ # 최종 문서
|
├── final/ # 최종 문서
|
||||||
├── phases/ # 단계 실행 계획과 상태 파일
|
├── phases/ # 단계 실행 계획과 상태 파일
|
||||||
└── scripts/
|
└── scripts/
|
||||||
├── execute.py # codex exec 기반 step 실행기
|
├── execute.py # Gemini CLI headless 기반 step 순차 실행기
|
||||||
├── validate_docs.py # 템플릿 구조 검증
|
├── validate_docs.py # 템플릿 구조 검증
|
||||||
└── test_execute.py # 실행기 테스트
|
└── test_execute.py # 실행기 테스트
|
||||||
```
|
```
|
||||||
@@ -76,18 +76,21 @@ git init
|
|||||||
- 조사 요구사항
|
- 조사 요구사항
|
||||||
- 승인 기준
|
- 승인 기준
|
||||||
|
|
||||||
3. Codex에서 Harness Skill을 사용합니다.
|
3. Gemini CLI에서 Harness Skill 또는 custom command를 사용합니다.
|
||||||
|
|
||||||
예시 프롬프트:
|
예시 프롬프트:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-harness를 사용해서 docs/PRD.md를 읽고 문서 작성 phase를 설계해 주세요.
|
document-harness Skill을 사용해서 docs/PRD.md를 읽고 문서 작성 phase를 설계해 주세요.
|
||||||
```
|
```
|
||||||
|
|
||||||
또는 바로 다음처럼 요청할 수 있습니다.
|
또는 custom command를 사용할 수 있습니다.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-harness를 사용해서 docs/PRD.md 기준으로 작성 규칙 구체화, ResearchNote 작성, 초안 작성 단계까지 진행해 주세요.
|
/harness:plan
|
||||||
|
/harness:research
|
||||||
|
/harness:draft
|
||||||
|
/harness:review
|
||||||
```
|
```
|
||||||
|
|
||||||
4. 생성된 초안을 검토합니다.
|
4. 생성된 초안을 검토합니다.
|
||||||
@@ -100,7 +103,7 @@ $document-harness를 사용해서 docs/PRD.md 기준으로 작성 규칙 구체
|
|||||||
|
|
||||||
## 자동 실행 방식
|
## 자동 실행 방식
|
||||||
|
|
||||||
Codex가 `phases/{task-name}/` 아래에 step 파일을 만든 뒤, 실행기는 각 step을 `codex exec`로 순차 실행합니다.
|
Gemini CLI가 `phases/{task-name}/` 아래에 step 파일을 만든 뒤, 실행기는 각 step을 Gemini CLI headless mode로 순차 실행합니다.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python scripts/execute.py <task-name>
|
python scripts/execute.py <task-name>
|
||||||
@@ -115,7 +118,7 @@ python scripts/execute.py <task-name> --push
|
|||||||
실행기가 처리하는 일:
|
실행기가 처리하는 일:
|
||||||
|
|
||||||
- `feat-{task-name}` 브랜치 생성 또는 checkout
|
- `feat-{task-name}` 브랜치 생성 또는 checkout
|
||||||
- `AGENTS.md`와 `docs/*.md`를 매 step 프롬프트에 주입
|
- `GEMINI.md`와 `docs/*.md`를 매 step 프롬프트에 주입
|
||||||
- 완료된 step의 `summary`를 다음 step에 전달
|
- 완료된 step의 `summary`를 다음 step에 전달
|
||||||
- 실패 시 최대 3회 재시도
|
- 실패 시 최대 3회 재시도
|
||||||
- step 상태를 `completed`, `blocked`, `error`로 관리
|
- step 상태를 `completed`, `blocked`, `error`로 관리
|
||||||
@@ -139,9 +142,9 @@ docs/FinalFeedback.md
|
|||||||
|
|
||||||
피드백을 작성한 뒤 해당 step의 상태를 `pending`으로 되돌리고 다시 실행하면 다음 단계가 진행됩니다.
|
피드백을 작성한 뒤 해당 step의 상태를 `pending`으로 되돌리고 다시 실행하면 다음 단계가 진행됩니다.
|
||||||
|
|
||||||
## Codex Skills
|
## Gemini CLI Skills
|
||||||
|
|
||||||
이 템플릿은 repo 공유 Skill을 사용합니다.
|
이 템플릿은 repo 공유 Skill을 사용합니다. Gemini CLI는 `.agents/skills/` 경로를 workspace skill alias로 인식합니다.
|
||||||
|
|
||||||
`document-harness`:
|
`document-harness`:
|
||||||
|
|
||||||
@@ -160,40 +163,31 @@ docs/FinalFeedback.md
|
|||||||
- 피드백 반영 확인
|
- 피드백 반영 확인
|
||||||
- 문체와 Markdown 구조 검토
|
- 문체와 Markdown 구조 검토
|
||||||
|
|
||||||
Codex에서 명시적으로 호출할 수 있습니다.
|
## Gemini CLI Subagents
|
||||||
|
|
||||||
```text
|
`.gemini/agents/`에는 문서 작성에 특화된 subagent 역할이 정의되어 있습니다.
|
||||||
$document-harness
|
|
||||||
$document-review
|
|
||||||
```
|
|
||||||
|
|
||||||
## Codex Custom Agents
|
|
||||||
|
|
||||||
`.codex/agents/`에는 문서 작성에 특화된 역할이 정의되어 있습니다.
|
|
||||||
|
|
||||||
| Agent | 역할 |
|
| Agent | 역할 |
|
||||||
|-------|------|
|
|-------|------|
|
||||||
| `doc_researcher` | PRD 키워드 조사, 출처 수집, `docs/ResearchNote.md` 작성 |
|
| `doc-researcher` | PRD 키워드 조사, 출처 수집, `docs/ResearchNote.md` 작성 |
|
||||||
| `doc_drafter` | ResearchNote와 PRD를 바탕으로 `drafts/` 초안 작성 |
|
| `doc-drafter` | ResearchNote와 PRD를 바탕으로 `drafts/` 초안 작성 |
|
||||||
| `doc_reviewer` | PRD 정합성, 구조, 피드백 반영 여부 리뷰 |
|
| `doc-reviewer` | PRD 정합성, 구조, 피드백 반영 여부 리뷰 |
|
||||||
| `evidence_checker` | 문서 주장과 ResearchNote 출처 연결 확인 |
|
| `evidence-checker` | 문서 주장과 ResearchNote 출처 연결 확인 |
|
||||||
|
|
||||||
Codex는 subagent를 항상 자동으로 생성하지 않습니다. 병렬 조사나 독립 리뷰가 필요하면 프롬프트에서 명시적으로 요청하세요.
|
명시적으로 subagent를 호출하려면 Gemini CLI에서 다음처럼 요청할 수 있습니다.
|
||||||
|
|
||||||
예시:
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
doc_researcher와 evidence_checker 역할을 사용해 핵심 키워드를 병렬 조사하고 docs/ResearchNote.md를 정리해 주세요.
|
@doc-researcher docs/PRD.md의 핵심 키워드를 조사하고 docs/ResearchNote.md를 정리해 주세요.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Hooks
|
## Hooks
|
||||||
|
|
||||||
`.codex/hooks.json`은 두 가지 기본 hook을 연결합니다.
|
`.gemini/settings.json`은 두 가지 기본 hook을 연결합니다.
|
||||||
|
|
||||||
- `PreToolUse`: 위험한 shell 명령을 차단합니다.
|
- `BeforeTool`: 위험한 shell 명령을 차단합니다.
|
||||||
- `Stop`: 응답 종료 시 `python scripts/validate_docs.py`를 실행해 템플릿 구조를 검증합니다.
|
- `AfterAgent`: 응답 종료 후 `python scripts/validate_docs.py`를 실행해 템플릿 구조를 검증합니다.
|
||||||
|
|
||||||
검증 실패 시 Codex가 문제를 고치도록 이어서 작업하게 만드는 용도입니다.
|
검증 실패 시 `AfterAgent` hook은 Gemini CLI에 재시도 피드백을 전달합니다.
|
||||||
|
|
||||||
## 검증
|
## 검증
|
||||||
|
|
||||||
@@ -213,7 +207,6 @@ python -m pytest scripts/test_execute.py
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
Document harness validation passed.
|
Document harness validation passed.
|
||||||
51 passed
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 문서 작성 규칙
|
## 문서 작성 규칙
|
||||||
@@ -230,30 +223,30 @@ Document harness validation passed.
|
|||||||
PRD 검토:
|
PRD 검토:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-harness를 사용해 docs/PRD.md가 문서 작성을 시작하기에 충분한지 검토해 주세요.
|
document-harness Skill을 사용해 docs/PRD.md가 문서 작성을 시작하기에 충분한지 검토해 주세요.
|
||||||
```
|
```
|
||||||
|
|
||||||
조사 노트 작성:
|
조사 노트 작성:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-harness를 사용해 docs/PRD.md의 중요 키워드를 웹 조사하고 docs/ResearchNote.md를 작성해 주세요.
|
/harness:research
|
||||||
```
|
```
|
||||||
|
|
||||||
초안 작성:
|
초안 작성:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-harness를 사용해 docs/PRD.md와 docs/ResearchNote.md를 바탕으로 drafts/에 초안을 작성해 주세요.
|
/harness:draft
|
||||||
```
|
```
|
||||||
|
|
||||||
문서 리뷰:
|
문서 리뷰:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
$document-review를 사용해 drafts/와 final/의 변경 사항을 검토해 주세요.
|
/harness:review
|
||||||
```
|
```
|
||||||
|
|
||||||
## 주의사항
|
## 주의사항
|
||||||
|
|
||||||
- 자동 실행기는 git 저장소를 전제로 합니다.
|
- 자동 실행기는 git 저장소와 Gemini CLI 설치를 전제로 합니다.
|
||||||
- 최신 정보가 중요한 문서는 `docs/ResearchNote.md`에 조사 일시와 기준일을 남겨야 합니다.
|
- 최신 정보가 중요한 문서는 `docs/ResearchNote.md`에 조사 일시와 기준일을 남겨야 합니다.
|
||||||
- `AGENTS.md`에는 지속적으로 적용할 규칙만 두고, 긴 절차는 Skill에 둡니다.
|
- `GEMINI.md`에는 지속적으로 적용할 규칙만 두고, 긴 절차는 Skill에 둡니다.
|
||||||
- Claude Code용 `.claude/` 구조는 사용하지 않습니다. 이 템플릿은 Codex의 `AGENTS.md`, Skill, hook, custom agent 구조를 기준으로 합니다.
|
- 이 템플릿은 Gemini CLI의 `GEMINI.md`, Skill, custom command, hook, subagent 구조를 기준으로 합니다.
|
||||||
|
|||||||
@@ -40,9 +40,9 @@
|
|||||||
|
|
||||||
**트레이드오프**: 파일 수가 늘어난다. 대신 리뷰와 회귀 확인이 쉬워진다.
|
**트레이드오프**: 파일 수가 늘어난다. 대신 리뷰와 회귀 확인이 쉬워진다.
|
||||||
|
|
||||||
### ADR-006: Codex의 AGENTS/Skill/Hook 구조로 이전
|
### ADR-006: Gemini CLI의 context/Skill/Command/Hook/Subagent 구조 사용
|
||||||
**결정**: Claude 전용 `CLAUDE.md`, `.claude/commands`, `.claude/settings.json` 구조를 Codex의 `AGENTS.md`, `.agents/skills`, `.codex/hooks.json`, `.codex/agents` 구조로 이전한다.
|
**결정**: 이 템플릿은 Gemini CLI의 `GEMINI.md`, `.agents/skills`, `.gemini/settings.json`, `.gemini/commands`, `.gemini/hooks`, `.gemini/agents` 구조를 기준으로 한다.
|
||||||
|
|
||||||
**이유**: Codex는 프로젝트 지침을 `AGENTS.md`로 읽고, 재사용 가능한 워크플로우를 Skill로 관리하며, lifecycle hook과 custom agent를 별도 디렉토리에서 구성한다. 템플릿의 의도를 Codex의 네이티브 구조에 맞추면 실행 맥락과 재사용성이 좋아진다.
|
**이유**: Gemini CLI는 프로젝트 지침을 `GEMINI.md`로 읽고, `SKILL.md` 기반 Agent Skills를 on-demand로 활성화하며, custom slash command와 lifecycle hook, local subagent를 `.gemini/` 아래에서 구성한다. 템플릿의 의도를 Gemini CLI 네이티브 구조에 맞추면 실행 맥락과 재사용성이 좋아진다.
|
||||||
|
|
||||||
**트레이드오프**: Claude Code와의 직접 호환성은 낮아진다. 대신 Codex CLI, Skill, custom agent, hook을 기준으로 한 문서 작성 자동화가 명확해진다.
|
**트레이드오프**: 다른 CLI 전용 구성과 직접 호환되지 않는다. 대신 Gemini CLI의 headless execution, custom commands, hooks, subagents를 기준으로 문서 작성 자동화가 명확해진다.
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
## 디렉토리 구조
|
## 디렉토리 구조
|
||||||
```text
|
```text
|
||||||
.
|
.
|
||||||
├── AGENTS.md # Codex가 읽는 프로젝트별 문서 작성 규칙
|
├── GEMINI.md # Gemini CLI가 읽는 프로젝트별 문서 작성 규칙
|
||||||
├── .agents/
|
├── .agents/
|
||||||
│ └── skills/
|
│ └── skills/
|
||||||
│ ├── document-harness/ # 단계적 문서 작성 Skill
|
│ ├── document-harness/ # 단계적 문서 작성 Skill
|
||||||
│ └── document-review/ # 문서 리뷰 Skill
|
│ └── document-review/ # 문서 리뷰 Skill
|
||||||
├── .codex/
|
├── .gemini/
|
||||||
│ ├── config.toml # Codex 기능, live web search, agent 한도 설정
|
│ ├── settings.json # context, skills, hooks 설정
|
||||||
│ ├── hooks.json # Stop/PreToolUse hook 설정
|
│ ├── commands/ # Harness custom slash commands
|
||||||
│ ├── hooks/ # hook 실행 스크립트
|
│ ├── hooks/ # hook 실행 스크립트
|
||||||
│ └── agents/ # 조사/초안/리뷰 custom agents
|
│ └── agents/ # 조사/초안/리뷰 subagents
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── PRD.md # 사용자 요구사항 원천
|
│ ├── PRD.md # 사용자 요구사항 원천
|
||||||
│ ├── ResearchNote.md # 조사 노트와 출처 장부
|
│ ├── ResearchNote.md # 조사 노트와 출처 장부
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
├── final/ # 피드백 반영 최종 산출물
|
├── final/ # 피드백 반영 최종 산출물
|
||||||
├── phases/ # Harness task/step 계획과 상태
|
├── phases/ # Harness task/step 계획과 상태
|
||||||
└── scripts/
|
└── scripts/
|
||||||
├── execute.py # codex exec 기반 step 순차 실행기
|
├── execute.py # Gemini CLI headless 기반 step 순차 실행기
|
||||||
├── validate_docs.py # 문서 템플릿 기본 검증
|
├── validate_docs.py # 문서 템플릿 기본 검증
|
||||||
└── test_execute.py # execute.py 안전망 테스트
|
└── test_execute.py # execute.py 안전망 테스트
|
||||||
```
|
```
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
```text
|
```text
|
||||||
사용자 입력
|
사용자 입력
|
||||||
-> docs/PRD.md
|
-> docs/PRD.md
|
||||||
-> AGENTS.md 작성 규칙 구체화
|
-> GEMINI.md 작성 규칙 구체화
|
||||||
-> Codex/custom agents 웹 검색 및 출처 검증
|
-> Gemini CLI/subagents 웹 검색 및 출처 검증
|
||||||
-> docs/ResearchNote.md
|
-> docs/ResearchNote.md
|
||||||
-> drafts/ 초안 작성
|
-> drafts/ 초안 작성
|
||||||
-> docs/DraftFeedback.md 사용자 피드백
|
-> docs/DraftFeedback.md 사용자 피드백
|
||||||
@@ -46,19 +46,21 @@
|
|||||||
## Step 설계 패턴
|
## Step 설계 패턴
|
||||||
권장 phase는 아래 순서를 따른다.
|
권장 phase는 아래 순서를 따른다.
|
||||||
|
|
||||||
1. `rule-synthesis`: `docs/PRD.md`를 읽고 `AGENTS.md`의 문서 작성 규칙을 프로젝트에 맞게 구체화한다.
|
1. `rule-synthesis`: `docs/PRD.md`를 읽고 `GEMINI.md`의 문서 작성 규칙을 프로젝트에 맞게 구체화한다.
|
||||||
2. `research-note`: 웹 검색과 사용자가 제공한 자료를 바탕으로 `docs/ResearchNote.md`를 작성한다. 필요하면 `doc_researcher` agent를 사용한다.
|
2. `research-note`: 웹 검색과 사용자가 제공한 자료를 바탕으로 `docs/ResearchNote.md`를 작성한다. 필요하면 `doc-researcher` subagent를 사용한다.
|
||||||
3. `draft-documents`: `drafts/`에 사용자 검토용 초안을 작성한다.
|
3. `draft-documents`: `drafts/`에 사용자 검토용 초안을 작성한다.
|
||||||
4. `draft-feedback-gate`: `docs/DraftFeedback.md`가 비어 있으면 `blocked`로 멈추고 사용자 검토를 요청한다.
|
4. `draft-feedback-gate`: `docs/DraftFeedback.md`가 비어 있으면 `blocked`로 멈추고 사용자 검토를 요청한다.
|
||||||
5. `final-documents`: 피드백을 반영해 `final/`에 최종 문서를 작성한다.
|
5. `final-documents`: 피드백을 반영해 `final/`에 최종 문서를 작성한다.
|
||||||
6. `final-feedback-gate`: `docs/FinalFeedback.md`에 승인 또는 추가 수정 요청이 없으면 `blocked`로 멈춘다.
|
6. `final-feedback-gate`: `docs/FinalFeedback.md`에 승인 또는 추가 수정 요청이 없으면 `blocked`로 멈춘다.
|
||||||
|
|
||||||
## Codex 구성 책임
|
## Gemini CLI 구성 책임
|
||||||
- `AGENTS.md`는 Codex가 매 작업에서 읽는 짧고 지속적인 규칙을 담는다.
|
- `GEMINI.md`는 Gemini CLI가 매 작업에서 읽는 짧고 지속적인 규칙을 담는다.
|
||||||
- `.agents/skills/document-harness/`는 phase 생성, research, draft, feedback gate, final 작성 절차를 담는다.
|
- `.agents/skills/document-harness/`는 phase 생성, research, draft, feedback gate, final 작성 절차를 담는다.
|
||||||
- `.agents/skills/document-review/`는 변경된 Markdown 문서의 리뷰 체크리스트를 담는다.
|
- `.agents/skills/document-review/`는 변경된 Markdown 문서의 리뷰 체크리스트를 담는다.
|
||||||
- `.codex/agents/`는 조사, 초안 작성, 리뷰, 근거 점검 역할을 분리한다.
|
- `.gemini/commands/`는 반복 작업을 호출하기 위한 project-local slash command를 담는다.
|
||||||
- `.codex/hooks.json`은 위험 명령 차단과 Stop 시점 문서 검증을 연결한다.
|
- `.gemini/agents/`는 조사, 초안 작성, 리뷰, 근거 점검 역할을 분리한다.
|
||||||
|
- `.gemini/settings.json`은 context, skills, hook 실행 설정을 담는다.
|
||||||
|
- `.gemini/hooks/`는 위험 명령 차단과 AfterAgent 시점 문서 검증을 연결한다.
|
||||||
|
|
||||||
## 상태 관리
|
## 상태 관리
|
||||||
- `pending`: 아직 실행되지 않은 step.
|
- `pending`: 아직 실행되지 않은 step.
|
||||||
@@ -67,7 +69,7 @@
|
|||||||
- `error`: 자동 수정 3회 후에도 실패한 상태.
|
- `error`: 자동 수정 3회 후에도 실패한 상태.
|
||||||
|
|
||||||
## 파일 책임
|
## 파일 책임
|
||||||
- `docs/PRD.md`는 사용자의 의도와 요구사항을 보존한다. Codex가 임의로 요구사항을 바꾸지 않는다.
|
- `docs/PRD.md`는 사용자의 의도와 요구사항을 보존한다. Gemini CLI가 임의로 요구사항을 바꾸지 않는다.
|
||||||
- `docs/ResearchNote.md`는 사실 검증의 근거 장부다. 최종 문서의 외부 주장은 이 파일의 출처와 연결되어야 한다.
|
- `docs/ResearchNote.md`는 사실 검증의 근거 장부다. 최종 문서의 외부 주장은 이 파일의 출처와 연결되어야 한다.
|
||||||
- `drafts/`는 논의용이다. 문장이 거칠 수 있지만 구조와 근거는 검토 가능해야 한다.
|
- `drafts/`는 논의용이다. 문장이 거칠 수 있지만 구조와 근거는 검토 가능해야 한다.
|
||||||
- `final/`은 납품용이다. 사용자 피드백, 출처, 스타일 기준을 반영해야 한다.
|
- `final/`은 납품용이다. 사용자 피드백, 출처, 스타일 기준을 반영해야 한다.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# PRD: {문서 프로젝트명}
|
# PRD: {문서 프로젝트명}
|
||||||
|
|
||||||
이 파일은 Codex 문서 작성 Harness의 출발점이다. 사용자는 아래 항목을 가능한 한 구체적으로 채운다. Codex는 이 문서를 기준으로 작성 규칙, 조사 계획, 초안, 최종 문서를 만든다.
|
이 파일은 Gemini CLI 문서 작성 Harness의 출발점이다. 사용자는 아래 항목을 가능한 한 구체적으로 채운다. Gemini CLI는 이 문서를 기준으로 작성 규칙, 조사 계획, 초안, 최종 문서를 만든다.
|
||||||
|
|
||||||
## 문서 목적
|
## 문서 목적
|
||||||
{이 문서가 해결하려는 문제, 설득하려는 주장, 설명하려는 주제, 또는 독자가 얻어야 할 결과를 한 문단으로 작성}
|
{이 문서가 해결하려는 문제, 설득하려는 주장, 설명하려는 주제, 또는 독자가 얻어야 할 결과를 한 문단으로 작성}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
| 목차와 본문 제목 불일치 | 리뷰와 유지보수가 어려워진다 |
|
| 목차와 본문 제목 불일치 | 리뷰와 유지보수가 어려워진다 |
|
||||||
| PRD에 없는 독자나 목표 추가 | 사용자 의도를 벗어난다 |
|
| PRD에 없는 독자나 목표 추가 | 사용자 의도를 벗어난다 |
|
||||||
| ResearchNote에 없는 외부 주장 단정 | 출처 추적이 끊긴다 |
|
| ResearchNote에 없는 외부 주장 단정 | 출처 추적이 끊긴다 |
|
||||||
| AGENTS.md와 Skill 지침 불일치 | Codex 실행 맥락이 흔들린다 |
|
| GEMINI.md와 Skill 지침 불일치 | Gemini CLI 실행 맥락이 흔들린다 |
|
||||||
|
|
||||||
## 구조
|
## 구조
|
||||||
- 문서 제목은 `#` 하나만 사용한다.
|
- 문서 제목은 `#` 하나만 사용한다.
|
||||||
@@ -51,4 +51,4 @@
|
|||||||
- 초안 피드백이 반영되었는가?
|
- 초안 피드백이 반영되었는가?
|
||||||
- 문서 제목, 섹션 제목, 파일명이 산출물 목적과 맞는가?
|
- 문서 제목, 섹션 제목, 파일명이 산출물 목적과 맞는가?
|
||||||
- 최종 문서는 `final/` 아래에 있는가?
|
- 최종 문서는 `final/` 아래에 있는가?
|
||||||
- Codex Skill, agent, hook 지침과 충돌하지 않는가?
|
- Gemini CLI Skill, subagent, command, hook 지침과 충돌하지 않는가?
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Codex Harness Step Executor — phase 내 step을 순차 실행하고 자가 교정한다.
|
Gemini Harness Step Executor — phase 내 step을 순차 실행하고 자가 교정한다.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python3 scripts/execute.py <phase-dir> [--push]
|
python scripts/execute.py <phase-dir> [--push]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import contextlib
|
import contextlib
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
@@ -51,7 +50,7 @@ def progress_indicator(label: str):
|
|||||||
|
|
||||||
|
|
||||||
class StepExecutor:
|
class StepExecutor:
|
||||||
"""Phase 디렉토리 안의 step들을 Codex로 순차 실행하는 하네스."""
|
"""Phase 디렉토리 안의 step들을 Gemini CLI로 순차 실행하는 하네스."""
|
||||||
|
|
||||||
MAX_RETRIES = 3
|
MAX_RETRIES = 3
|
||||||
FEAT_MSG = "feat({phase}): step {num} — {name}"
|
FEAT_MSG = "feat({phase}): step {num} — {name}"
|
||||||
@@ -115,7 +114,7 @@ class StepExecutor:
|
|||||||
|
|
||||||
r = self._run_git("rev-parse", "--abbrev-ref", "HEAD")
|
r = self._run_git("rev-parse", "--abbrev-ref", "HEAD")
|
||||||
if r.returncode != 0:
|
if r.returncode != 0:
|
||||||
print(f" ERROR: git을 사용할 수 없거나 git repo가 아닙니다.")
|
print(" ERROR: git을 사용할 수 없거나 git repo가 아닙니다.")
|
||||||
print(f" {r.stderr.strip()}")
|
print(f" {r.stderr.strip()}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@@ -128,7 +127,7 @@ class StepExecutor:
|
|||||||
if r.returncode != 0:
|
if r.returncode != 0:
|
||||||
print(f" ERROR: 브랜치 '{branch}' checkout 실패.")
|
print(f" ERROR: 브랜치 '{branch}' checkout 실패.")
|
||||||
print(f" {r.stderr.strip()}")
|
print(f" {r.stderr.strip()}")
|
||||||
print(f" Hint: 변경사항을 stash하거나 commit한 후 다시 시도하세요.")
|
print(" Hint: 변경사항을 stash하거나 commit한 후 다시 시도하세요.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print(f" Branch: {branch}")
|
print(f" Branch: {branch}")
|
||||||
@@ -176,9 +175,9 @@ class StepExecutor:
|
|||||||
|
|
||||||
def _load_guardrails(self) -> str:
|
def _load_guardrails(self) -> str:
|
||||||
sections = []
|
sections = []
|
||||||
agents_md = ROOT / "AGENTS.md"
|
gemini_md = ROOT / "GEMINI.md"
|
||||||
if agents_md.exists():
|
if gemini_md.exists():
|
||||||
sections.append(f"## 프로젝트 규칙 (AGENTS.md)\n\n{agents_md.read_text(encoding='utf-8')}")
|
sections.append(f"## 프로젝트 규칙 (GEMINI.md)\n\n{gemini_md.read_text(encoding='utf-8')}")
|
||||||
docs_dir = ROOT / "docs"
|
docs_dir = ROOT / "docs"
|
||||||
if docs_dir.is_dir():
|
if docs_dir.is_dir():
|
||||||
for doc in sorted(docs_dir.glob("*.md")):
|
for doc in sorted(docs_dir.glob("*.md")):
|
||||||
@@ -201,29 +200,29 @@ class StepExecutor:
|
|||||||
retry_section = ""
|
retry_section = ""
|
||||||
if prev_error:
|
if prev_error:
|
||||||
retry_section = (
|
retry_section = (
|
||||||
f"\n## ⚠ 이전 시도 실패 — 아래 에러를 반드시 참고하여 수정하라\n\n"
|
"\n## 이전 시도 실패 — 아래 에러를 반드시 참고하여 수정하라\n\n"
|
||||||
f"{prev_error}\n\n---\n\n"
|
f"{prev_error}\n\n---\n\n"
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
f"당신은 {self._project} 프로젝트의 Codex 문서 작성 에이전트입니다. 아래 step을 수행하세요.\n\n"
|
f"당신은 {self._project} 프로젝트의 Gemini CLI 문서 작성 에이전트입니다. 아래 step을 수행하세요.\n\n"
|
||||||
f"{guardrails}\n\n---\n\n"
|
f"{guardrails}\n\n---\n\n"
|
||||||
f"{step_context}{retry_section}"
|
f"{step_context}{retry_section}"
|
||||||
f"## 작업 규칙\n\n"
|
"## 작업 규칙\n\n"
|
||||||
f"1. 이전 step에서 작성된 문서와 메모를 확인하고 일관성을 유지하라.\n"
|
"1. 이전 step에서 작성된 문서와 메모를 확인하고 일관성을 유지하라.\n"
|
||||||
f"2. 이 step에 명시된 작업만 수행하라. 추가 산출물이나 임의 요구사항을 만들지 마라.\n"
|
"2. 이 step에 명시된 작업만 수행하라. 추가 산출물이나 임의 요구사항을 만들지 마라.\n"
|
||||||
f"3. 기존 문서 구조와 피드백 기록을 깨뜨리지 마라.\n"
|
"3. 기존 문서 구조와 피드백 기록을 깨뜨리지 마라.\n"
|
||||||
f"4. AC(Acceptance Criteria) 검증을 직접 실행하라.\n"
|
"4. AC(Acceptance Criteria) 검증을 직접 실행하라.\n"
|
||||||
f"5. /phases/{self._phase_dir_name}/index.json의 해당 step status를 업데이트하라:\n"
|
f"5. /phases/{self._phase_dir_name}/index.json의 해당 step status를 업데이트하라:\n"
|
||||||
f" - AC 통과 → \"completed\" + \"summary\" 필드에 이 step의 산출물을 한 줄로 요약\n"
|
" - AC 통과 -> \"completed\" + \"summary\" 필드에 이 step의 산출물을 한 줄로 요약\n"
|
||||||
f" - {self.MAX_RETRIES}회 수정 시도 후에도 실패 → \"error\" + \"error_message\" 기록\n"
|
f" - {self.MAX_RETRIES}회 수정 시도 후에도 실패 -> \"error\" + \"error_message\" 기록\n"
|
||||||
f" - 사용자 개입이 필요한 경우 (API 키, 인증, 수동 설정 등) → \"blocked\" + \"blocked_reason\" 기록 후 즉시 중단\n"
|
" - 사용자 개입이 필요한 경우 -> \"blocked\" + \"blocked_reason\" 기록 후 즉시 중단\n"
|
||||||
f"6. 직접 git commit하지 마라. commit은 scripts/execute.py가 step 완료 후 수행한다.\n"
|
"6. 직접 git commit하지 마라. commit은 scripts/execute.py가 step 완료 후 수행한다.\n"
|
||||||
f"7. 병렬 조사나 독립 리뷰가 필요하고 step에서 허용했다면 .codex/agents의 custom agent 역할을 활용하라.\n\n---\n\n"
|
"7. 병렬 조사나 독립 리뷰가 필요하고 step에서 허용했다면 .gemini/agents의 subagent 역할을 활용하라.\n\n---\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
# --- Codex 호출 ---
|
# --- Gemini CLI invocation ---
|
||||||
|
|
||||||
def _invoke_codex(self, step: dict, preamble: str) -> dict:
|
def _invoke_gemini(self, step: dict, preamble: str) -> dict:
|
||||||
step_num, step_name = step["step"], step["name"]
|
step_num, step_name = step["step"], step["name"]
|
||||||
step_file = self._phase_dir / f"step{step_num}.md"
|
step_file = self._phase_dir / f"step{step_num}.md"
|
||||||
|
|
||||||
@@ -232,7 +231,7 @@ class StepExecutor:
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
prompt = preamble + step_file.read_text(encoding="utf-8")
|
prompt = preamble + step_file.read_text(encoding="utf-8")
|
||||||
cmd = ["codex", "exec", "--skip-git-repo-check", "--full-auto", "--json", "-"]
|
cmd = ["gemini", "--output-format", "json", "--approval-mode", "yolo"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
@@ -246,18 +245,20 @@ class StepExecutor:
|
|||||||
timeout=1800,
|
timeout=1800,
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("\n ERROR: Codex CLI를 찾을 수 없습니다. `codex --version`이 실행되는지 확인하세요.")
|
print("\n ERROR: Gemini CLI를 찾을 수 없습니다. `gemini --version`이 실행되는지 확인하세요.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"\n WARN: Codex가 비정상 종료됨 (code {result.returncode})")
|
print(f"\n WARN: Gemini CLI가 비정상 종료됨 (code {result.returncode})")
|
||||||
if result.stderr:
|
if result.stderr:
|
||||||
print(f" stderr: {result.stderr[:500]}")
|
print(f" stderr: {result.stderr[:500]}")
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"step": step_num, "name": step_name,
|
"step": step_num,
|
||||||
|
"name": step_name,
|
||||||
"exitCode": result.returncode,
|
"exitCode": result.returncode,
|
||||||
"stdout": result.stdout, "stderr": result.stderr,
|
"stdout": result.stdout,
|
||||||
|
"stderr": result.stderr,
|
||||||
}
|
}
|
||||||
out_path = self._phase_dir / f"step{step_num}-output.json"
|
out_path = self._phase_dir / f"step{step_num}-output.json"
|
||||||
with open(out_path, "w", encoding="utf-8") as f:
|
with open(out_path, "w", encoding="utf-8") as f:
|
||||||
@@ -269,10 +270,10 @@ class StepExecutor:
|
|||||||
|
|
||||||
def _print_header(self):
|
def _print_header(self):
|
||||||
print(f"\n{'='*60}")
|
print(f"\n{'='*60}")
|
||||||
print(f" Codex Harness Step Executor")
|
print(" Gemini Harness Step Executor")
|
||||||
print(f" Phase: {self._phase_name} | Steps: {self._total}")
|
print(f" Phase: {self._phase_name} | Steps: {self._total}")
|
||||||
if self._auto_push:
|
if self._auto_push:
|
||||||
print(f" Auto-push: enabled")
|
print(" Auto-push: enabled")
|
||||||
print(f"{'='*60}")
|
print(f"{'='*60}")
|
||||||
|
|
||||||
def _check_blockers(self):
|
def _check_blockers(self):
|
||||||
@@ -281,12 +282,12 @@ class StepExecutor:
|
|||||||
if s["status"] == "error":
|
if s["status"] == "error":
|
||||||
print(f"\n ✗ Step {s['step']} ({s['name']}) failed.")
|
print(f"\n ✗ Step {s['step']} ({s['name']}) failed.")
|
||||||
print(f" Error: {s.get('error_message', 'unknown')}")
|
print(f" Error: {s.get('error_message', 'unknown')}")
|
||||||
print(f" Fix and reset status to 'pending' to retry.")
|
print(" Fix and reset status to 'pending' to retry.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if s["status"] == "blocked":
|
if s["status"] == "blocked":
|
||||||
print(f"\n ⏸ Step {s['step']} ({s['name']}) blocked.")
|
print(f"\n ⏸ Step {s['step']} ({s['name']}) blocked.")
|
||||||
print(f" Reason: {s.get('blocked_reason', 'unknown')}")
|
print(f" Reason: {s.get('blocked_reason', 'unknown')}")
|
||||||
print(f" Resolve and reset status to 'pending' to retry.")
|
print(" Resolve and reset status to 'pending' to retry.")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
if s["status"] != "pending":
|
if s["status"] != "pending":
|
||||||
break
|
break
|
||||||
@@ -315,7 +316,7 @@ class StepExecutor:
|
|||||||
tag += f" [retry {attempt}/{self.MAX_RETRIES}]"
|
tag += f" [retry {attempt}/{self.MAX_RETRIES}]"
|
||||||
|
|
||||||
with progress_indicator(tag) as pi:
|
with progress_indicator(tag) as pi:
|
||||||
self._invoke_codex(step, preamble)
|
self._invoke_gemini(step, preamble)
|
||||||
elapsed = int(pi.elapsed)
|
elapsed = int(pi.elapsed)
|
||||||
|
|
||||||
index = self._read_json(self._index_file)
|
index = self._read_json(self._index_file)
|
||||||
@@ -368,7 +369,7 @@ class StepExecutor:
|
|||||||
self._update_top_index("error")
|
self._update_top_index("error")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
return False # unreachable
|
return False
|
||||||
|
|
||||||
def _execute_all_steps(self, guardrails: str):
|
def _execute_all_steps(self, guardrails: str):
|
||||||
while True:
|
while True:
|
||||||
@@ -414,8 +415,8 @@ class StepExecutor:
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Codex Harness Step Executor")
|
parser = argparse.ArgumentParser(description="Gemini Harness Step Executor")
|
||||||
parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-mvp)")
|
parser.add_argument("phase_dir", help="Phase directory name (e.g. 0-document)")
|
||||||
parser.add_argument("--push", action="store_true", help="Push branch after completion")
|
parser.add_argument("--push", action="store_true", help="Push branch after completion")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ import execute as ex
|
|||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tmp_project(tmp_path):
|
def tmp_project(tmp_path):
|
||||||
"""phases/, AGENTS.md, docs/ 를 갖춘 임시 프로젝트 구조."""
|
"""phases/, GEMINI.md, docs/ 를 갖춘 임시 프로젝트 구조."""
|
||||||
phases_dir = tmp_path / "phases"
|
phases_dir = tmp_path / "phases"
|
||||||
phases_dir.mkdir()
|
phases_dir.mkdir()
|
||||||
|
|
||||||
agents_md = tmp_path / "AGENTS.md"
|
gemini_md = tmp_path / "GEMINI.md"
|
||||||
agents_md.write_text("# Rules\n- rule one\n- rule two", encoding="utf-8")
|
gemini_md.write_text("# Rules\n- rule one\n- rule two", encoding="utf-8")
|
||||||
|
|
||||||
docs_dir = tmp_path / "docs"
|
docs_dir = tmp_path / "docs"
|
||||||
docs_dir.mkdir()
|
docs_dir.mkdir()
|
||||||
@@ -146,7 +146,7 @@ class TestJsonHelpers:
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class TestLoadGuardrails:
|
class TestLoadGuardrails:
|
||||||
def test_loads_agents_md_and_docs(self, executor, tmp_project):
|
def test_loads_gemini_md_and_docs(self, executor, tmp_project):
|
||||||
with patch.object(ex, "ROOT", tmp_project):
|
with patch.object(ex, "ROOT", tmp_project):
|
||||||
result = executor._load_guardrails()
|
result = executor._load_guardrails()
|
||||||
assert "# Rules" in result
|
assert "# Rules" in result
|
||||||
@@ -166,11 +166,11 @@ class TestLoadGuardrails:
|
|||||||
guide_pos = result.index("guide")
|
guide_pos = result.index("guide")
|
||||||
assert arch_pos < guide_pos
|
assert arch_pos < guide_pos
|
||||||
|
|
||||||
def test_no_agents_md(self, executor, tmp_project):
|
def test_no_gemini_md(self, executor, tmp_project):
|
||||||
(tmp_project / "AGENTS.md").unlink()
|
(tmp_project / "GEMINI.md").unlink()
|
||||||
with patch.object(ex, "ROOT", tmp_project):
|
with patch.object(ex, "ROOT", tmp_project):
|
||||||
result = executor._load_guardrails()
|
result = executor._load_guardrails()
|
||||||
assert "AGENTS.md" not in result
|
assert "GEMINI.md" not in result
|
||||||
assert "Architecture" in result
|
assert "Architecture" in result
|
||||||
|
|
||||||
def test_no_docs_dir(self, executor, tmp_project):
|
def test_no_docs_dir(self, executor, tmp_project):
|
||||||
@@ -420,24 +420,24 @@ class TestCommitStep:
|
|||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# _invoke_codex (mocked)
|
# _invoke_gemini (mocked)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class TestInvokeCodex:
|
class TestInvokeGemini:
|
||||||
def test_invokes_codex_with_correct_args(self, executor):
|
def test_invokes_gemini_with_correct_args(self, executor):
|
||||||
mock_result = MagicMock(returncode=0, stdout='{"result": "ok"}', stderr="")
|
mock_result = MagicMock(returncode=0, stdout='{"result": "ok"}', stderr="")
|
||||||
step = {"step": 2, "name": "ui"}
|
step = {"step": 2, "name": "ui"}
|
||||||
preamble = "PREAMBLE\n"
|
preamble = "PREAMBLE\n"
|
||||||
|
|
||||||
with patch("subprocess.run", return_value=mock_result) as mock_run:
|
with patch("subprocess.run", return_value=mock_result) as mock_run:
|
||||||
output = executor._invoke_codex(step, preamble)
|
output = executor._invoke_gemini(step, preamble)
|
||||||
|
|
||||||
cmd = mock_run.call_args[0][0]
|
cmd = mock_run.call_args[0][0]
|
||||||
assert cmd[:2] == ["codex", "exec"]
|
assert cmd[0] == "gemini"
|
||||||
assert "--skip-git-repo-check" in cmd
|
assert "--output-format" in cmd
|
||||||
assert "--full-auto" in cmd
|
assert "json" in cmd
|
||||||
assert "--json" in cmd
|
assert "--approval-mode" in cmd
|
||||||
assert cmd[-1] == "-"
|
assert "yolo" in cmd
|
||||||
assert "PREAMBLE" in mock_run.call_args[1]["input"]
|
assert "PREAMBLE" in mock_run.call_args[1]["input"]
|
||||||
assert "UI를 구현하세요" in mock_run.call_args[1]["input"]
|
assert "UI를 구현하세요" in mock_run.call_args[1]["input"]
|
||||||
|
|
||||||
@@ -446,7 +446,7 @@ class TestInvokeCodex:
|
|||||||
step = {"step": 2, "name": "ui"}
|
step = {"step": 2, "name": "ui"}
|
||||||
|
|
||||||
with patch("subprocess.run", return_value=mock_result):
|
with patch("subprocess.run", return_value=mock_result):
|
||||||
executor._invoke_codex(step, "preamble")
|
executor._invoke_gemini(step, "preamble")
|
||||||
|
|
||||||
output_file = executor._phase_dir / "step2-output.json"
|
output_file = executor._phase_dir / "step2-output.json"
|
||||||
assert output_file.exists()
|
assert output_file.exists()
|
||||||
@@ -458,7 +458,7 @@ class TestInvokeCodex:
|
|||||||
def test_nonexistent_step_file_exits(self, executor):
|
def test_nonexistent_step_file_exits(self, executor):
|
||||||
step = {"step": 99, "name": "nonexistent"}
|
step = {"step": 99, "name": "nonexistent"}
|
||||||
with pytest.raises(SystemExit) as exc_info:
|
with pytest.raises(SystemExit) as exc_info:
|
||||||
executor._invoke_codex(step, "preamble")
|
executor._invoke_gemini(step, "preamble")
|
||||||
assert exc_info.value.code == 1
|
assert exc_info.value.code == 1
|
||||||
|
|
||||||
def test_timeout_is_1800(self, executor):
|
def test_timeout_is_1800(self, executor):
|
||||||
@@ -466,7 +466,7 @@ class TestInvokeCodex:
|
|||||||
step = {"step": 2, "name": "ui"}
|
step = {"step": 2, "name": "ui"}
|
||||||
|
|
||||||
with patch("subprocess.run", return_value=mock_result) as mock_run:
|
with patch("subprocess.run", return_value=mock_result) as mock_run:
|
||||||
executor._invoke_codex(step, "preamble")
|
executor._invoke_gemini(step, "preamble")
|
||||||
|
|
||||||
assert mock_run.call_args[1]["timeout"] == 1800
|
assert mock_run.call_args[1]["timeout"] == 1800
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Basic validation for the Markdown document harness template.
|
Basic validation for the Gemini CLI Markdown document harness template.
|
||||||
|
|
||||||
This check is intentionally lightweight: it verifies that the template files
|
This check is intentionally lightweight: it verifies that the template files
|
||||||
exist and keep the sections that later Harness steps depend on.
|
exist and keep the sections that later Harness steps depend on.
|
||||||
@@ -20,7 +20,7 @@ ROOT = Path(__file__).resolve().parent.parent
|
|||||||
|
|
||||||
REQUIRED_FILES = [
|
REQUIRED_FILES = [
|
||||||
"README.md",
|
"README.md",
|
||||||
"AGENTS.md",
|
"GEMINI.md",
|
||||||
"docs/PRD.md",
|
"docs/PRD.md",
|
||||||
"docs/ResearchNote.md",
|
"docs/ResearchNote.md",
|
||||||
"docs/DraftFeedback.md",
|
"docs/DraftFeedback.md",
|
||||||
@@ -31,14 +31,19 @@ REQUIRED_FILES = [
|
|||||||
".agents/skills/document-harness/SKILL.md",
|
".agents/skills/document-harness/SKILL.md",
|
||||||
".agents/skills/document-harness/references/phase-templates.md",
|
".agents/skills/document-harness/references/phase-templates.md",
|
||||||
".agents/skills/document-review/SKILL.md",
|
".agents/skills/document-review/SKILL.md",
|
||||||
".codex/config.toml",
|
".gemini/settings.json",
|
||||||
".codex/hooks.json",
|
".gemini/hooks/pre_tool_guard.py",
|
||||||
".codex/hooks/pre_tool_guard.py",
|
".gemini/hooks/validate_docs_after_agent.py",
|
||||||
".codex/hooks/stop_validate.py",
|
".gemini/agents/doc-researcher.md",
|
||||||
".codex/agents/doc_researcher.toml",
|
".gemini/agents/doc-drafter.md",
|
||||||
".codex/agents/doc_drafter.toml",
|
".gemini/agents/doc-reviewer.md",
|
||||||
".codex/agents/doc_reviewer.toml",
|
".gemini/agents/evidence-checker.md",
|
||||||
".codex/agents/evidence_checker.toml",
|
".gemini/commands/harness/plan.toml",
|
||||||
|
".gemini/commands/harness/research.toml",
|
||||||
|
".gemini/commands/harness/draft.toml",
|
||||||
|
".gemini/commands/harness/final.toml",
|
||||||
|
".gemini/commands/harness/review.toml",
|
||||||
|
".gemini/commands/harness/status.toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
REQUIRED_DIRS = [
|
REQUIRED_DIRS = [
|
||||||
@@ -48,18 +53,23 @@ REQUIRED_DIRS = [
|
|||||||
".agents/skills",
|
".agents/skills",
|
||||||
".agents/skills/document-harness",
|
".agents/skills/document-harness",
|
||||||
".agents/skills/document-review",
|
".agents/skills/document-review",
|
||||||
".codex",
|
".gemini",
|
||||||
".codex/hooks",
|
".gemini/commands",
|
||||||
".codex/agents",
|
".gemini/commands/harness",
|
||||||
|
".gemini/hooks",
|
||||||
|
".gemini/agents",
|
||||||
]
|
]
|
||||||
|
|
||||||
REQUIRED_SECTIONS = {
|
REQUIRED_SECTIONS = {
|
||||||
"README.md": [
|
"README.md": [
|
||||||
"## 핵심 아이디어",
|
"## 핵심 아이디어",
|
||||||
"## Codex 구성",
|
"## Gemini CLI 구성",
|
||||||
"## 빠른 시작",
|
"## 빠른 시작",
|
||||||
"## 자동 실행 방식",
|
"## 자동 실행 방식",
|
||||||
"## 피드백 게이트",
|
"## 피드백 게이트",
|
||||||
|
"## Gemini CLI Skills",
|
||||||
|
"## Gemini CLI Subagents",
|
||||||
|
"## Hooks",
|
||||||
"## 검증",
|
"## 검증",
|
||||||
],
|
],
|
||||||
"docs/PRD.md": [
|
"docs/PRD.md": [
|
||||||
@@ -83,15 +93,23 @@ REQUIRED_SECTIONS = {
|
|||||||
"## 쟁점과 상반된 주장",
|
"## 쟁점과 상반된 주장",
|
||||||
"## 확인 필요",
|
"## 확인 필요",
|
||||||
],
|
],
|
||||||
"AGENTS.md": [
|
"GEMINI.md": [
|
||||||
"## 목적",
|
"## 목적",
|
||||||
"## Codex 구성",
|
"## Gemini CLI 구성",
|
||||||
"## 기본 산출물",
|
"## 기본 산출물",
|
||||||
"## 문서 작성 규칙",
|
"## 문서 작성 규칙",
|
||||||
"## Codex 작업 규칙",
|
"## Gemini CLI 작업 규칙",
|
||||||
"## 권장 워크플로우",
|
"## 권장 워크플로우",
|
||||||
"## 명령어",
|
"## 명령어",
|
||||||
],
|
],
|
||||||
|
"docs/ARCHITECTURE.md": [
|
||||||
|
"## 디렉토리 구조",
|
||||||
|
"## 데이터 흐름",
|
||||||
|
"## Step 설계 패턴",
|
||||||
|
"## Gemini CLI 구성 책임",
|
||||||
|
"## 상태 관리",
|
||||||
|
"## 파일 책임",
|
||||||
|
],
|
||||||
".agents/skills/document-harness/SKILL.md": [
|
".agents/skills/document-harness/SKILL.md": [
|
||||||
"# Document Harness Skill",
|
"# Document Harness Skill",
|
||||||
"## Operating Rules",
|
"## Operating Rules",
|
||||||
@@ -107,11 +125,24 @@ REQUIRED_SECTIONS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
REQUIRED_JSON_FILES = [
|
REQUIRED_JSON_FILES = [
|
||||||
".codex/hooks.json",
|
".gemini/settings.json",
|
||||||
]
|
]
|
||||||
|
|
||||||
REQUIRED_TOML_FILES = [
|
REQUIRED_TOML_FILES = [
|
||||||
|
".gemini/commands/harness/plan.toml",
|
||||||
|
".gemini/commands/harness/research.toml",
|
||||||
|
".gemini/commands/harness/draft.toml",
|
||||||
|
".gemini/commands/harness/final.toml",
|
||||||
|
".gemini/commands/harness/review.toml",
|
||||||
|
".gemini/commands/harness/status.toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
FORBIDDEN_FILES = [
|
||||||
|
"AGENTS.md",
|
||||||
".codex/config.toml",
|
".codex/config.toml",
|
||||||
|
".codex/hooks.json",
|
||||||
|
".codex/hooks/pre_tool_guard.py",
|
||||||
|
".codex/hooks/stop_validate.py",
|
||||||
".codex/agents/doc_researcher.toml",
|
".codex/agents/doc_researcher.toml",
|
||||||
".codex/agents/doc_drafter.toml",
|
".codex/agents/doc_drafter.toml",
|
||||||
".codex/agents/doc_reviewer.toml",
|
".codex/agents/doc_reviewer.toml",
|
||||||
@@ -132,6 +163,8 @@ def markdown_file_has_valid_start(path: Path) -> bool:
|
|||||||
return True
|
return True
|
||||||
if first == "---" and path.name == "SKILL.md":
|
if first == "---" and path.name == "SKILL.md":
|
||||||
return True
|
return True
|
||||||
|
if first == "---" and path.parent.name == "agents":
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -151,7 +184,12 @@ def main() -> int:
|
|||||||
|
|
||||||
if path.suffix == ".md":
|
if path.suffix == ".md":
|
||||||
if not markdown_file_has_valid_start(path):
|
if not markdown_file_has_valid_start(path):
|
||||||
errors.append(f"markdown file must start with a level-1 heading or Skill frontmatter: {rel}")
|
errors.append(f"markdown file must start with a level-1 heading, Skill frontmatter, or agent frontmatter: {rel}")
|
||||||
|
|
||||||
|
for rel in FORBIDDEN_FILES:
|
||||||
|
path = ROOT / rel
|
||||||
|
if path.exists():
|
||||||
|
errors.append(f"forbidden legacy file remains: {rel}")
|
||||||
|
|
||||||
for rel, sections in REQUIRED_SECTIONS.items():
|
for rel, sections in REQUIRED_SECTIONS.items():
|
||||||
path = ROOT / rel
|
path = ROOT / rel
|
||||||
|
|||||||
Reference in New Issue
Block a user