feat(shared-skills): move init-deep to shared skill

This commit is contained in:
YeonGyu-Kim
2026-05-28 16:34:17 +09:00
parent 5662144283
commit 58871c4301
17 changed files with 499 additions and 73 deletions
+1 -1
View File
@@ -54,6 +54,7 @@
"git-master", "git-master",
"review-work", "review-work",
"ai-slop-remover", "ai-slop-remover",
"init-deep",
"team-mode" "team-mode"
] ]
} }
@@ -69,7 +70,6 @@
"items": { "items": {
"type": "string", "type": "string",
"enum": [ "enum": [
"init-deep",
"ralph-loop", "ralph-loop",
"ulw-loop", "ulw-loop",
"cancel-ralph", "cancel-ralph",
@@ -0,0 +1,325 @@
---
name: init-deep
description: "(builtin) Initialize hierarchical AGENTS.md knowledge base"
---
## Codex Harness Tool Compatibility
This skill may include examples copied from the OpenCode harness. In Codex, do not call OpenCode-only tools such as `call_omo_agent(...)`, `task(...)`, `background_output(...)`, or `team_*(...)` literally. Translate those examples to Codex native tools:
| OpenCode example | Codex tool to use |
| --- | --- |
| `call_omo_agent(subagent_type="explore", ...)` | `spawn_agent(agent_type="explorer", task_name="...", message="...")` |
| `call_omo_agent(subagent_type="librarian", ...)` | `spawn_agent(agent_type="librarian", task_name="...", message="...")` |
| `task(subagent_type="plan", ...)` | `spawn_agent(agent_type="plan", task_name="...", message="...")` |
| `task(subagent_type="oracle", ...)` for final verification | `spawn_agent(agent_type="codex-ultrawork-reviewer", task_name="...", message="...")` |
| `task(category="...", ...)` for implementation or QA | `spawn_agent(agent_type="worker", task_name="...", message="...")` |
| `background_output(task_id="...")` | `wait_agent(...)` to wait for subagent completion and mailbox updates |
| `team_*(...)` | Use Codex native subagents plus `send_message`, `followup_task`, `wait_agent`, and `close_agent` |
When translating `load_skills=[...]`, include the requested skill names in the spawned agent's `message`. If a code block below conflicts with this section, this section wins.
# /init-deep
Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories.
## Usage
```
/init-deep # Update mode: modify existing + create new where warranted
/init-deep --create-new # Read existing → remove all → regenerate from scratch
/init-deep --max-depth=2 # Limit directory depth (default: 3)
```
---
## Workflow (High-Level)
1. **Discovery + Analysis** (concurrent)
- Fire background explore agents immediately
- Main session: bash structure + LSP codemap + read existing AGENTS.md
2. **Score & Decide** - Determine AGENTS.md locations from merged findings
3. **Generate** - Root first, then subdirs in parallel
4. **Review** - Deduplicate, trim, validate
<critical>
**TodoWrite ALL phases. Mark in_progress → completed in real-time.**
```
TodoWrite([
{ id: "discovery", content: "Fire explore agents + LSP codemap + read existing", status: "pending", priority: "high" },
{ id: "scoring", content: "Score directories, determine locations", status: "pending", priority: "high" },
{ id: "generate", content: "Generate AGENTS.md files (root + subdirs)", status: "pending", priority: "high" },
{ id: "review", content: "Deduplicate, validate, trim", status: "pending", priority: "medium" }
])
```
</critical>
---
## Phase 1: Discovery + Analysis (Concurrent)
**Mark "discovery" as in_progress.**
### Fire Background Explore Agents IMMEDIATELY
Don't wait-these run async while main session works.
```
// Fire all at once, collect results later
task(subagent_type="explore", load_skills=[], description="Explore project structure", run_in_background=true, prompt="Project structure: PREDICT standard patterns for detected language → REPORT deviations only")
task(subagent_type="explore", load_skills=[], description="Find entry points", run_in_background=true, prompt="Entry points: FIND main files → REPORT non-standard organization")
task(subagent_type="explore", load_skills=[], description="Find conventions", run_in_background=true, prompt="Conventions: FIND config files (.eslintrc, pyproject.toml, .editorconfig) → REPORT project-specific rules")
task(subagent_type="explore", load_skills=[], description="Find anti-patterns", run_in_background=true, prompt="Anti-patterns: FIND 'DO NOT', 'NEVER', 'ALWAYS', 'DEPRECATED' comments → LIST forbidden patterns")
task(subagent_type="explore", load_skills=[], description="Explore build/CI", run_in_background=true, prompt="Build/CI: FIND .github/workflows, Makefile → REPORT non-standard patterns")
task(subagent_type="explore", load_skills=[], description="Find test patterns", run_in_background=true, prompt="Test patterns: FIND test configs, test structure → REPORT unique conventions")
```
<dynamic-agents>
**DYNAMIC AGENT SPAWNING**: After bash analysis, spawn ADDITIONAL explore agents based on project scale:
| Factor | Threshold | Additional Agents |
|--------|-----------|-------------------|
| **Total files** | >100 | +1 per 100 files |
| **Total lines** | >10k | +1 per 10k lines |
| **Directory depth** | ≥4 | +2 for deep exploration |
| **Large files (>500 lines)** | >10 files | +1 for complexity hotspots |
| **Monorepo** | detected | +1 per package/workspace |
| **Multiple languages** | >1 | +1 per language |
```bash
# Measure project scale first
total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l)
total_lines=$(find . -type f \\( -name "*.ts" -o -name "*.py" -o -name "*.go" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}')
large_files=$(find . -type f \\( -name "*.ts" -o -name "*.py" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | awk '$1 > 500 {count++} END {print count+0}')
max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1)
```
Example spawning:
```
// 500 files, 50k lines, depth 6, 15 large files → spawn 5+5+2+1 = 13 additional agents
task(subagent_type="explore", load_skills=[], description="Analyze large files", run_in_background=true, prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
task(subagent_type="explore", load_skills=[], description="Explore deep modules", run_in_background=true, prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
task(subagent_type="explore", load_skills=[], description="Find shared utilities", run_in_background=true, prompt="Cross-cutting concerns: FIND shared utilities across directories")
// ... more based on calculation
```
</dynamic-agents>
### Main Session: Concurrent Analysis
**While background agents run**, main session does:
#### 1. Bash Structural Analysis
```bash
# Directory depth + file counts
find . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c
# Files per directory (top 30)
find . -type f -not -path '*/\\.*' -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -30
# Code concentration by extension
find . -type f \\( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.go" -o -name "*.rs" \\) -not -path '*/node_modules/*' | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -20
# Existing AGENTS.md / CLAUDE.md
find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null
```
#### 2. Read Existing AGENTS.md
```
For each existing file found:
Read(filePath=file)
Extract: key insights, conventions, anti-patterns
Store in EXISTING_AGENTS map
```
If `--create-new`: Read all existing first (preserve context) → then delete all → regenerate.
#### 3. LSP Codemap (if available)
```
LspServers() # Check availability
# Entry points (parallel)
LspDocumentSymbols(filePath="src/index.ts")
LspDocumentSymbols(filePath="main.py")
# Key symbols (parallel)
LspWorkspaceSymbols(filePath=".", query="class")
LspWorkspaceSymbols(filePath=".", query="interface")
LspWorkspaceSymbols(filePath=".", query="function")
# Centrality for top exports
LspFindReferences(filePath="...", line=X, character=Y)
```
**LSP Fallback**: If unavailable, rely on explore agents + AST-grep.
### Collect Background Results
```
// After main session analysis done, collect all task results
for each background task ID (`bg_...`): background_output(task_id="bg_...")
```
**Merge: bash + LSP + existing + explore findings. Mark "discovery" as completed.**
---
## Phase 2: Scoring & Location Decision
**Mark "scoring" as in_progress.**
### Scoring Matrix
| Factor | Weight | High Threshold | Source |
|--------|--------|----------------|--------|
| File count | 3x | >20 | bash |
| Subdir count | 2x | >5 | bash |
| Code ratio | 2x | >70% | bash |
| Unique patterns | 1x | Has own config | explore |
| Module boundary | 2x | Has index.ts/__init__.py | bash |
| Symbol density | 2x | >30 symbols | LSP |
| Export count | 2x | >10 exports | LSP |
| Reference centrality | 3x | >20 refs | LSP |
### Decision Rules
| Score | Action |
|-------|--------|
| **Root (.)** | ALWAYS create |
| **>15** | Create AGENTS.md |
| **8-15** | Create if distinct domain |
| **<8** | Skip (parent covers) |
### Output
```
AGENTS_LOCATIONS = [
{ path: ".", type: "root" },
{ path: "src/hooks", score: 18, reason: "high complexity" },
{ path: "src/api", score: 12, reason: "distinct domain" }
]
```
**Mark "scoring" as completed.**
---
## Phase 3: Generate AGENTS.md
**Mark "generate" as in_progress.**
<critical>
**File Writing Rule**: If AGENTS.md already exists at the target path → use `Edit` tool. If it does NOT exist → use `Write` tool.
NEVER use Write to overwrite an existing file. ALWAYS check existence first via `Read` or discovery results.
</critical>
### Root AGENTS.md (Full Treatment)
```markdown
# PROJECT KNOWLEDGE BASE
**Generated:** {TIMESTAMP}
**Commit:** {SHORT_SHA}
**Branch:** {BRANCH}
## OVERVIEW
{1-2 sentences: what + core stack}
## STRUCTURE
```
{root}/
├── {dir}/ # {non-obvious purpose only}
└── {entry}
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
## CODE MAP
{From LSP - skip if unavailable or project <10 files}
| Symbol | Type | Location | Refs | Role |
|--------|------|----------|------|------|
## CONVENTIONS
{ONLY deviations from standard}
## ANTI-PATTERNS (THIS PROJECT)
{Explicitly forbidden here}
## UNIQUE STYLES
{Project-specific}
## COMMANDS
```bash
{dev/test/build}
```
## NOTES
{Gotchas}
```
**Quality gates**: 50-150 lines, no generic advice, no obvious info.
### Subdirectory AGENTS.md (Parallel)
Launch writing tasks for each location:
```
for loc in AGENTS_LOCATIONS (except root):
task(category="writing", load_skills=[], run_in_background=false, description="Generate AGENTS.md", prompt=`
Generate AGENTS.md for: ${loc.path}
- Reason: ${loc.reason}
- 30-80 lines max
- NEVER repeat parent content
- Sections: OVERVIEW (1 line), STRUCTURE (if >5 subdirs), WHERE TO LOOK, CONVENTIONS (if different), ANTI-PATTERNS
`)
```
**Wait for all. Mark "generate" as completed.**
---
## Phase 4: Review & Deduplicate
**Mark "review" as in_progress.**
For each generated file:
- Remove generic advice
- Remove parent duplicates
- Trim to size limits
- Verify telegraphic style
**Mark "review" as completed.**
---
## Final Report
```
=== init-deep Complete ===
Mode: {update | create-new}
Files:
[OK] ./AGENTS.md (root, {N} lines)
[OK] ./src/hooks/AGENTS.md ({N} lines)
Dirs Analyzed: {N}
AGENTS.md Created: {N}
AGENTS.md Updated: {N}
Hierarchy:
./AGENTS.md
└── src/hooks/AGENTS.md
```
---
## Anti-Patterns
- **Static agent count**: MUST vary agents based on project size/depth
- **Sequential execution**: MUST parallel (explore + LSP concurrent)
- **Ignoring existing**: ALWAYS read existing first, even with --create-new
- **Over-documenting**: Not every dir needs AGENTS.md
- **Redundancy**: Child never repeats parent
- **Generic content**: Remove anything that applies to ALL projects
- **Verbose style**: Telegraphic or die
@@ -11,6 +11,7 @@ const expectedSkills = [
"comment-checker", "comment-checker",
"debugging", "debugging",
"frontend-ui-ux", "frontend-ui-ux",
"init-deep",
"lsp", "lsp",
"metis", "metis",
"momus", "momus",
@@ -1,14 +1,18 @@
export const INIT_DEEP_TEMPLATE = `# /init-deep ---
name: init-deep
description: "(builtin) Initialize hierarchical AGENTS.md knowledge base"
---
# /init-deep
Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories. Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories.
## Usage ## Usage
\`\`\` ```
/init-deep # Update mode: modify existing + create new where warranted /init-deep # Update mode: modify existing + create new where warranted
/init-deep --create-new # Read existing → remove all → regenerate from scratch /init-deep --create-new # Read existing → remove all → regenerate from scratch
/init-deep --max-depth=2 # Limit directory depth (default: 3) /init-deep --max-depth=2 # Limit directory depth (default: 3)
\`\`\` ```
--- ---
@@ -23,14 +27,14 @@ Generate hierarchical AGENTS.md files. Root + complexity-scored subdirectories.
<critical> <critical>
**TodoWrite ALL phases. Mark in_progress → completed in real-time.** **TodoWrite ALL phases. Mark in_progress → completed in real-time.**
\`\`\` ```
TodoWrite([ TodoWrite([
{ id: "discovery", content: "Fire explore agents + LSP codemap + read existing", status: "pending", priority: "high" }, { id: "discovery", content: "Fire explore agents + LSP codemap + read existing", status: "pending", priority: "high" },
{ id: "scoring", content: "Score directories, determine locations", status: "pending", priority: "high" }, { id: "scoring", content: "Score directories, determine locations", status: "pending", priority: "high" },
{ id: "generate", content: "Generate AGENTS.md files (root + subdirs)", status: "pending", priority: "high" }, { id: "generate", content: "Generate AGENTS.md files (root + subdirs)", status: "pending", priority: "high" },
{ id: "review", content: "Deduplicate, validate, trim", status: "pending", priority: "medium" } { id: "review", content: "Deduplicate, validate, trim", status: "pending", priority: "medium" }
]) ])
\`\`\` ```
</critical> </critical>
--- ---
@@ -43,7 +47,7 @@ TodoWrite([
Don't wait-these run async while main session works. Don't wait-these run async while main session works.
\`\`\` ```
// Fire all at once, collect results later // Fire all at once, collect results later
task(subagent_type="explore", load_skills=[], description="Explore project structure", run_in_background=true, prompt="Project structure: PREDICT standard patterns for detected language → REPORT deviations only") task(subagent_type="explore", load_skills=[], description="Explore project structure", run_in_background=true, prompt="Project structure: PREDICT standard patterns for detected language → REPORT deviations only")
task(subagent_type="explore", load_skills=[], description="Find entry points", run_in_background=true, prompt="Entry points: FIND main files → REPORT non-standard organization") task(subagent_type="explore", load_skills=[], description="Find entry points", run_in_background=true, prompt="Entry points: FIND main files → REPORT non-standard organization")
@@ -51,7 +55,7 @@ task(subagent_type="explore", load_skills=[], description="Find conventions", ru
task(subagent_type="explore", load_skills=[], description="Find anti-patterns", run_in_background=true, prompt="Anti-patterns: FIND 'DO NOT', 'NEVER', 'ALWAYS', 'DEPRECATED' comments → LIST forbidden patterns") task(subagent_type="explore", load_skills=[], description="Find anti-patterns", run_in_background=true, prompt="Anti-patterns: FIND 'DO NOT', 'NEVER', 'ALWAYS', 'DEPRECATED' comments → LIST forbidden patterns")
task(subagent_type="explore", load_skills=[], description="Explore build/CI", run_in_background=true, prompt="Build/CI: FIND .github/workflows, Makefile → REPORT non-standard patterns") task(subagent_type="explore", load_skills=[], description="Explore build/CI", run_in_background=true, prompt="Build/CI: FIND .github/workflows, Makefile → REPORT non-standard patterns")
task(subagent_type="explore", load_skills=[], description="Find test patterns", run_in_background=true, prompt="Test patterns: FIND test configs, test structure → REPORT unique conventions") task(subagent_type="explore", load_skills=[], description="Find test patterns", run_in_background=true, prompt="Test patterns: FIND test configs, test structure → REPORT unique conventions")
\`\`\` ```
<dynamic-agents> <dynamic-agents>
**DYNAMIC AGENT SPAWNING**: After bash analysis, spawn ADDITIONAL explore agents based on project scale: **DYNAMIC AGENT SPAWNING**: After bash analysis, spawn ADDITIONAL explore agents based on project scale:
@@ -65,22 +69,22 @@ task(subagent_type="explore", load_skills=[], description="Find test patterns",
| **Monorepo** | detected | +1 per package/workspace | | **Monorepo** | detected | +1 per package/workspace |
| **Multiple languages** | >1 | +1 per language | | **Multiple languages** | >1 | +1 per language |
\`\`\`bash ```bash
# Measure project scale first # Measure project scale first
total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l) total_files=$(find . -type f -not -path '*/node_modules/*' -not -path '*/.git/*' | wc -l)
total_lines=$(find . -type f \\( -name "*.ts" -o -name "*.py" -o -name "*.go" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}') total_lines=$(find . -type f \\( -name "*.ts" -o -name "*.py" -o -name "*.go" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | tail -1 | awk '{print $1}')
large_files=$(find . -type f \\( -name "*.ts" -o -name "*.py" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | awk '$1 > 500 {count++} END {print count+0}') large_files=$(find . -type f \\( -name "*.ts" -o -name "*.py" \\) -not -path '*/node_modules/*' -exec wc -l {} + 2>/dev/null | awk '$1 > 500 {count++} END {print count+0}')
max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1) max_depth=$(find . -type d -not -path '*/node_modules/*' -not -path '*/.git/*' | awk -F/ '{print NF}' | sort -rn | head -1)
\`\`\` ```
Example spawning: Example spawning:
\`\`\` ```
// 500 files, 50k lines, depth 6, 15 large files → spawn 5+5+2+1 = 13 additional agents // 500 files, 50k lines, depth 6, 15 large files → spawn 5+5+2+1 = 13 additional agents
task(subagent_type="explore", load_skills=[], description="Analyze large files", run_in_background=true, prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots") task(subagent_type="explore", load_skills=[], description="Analyze large files", run_in_background=true, prompt="Large file analysis: FIND files >500 lines, REPORT complexity hotspots")
task(subagent_type="explore", load_skills=[], description="Explore deep modules", run_in_background=true, prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions") task(subagent_type="explore", load_skills=[], description="Explore deep modules", run_in_background=true, prompt="Deep modules at depth 4+: FIND hidden patterns, internal conventions")
task(subagent_type="explore", load_skills=[], description="Find shared utilities", run_in_background=true, prompt="Cross-cutting concerns: FIND shared utilities across directories") task(subagent_type="explore", load_skills=[], description="Find shared utilities", run_in_background=true, prompt="Cross-cutting concerns: FIND shared utilities across directories")
// ... more based on calculation // ... more based on calculation
\`\`\` ```
</dynamic-agents> </dynamic-agents>
### Main Session: Concurrent Analysis ### Main Session: Concurrent Analysis
@@ -88,7 +92,7 @@ task(subagent_type="explore", load_skills=[], description="Find shared utilities
**While background agents run**, main session does: **While background agents run**, main session does:
#### 1. Bash Structural Analysis #### 1. Bash Structural Analysis
\`\`\`bash ```bash
# Directory depth + file counts # Directory depth + file counts
find . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c find . -type d -not -path '*/\\.*' -not -path '*/node_modules/*' -not -path '*/venv/*' -not -path '*/dist/*' -not -path '*/build/*' | awk -F/ '{print NF-1}' | sort -n | uniq -c
@@ -100,20 +104,20 @@ find . -type f \\( -name "*.py" -o -name "*.ts" -o -name "*.tsx" -o -name "*.js"
# Existing AGENTS.md / CLAUDE.md # Existing AGENTS.md / CLAUDE.md
find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null find . -type f \\( -name "AGENTS.md" -o -name "CLAUDE.md" \\) -not -path '*/node_modules/*' 2>/dev/null
\`\`\` ```
#### 2. Read Existing AGENTS.md #### 2. Read Existing AGENTS.md
\`\`\` ```
For each existing file found: For each existing file found:
Read(filePath=file) Read(filePath=file)
Extract: key insights, conventions, anti-patterns Extract: key insights, conventions, anti-patterns
Store in EXISTING_AGENTS map Store in EXISTING_AGENTS map
\`\`\` ```
If \`--create-new\`: Read all existing first (preserve context) → then delete all → regenerate. If `--create-new`: Read all existing first (preserve context) → then delete all → regenerate.
#### 3. LSP Codemap (if available) #### 3. LSP Codemap (if available)
\`\`\` ```
LspServers() # Check availability LspServers() # Check availability
# Entry points (parallel) # Entry points (parallel)
@@ -127,16 +131,16 @@ LspWorkspaceSymbols(filePath=".", query="function")
# Centrality for top exports # Centrality for top exports
LspFindReferences(filePath="...", line=X, character=Y) LspFindReferences(filePath="...", line=X, character=Y)
\`\`\` ```
**LSP Fallback**: If unavailable, rely on explore agents + AST-grep. **LSP Fallback**: If unavailable, rely on explore agents + AST-grep.
### Collect Background Results ### Collect Background Results
\`\`\` ```
// After main session analysis done, collect all task results // After main session analysis done, collect all task results
for each background task ID (\`bg_...\`): background_output(task_id="bg_...") for each background task ID (`bg_...`): background_output(task_id="bg_...")
\`\`\` ```
**Merge: bash + LSP + existing + explore findings. Mark "discovery" as completed.** **Merge: bash + LSP + existing + explore findings. Mark "discovery" as completed.**
@@ -169,13 +173,13 @@ for each background task ID (\`bg_...\`): background_output(task_id="bg_...")
| **<8** | Skip (parent covers) | | **<8** | Skip (parent covers) |
### Output ### Output
\`\`\` ```
AGENTS_LOCATIONS = [ AGENTS_LOCATIONS = [
{ path: ".", type: "root" }, { path: ".", type: "root" },
{ path: "src/hooks", score: 18, reason: "high complexity" }, { path: "src/hooks", score: 18, reason: "high complexity" },
{ path: "src/api", score: 12, reason: "distinct domain" } { path: "src/api", score: 12, reason: "distinct domain" }
] ]
\`\`\` ```
**Mark "scoring" as completed.** **Mark "scoring" as completed.**
@@ -186,13 +190,13 @@ AGENTS_LOCATIONS = [
**Mark "generate" as in_progress.** **Mark "generate" as in_progress.**
<critical> <critical>
**File Writing Rule**: If AGENTS.md already exists at the target path → use \`Edit\` tool. If it does NOT exist → use \`Write\` tool. **File Writing Rule**: If AGENTS.md already exists at the target path → use `Edit` tool. If it does NOT exist → use `Write` tool.
NEVER use Write to overwrite an existing file. ALWAYS check existence first via \`Read\` or discovery results. NEVER use Write to overwrite an existing file. ALWAYS check existence first via `Read` or discovery results.
</critical> </critical>
### Root AGENTS.md (Full Treatment) ### Root AGENTS.md (Full Treatment)
\`\`\`markdown ```markdown
# PROJECT KNOWLEDGE BASE # PROJECT KNOWLEDGE BASE
**Generated:** {TIMESTAMP} **Generated:** {TIMESTAMP}
@@ -203,11 +207,11 @@ NEVER use Write to overwrite an existing file. ALWAYS check existence first via
{1-2 sentences: what + core stack} {1-2 sentences: what + core stack}
## STRUCTURE ## STRUCTURE
\\\`\\\`\\\` ```
{root}/ {root}/
├── {dir}/ # {non-obvious purpose only} ├── {dir}/ # {non-obvious purpose only}
└── {entry} └── {entry}
\\\`\\\`\\\` ```
## WHERE TO LOOK ## WHERE TO LOOK
| Task | Location | Notes | | Task | Location | Notes |
@@ -229,13 +233,13 @@ NEVER use Write to overwrite an existing file. ALWAYS check existence first via
{Project-specific} {Project-specific}
## COMMANDS ## COMMANDS
\\\`\\\`\\\`bash ```bash
{dev/test/build} {dev/test/build}
\\\`\\\`\\\` ```
## NOTES ## NOTES
{Gotchas} {Gotchas}
\`\`\` ```
**Quality gates**: 50-150 lines, no generic advice, no obvious info. **Quality gates**: 50-150 lines, no generic advice, no obvious info.
@@ -243,16 +247,16 @@ NEVER use Write to overwrite an existing file. ALWAYS check existence first via
Launch writing tasks for each location: Launch writing tasks for each location:
\`\`\` ```
for loc in AGENTS_LOCATIONS (except root): for loc in AGENTS_LOCATIONS (except root):
task(category="writing", load_skills=[], run_in_background=false, description="Generate AGENTS.md", prompt=\\\` task(category="writing", load_skills=[], run_in_background=false, description="Generate AGENTS.md", prompt=`
Generate AGENTS.md for: \${loc.path} Generate AGENTS.md for: ${loc.path}
- Reason: \${loc.reason} - Reason: ${loc.reason}
- 30-80 lines max - 30-80 lines max
- NEVER repeat parent content - NEVER repeat parent content
- Sections: OVERVIEW (1 line), STRUCTURE (if >5 subdirs), WHERE TO LOOK, CONVENTIONS (if different), ANTI-PATTERNS - Sections: OVERVIEW (1 line), STRUCTURE (if >5 subdirs), WHERE TO LOOK, CONVENTIONS (if different), ANTI-PATTERNS
\\\`) `)
\`\`\` ```
**Wait for all. Mark "generate" as completed.** **Wait for all. Mark "generate" as completed.**
@@ -274,7 +278,7 @@ For each generated file:
## Final Report ## Final Report
\`\`\` ```
=== init-deep Complete === === init-deep Complete ===
Mode: {update | create-new} Mode: {update | create-new}
@@ -290,7 +294,7 @@ AGENTS.md Updated: {N}
Hierarchy: Hierarchy:
./AGENTS.md ./AGENTS.md
└── src/hooks/AGENTS.md └── src/hooks/AGENTS.md
\`\`\` ```
--- ---
@@ -302,4 +306,4 @@ Hierarchy:
- **Over-documenting**: Not every dir needs AGENTS.md - **Over-documenting**: Not every dir needs AGENTS.md
- **Redundancy**: Child never repeats parent - **Redundancy**: Child never repeats parent
- **Generic content**: Remove anything that applies to ALL projects - **Generic content**: Remove anything that applies to ALL projects
- **Verbose style**: Telegraphic or die` - **Verbose style**: Telegraphic or die
+5 -2
View File
@@ -1,11 +1,13 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { OhMyOpenCodeConfigSchema } from "./oh-my-opencode-config" import { OhMyOpenCodeConfigSchema } from "./oh-my-opencode-config"
describe("OhMyOpenCodeConfigSchema disabled_skills", () => { describe("OhMyOpenCodeConfigSchema disabled_skills", () => {
test("accepts review-work and ai-slop-remover", () => { test("accepts review-work, ai-slop-remover, and init-deep", () => {
// given // given
const config = { const config = {
disabled_skills: ["review-work", "ai-slop-remover"], disabled_skills: ["review-work", "ai-slop-remover", "init-deep"],
} }
// when // when
@@ -17,6 +19,7 @@ describe("OhMyOpenCodeConfigSchema disabled_skills", () => {
expect(result.data.disabled_skills).toEqual([ expect(result.data.disabled_skills).toEqual([
"review-work", "review-work",
"ai-slop-remover", "ai-slop-remover",
"init-deep",
]) ])
} }
}) })
+1
View File
@@ -22,6 +22,7 @@ export const BuiltinSkillNameSchema = z.enum([
"git-master", "git-master",
"review-work", "review-work",
"ai-slop-remover", "ai-slop-remover",
"init-deep",
"team-mode", "team-mode",
]) ])
-1
View File
@@ -1,7 +1,6 @@
import { z } from "zod" import { z } from "zod"
export const BuiltinCommandNameSchema = z.enum([ export const BuiltinCommandNameSchema = z.enum([
"init-deep",
"ralph-loop", "ralph-loop",
"ulw-loop", "ulw-loop",
"cancel-ralph", "cancel-ralph",
-12
View File
@@ -1,7 +1,6 @@
import type { CommandDefinition } from "../claude-code-command-loader" import type { CommandDefinition } from "../claude-code-command-loader"
import { isAgentRegistered } from "../claude-code-session-state" import { isAgentRegistered } from "../claude-code-session-state"
import type { BuiltinCommandName, BuiltinCommands } from "./types" import type { BuiltinCommandName, BuiltinCommands } from "./types"
import { INIT_DEEP_TEMPLATE } from "./templates/init-deep"
import { RALPH_LOOP_TEMPLATE, ULW_LOOP_TEMPLATE, CANCEL_RALPH_TEMPLATE } from "./templates/ralph-loop" import { RALPH_LOOP_TEMPLATE, ULW_LOOP_TEMPLATE, CANCEL_RALPH_TEMPLATE } from "./templates/ralph-loop"
import { STOP_CONTINUATION_TEMPLATE } from "./templates/stop-continuation" import { STOP_CONTINUATION_TEMPLATE } from "./templates/stop-continuation"
import { REFACTOR_TEMPLATE, REFACTOR_TEAM_MODE_ADDENDUM } from "./templates/refactor" import { REFACTOR_TEMPLATE, REFACTOR_TEAM_MODE_ADDENDUM } from "./templates/refactor"
@@ -39,17 +38,6 @@ function createBuiltinCommandDefinitions(
) )
return { return {
"init-deep": {
description: "(builtin) Initialize hierarchical AGENTS.md knowledge base",
template: `<command-instruction>
${INIT_DEEP_TEMPLATE}
</command-instruction>
<user-request>
$ARGUMENTS
</user-request>`,
argumentHint: "[--create-new] [--max-depth=N]",
},
"ralph-loop": { "ralph-loop": {
description: "(builtin) Start self-referential development loop until completion", description: "(builtin) Start self-referential development loop until completion",
template: `<command-instruction> template: `<command-instruction>
@@ -0,0 +1,16 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, test } from "bun:test"
import { loadBuiltinCommands } from "./commands"
describe("init-deep skill migration", () => {
test("#given builtin commands #when loaded #then init-deep no longer ships as a command", () => {
// given
// when
const commands = loadBuiltinCommands()
// then
expect(commands["init-deep"]).toBeUndefined()
})
})
+1 -1
View File
@@ -1,6 +1,6 @@
import type { CommandDefinition } from "../claude-code-command-loader" import type { CommandDefinition } from "../claude-code-command-loader"
export type BuiltinCommandName = "init-deep" | "ralph-loop" | "cancel-ralph" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "remove-ai-slops" | "hyperplan" export type BuiltinCommandName = "ralph-loop" | "cancel-ralph" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "remove-ai-slops" | "hyperplan"
export interface BuiltinCommandConfig { export interface BuiltinCommandConfig {
disabled_commands?: BuiltinCommandName[] disabled_commands?: BuiltinCommandName[]
@@ -1,7 +1,13 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import type { BuiltinSkill } from "./types" import type { BuiltinSkill } from "./types"
const TARGET_SKILLS = ["ai-slop-remover", "review-work", "frontend-ui-ux"] as const declare const Bun: {
file(path: string): { text(): Promise<string> }
}
const TARGET_SKILLS = ["ai-slop-remover", "review-work", "frontend-ui-ux", "init-deep"] as const
type TargetSkill = (typeof TARGET_SKILLS)[number] type TargetSkill = (typeof TARGET_SKILLS)[number]
@@ -28,10 +34,13 @@ async function readSkillSource(name: TargetSkill): Promise<SkillSource> {
case "review-work": case "review-work":
skill = (await import("./skills/review-work")).reviewWorkSkill skill = (await import("./skills/review-work")).reviewWorkSkill
break break
case "frontend-ui-ux": case "frontend-ui-ux":
skill = (await import("./skills/frontend-ui-ux")).frontendUiUxSkill skill = (await import("./skills/frontend-ui-ux")).frontendUiUxSkill
break break
} case "init-deep":
skill = (await import("./skills/init-deep")).initDeepSkill
break
}
return { name, description: skill.description, template: skill.template } return { name, description: skill.description, template: skill.template }
} }
@@ -1,9 +1,15 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, test } from "bun:test" import { describe, expect, test } from "bun:test"
import { parseFrontmatter } from "../../shared/frontmatter" import { parseFrontmatter } from "../../shared/frontmatter"
import { createBuiltinSkills } from "./skills" import { createBuiltinSkills } from "./skills"
import { createSharedSkillTemplateLoader, loadSharedSkillTemplate } from "./skill-file-loader" import { createSharedSkillTemplateLoader, loadSharedSkillTemplate } from "./skill-file-loader"
const SHARED_BUILTIN_SKILLS = ["ai-slop-remover", "review-work", "frontend-ui-ux"] as const declare const Bun: {
file(path: string): { text(): Promise<string> }
}
const SHARED_BUILTIN_SKILLS = ["ai-slop-remover", "review-work", "frontend-ui-ux", "init-deep"] as const
describe("shared builtin skill file loader", () => { describe("shared builtin skill file loader", () => {
test("#given extracted shared skill files #when builtin skills are created #then templates load from SKILL.md bodies", async () => { test("#given extracted shared skill files #when builtin skills are created #then templates load from SKILL.md bodies", async () => {
+29 -9
View File
@@ -1,3 +1,5 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, test, expect } from "bun:test" import { describe, test, expect } from "bun:test"
import { createBuiltinSkills } from "./skills" import { createBuiltinSkills } from "./skills"
@@ -83,7 +85,7 @@ describe("createBuiltinSkills", () => {
expect(agentBrowserSkill!.template).toContain("agent-browser snapshot") expect(agentBrowserSkill!.template).toContain("agent-browser snapshot")
}) })
test("always includes frontend-ui-ux, git-master, review-work, and ai-slop-remover skills", () => { test("always includes frontend-ui-ux, git-master, review-work, ai-slop-remover, and init-deep skills", () => {
// given - both provider options // given - both provider options
// when // when
@@ -97,10 +99,11 @@ describe("createBuiltinSkills", () => {
expect(skills.find((s) => s.name === "git-master")).toBeDefined() expect(skills.find((s) => s.name === "git-master")).toBeDefined()
expect(skills.find((s) => s.name === "review-work")).toBeDefined() expect(skills.find((s) => s.name === "review-work")).toBeDefined()
expect(skills.find((s) => s.name === "ai-slop-remover")).toBeDefined() expect(skills.find((s) => s.name === "ai-slop-remover")).toBeDefined()
expect(skills.find((s) => s.name === "init-deep")).toBeDefined()
} }
}) })
test("returns exactly 5 skills regardless of provider", () => { test("returns exactly 6 skills regardless of provider", () => {
// given // given
// when // when
@@ -109,9 +112,9 @@ describe("createBuiltinSkills", () => {
const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" }) const devBrowserSkills = createBuiltinSkills({ browserProvider: "dev-browser" })
// then // then
expect(defaultSkills).toHaveLength(5) expect(defaultSkills).toHaveLength(6)
expect(agentBrowserSkills).toHaveLength(5) expect(agentBrowserSkills).toHaveLength(6)
expect(devBrowserSkills).toHaveLength(5) expect(devBrowserSkills).toHaveLength(6)
}) })
test("should exclude playwright when it is in disabledSkills", () => { test("should exclude playwright when it is in disabledSkills", () => {
@@ -128,7 +131,8 @@ describe("createBuiltinSkills", () => {
expect(skills.map((s) => s.name)).not.toContain("dev-browser") expect(skills.map((s) => s.name)).not.toContain("dev-browser")
expect(skills.map((s) => s.name)).toContain("review-work") expect(skills.map((s) => s.name)).toContain("review-work")
expect(skills.map((s) => s.name)).toContain("ai-slop-remover") expect(skills.map((s) => s.name)).toContain("ai-slop-remover")
expect(skills.length).toBe(4) expect(skills.map((s) => s.name)).toContain("init-deep")
expect(skills.length).toBe(5)
}) })
test("should exclude multiple skills when they are in disabledSkills", () => { test("should exclude multiple skills when they are in disabledSkills", () => {
@@ -145,12 +149,13 @@ describe("createBuiltinSkills", () => {
expect(skills.map((s) => s.name)).not.toContain("dev-browser") expect(skills.map((s) => s.name)).not.toContain("dev-browser")
expect(skills.map((s) => s.name)).toContain("review-work") expect(skills.map((s) => s.name)).toContain("review-work")
expect(skills.map((s) => s.name)).toContain("ai-slop-remover") expect(skills.map((s) => s.name)).toContain("ai-slop-remover")
expect(skills.length).toBe(3) expect(skills.map((s) => s.name)).toContain("init-deep")
expect(skills.length).toBe(4)
}) })
test("should return an empty array when all skills are disabled", () => { test("should return an empty array when all skills are disabled", () => {
// #given // #given
const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover"]) } const options = { disabledSkills: new Set(["playwright", "frontend-ui-ux", "git-master", "review-work", "ai-slop-remover", "init-deep"]) }
// #when // #when
const skills = createBuiltinSkills(options) const skills = createBuiltinSkills(options)
@@ -167,7 +172,22 @@ describe("createBuiltinSkills", () => {
const skills = createBuiltinSkills(options) const skills = createBuiltinSkills(options)
// #then // #then
expect(skills.length).toBe(5) expect(skills.length).toBe(6)
})
test("init-deep skill has correct structure", () => {
// #given - default options
// #when
const skills = createBuiltinSkills()
const initDeep = skills.find((s) => s.name === "init-deep")
// #then
expect(initDeep).toBeDefined()
expect(initDeep!.description).toContain("hierarchical AGENTS.md")
expect(initDeep!.argumentHint).toBe("[--create-new] [--max-depth=N]")
expect(initDeep!.template).toContain("Generate hierarchical AGENTS.md files")
expect(initDeep!.template).toContain("Discovery + Analysis")
}) })
test("review-work skill has correct structure", () => { test("review-work skill has correct structure", () => {
+2 -1
View File
@@ -8,6 +8,7 @@ import {
frontendUiUxSkill, frontendUiUxSkill,
gitMasterSkill, gitMasterSkill,
devBrowserSkill, devBrowserSkill,
initDeepSkill,
reviewWorkSkill, reviewWorkSkill,
aiSlopRemoverSkill, aiSlopRemoverSkill,
teamModeSkill, teamModeSkill,
@@ -33,7 +34,7 @@ export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): B
browserSkill = playwrightSkill browserSkill = playwrightSkill
} }
const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, reviewWorkSkill, aiSlopRemoverSkill] const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, reviewWorkSkill, aiSlopRemoverSkill, initDeepSkill]
if (teamModeEnabled && !disabledSkills?.has("team-mode")) { if (teamModeEnabled && !disabledSkills?.has("team-mode")) {
skills.push(teamModeSkill) skills.push(teamModeSkill)
@@ -5,4 +5,5 @@ export { gitMasterSkill } from "./git-master"
export { devBrowserSkill } from "./dev-browser" export { devBrowserSkill } from "./dev-browser"
export { reviewWorkSkill } from "./review-work" export { reviewWorkSkill } from "./review-work"
export { aiSlopRemoverSkill } from "./ai-slop-remover" export { aiSlopRemoverSkill } from "./ai-slop-remover"
export { initDeepSkill } from "./init-deep"
export * from "./team-mode" export * from "./team-mode"
@@ -0,0 +1,9 @@
import { loadSharedSkillTemplate } from "../skill-file-loader"
import type { BuiltinSkill } from "../types"
export const initDeepSkill: BuiltinSkill = {
name: "init-deep",
description: "(builtin) Initialize hierarchical AGENTS.md knowledge base",
template: loadSharedSkillTemplate("init-deep"),
argumentHint: "[--create-new] [--max-depth=N]",
}
@@ -0,0 +1,43 @@
/// <reference path="../../../bun-test.d.ts" />
import { describe, expect, test } from "bun:test"
import { createBuiltinSkills } from "../../features/builtin-skills"
import type { LoadedSkill } from "../../features/opencode-skill-loader"
import { executeSlashCommand } from "./executor"
function asLoadedSkill(name: string): LoadedSkill {
const skill = createBuiltinSkills().find((candidate) => candidate.name === name)
if (!skill) {
throw new Error(`missing builtin skill: ${name}`)
}
return {
name: skill.name,
definition: {
name: skill.name,
description: skill.description,
template: skill.template,
argumentHint: skill.argumentHint,
},
scope: "builtin",
}
}
describe("init-deep slash surface", () => {
test("#given init-deep builtin skill #when slash command executes #then it renders skill instructions with arguments", async () => {
// given
const skills = [asLoadedSkill("init-deep")]
// when
const result = await executeSlashCommand(
{ command: "init-deep", args: "--max-depth=2", raw: "/init-deep --max-depth=2" },
{ skills, pluginsEnabled: false },
)
// then
expect(result.success).toBe(true)
expect(result.replacementText).toContain("**Scope**: skill")
expect(result.replacementText).toContain("--max-depth=2")
expect(result.replacementText).toContain("Generate hierarchical AGENTS.md files")
})
})