Skip to content

Commit cf7189d

Browse files
jcasimirclaude
andcommitted
Add generate-shims.sh for deterministic agent shim generation
Bash script scans orchestrators and reviewers for agent-shim: true in frontmatter, generates _shim-*.md files in agents/review/. Replaces Claude-driven generation with deterministic output. Orchestrator shims delegate to /ce:run. Reviewer shims load the full persona and answer in character. Old shims are cleaned up on each run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 33ae431 commit cf7189d

2 files changed

Lines changed: 162 additions & 45 deletions

File tree

plugins/compound-engineering/skills/refresh/SKILL.md

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -78,52 +78,13 @@ bash "$PLUGIN_DIR/skills/refresh/sync-reviewers.sh" \
7878

7979
## Step 5: Generate agent shims
8080

81-
After syncing reviewers and orchestrators, scan both directories for files with `agent-shim: true` in their YAML frontmatter. For each match, generate an agent shim file in `$PLUGIN_DIR/agents/review/`.
81+
Run the shim generation script. This scans synced reviewers and orchestrators for `agent-shim: true` in their frontmatter and generates `_shim-*.md` files in `agents/review/`:
8282

83-
### For orchestrators (`$PLUGIN_DIR/orchestrators/*.md`)
84-
85-
Read each file's frontmatter. If `agent-shim: true` is present, extract the `name` and `description` fields. Generate a shim at `$PLUGIN_DIR/agents/review/_shim-<name>.md`:
86-
87-
```markdown
88-
---
89-
name: <name>
90-
description: "<first line of description>. Use when the user mentions <name> by name."
91-
model: inherit
92-
---
93-
94-
Run `/ce:run <name> $ARGUMENTS`
95-
```
96-
97-
### For reviewers (`$PLUGIN_DIR/agents/review/*.md`)
98-
99-
Read each file's frontmatter. If `agent-shim: true` is present, extract the `name`, `description`, and the reviewer's filename. Generate a shim at `$PLUGIN_DIR/agents/review/_shim-<short-name>.md` where `<short-name>` is the first name (e.g., `avi` from `avi-rails-architect`, `sandi` from `sandi-metz-oo-reviewer`):
100-
101-
```markdown
102-
---
103-
name: <short-name>
104-
description: "<description>. Use when the user mentions <short-name> by name or asks for their opinion."
105-
model: inherit
106-
tools: Read, Grep, Glob, Bash
107-
---
108-
109-
You are <short-name>. Load your full persona from `$PLUGIN_DIR/agents/review/<reviewer-filename>` and adopt it. Then address the user's request in character.
110-
111-
$ARGUMENTS
83+
```bash
84+
bash "$PLUGIN_DIR/skills/refresh/generate-shims.sh" "$PLUGIN_DIR"
11285
```
11386

114-
### Cleanup
115-
116-
Before generating, remove any existing `_shim-*.md` files in `agents/review/` to avoid stale shims from previously synced definitions.
117-
118-
### Summary
119-
120-
After generating, list the shims created:
121-
122-
```
123-
Generated agent shims:
124-
Orchestrators: erin, lfg, max, nelly, oscar
125-
Reviewers: avi, abby, sandi, ...
126-
```
87+
Show the script's output to the user — it lists which shims were generated.
12788

12889
## Step 6: Show results
12990

@@ -133,8 +94,6 @@ The sync script writes summaries to `~/.config/compound-engineering/`:
13394

13495
Read all summary files that exist and **output their contents to the user exactly as written**. The summaries are already formatted as markdown — do not summarize, paraphrase, or reformat them.
13596

136-
Then show the agent shim generation summary.
137-
13897
## Source YAML Format
13998

14099
Both reviewer and orchestrator source configs use the same format:
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env bash
2+
#
3+
# generate-shims.sh — Auto-generate agent shim files from agent-shim: true frontmatter
4+
#
5+
# Usage: ./generate-shims.sh <plugin-dir>
6+
#
7+
# Scans orchestrators/ and agents/review/ for files with agent-shim: true
8+
# in their YAML frontmatter. Generates _shim-<name>.md files in agents/review/
9+
# so they're addressable by name in natural language.
10+
11+
set -u
12+
13+
PLUGIN_DIR="${1:?Usage: generate-shims.sh <plugin-dir>}"
14+
REVIEW_DIR="$PLUGIN_DIR/agents/review"
15+
ORCH_DIR="$PLUGIN_DIR/orchestrators"
16+
17+
# Clean up old shims
18+
rm -f "$REVIEW_DIR"/_shim-*.md
19+
20+
orch_shims=""
21+
reviewer_shims=""
22+
23+
# Helper: extract frontmatter fields from an .md file
24+
# Writes name and description to temp files
25+
extract_frontmatter() {
26+
local file="$1" name_file="$2" desc_file="$3"
27+
python3 -c "
28+
import sys
29+
30+
in_front = False
31+
name = ''
32+
desc_lines = []
33+
in_desc = False
34+
35+
for line in open(sys.argv[1]):
36+
stripped = line.strip()
37+
if stripped == '---':
38+
if in_front: break
39+
in_front = True
40+
continue
41+
if not in_front:
42+
continue
43+
if in_desc:
44+
if stripped and not any(stripped.startswith(k) for k in [
45+
'phases:', 'type:', 'model:', 'orchestrator-model:',
46+
'agent-model:', 'agent-shim:', 'review-preferences:',
47+
'synthesis:', 'category:', 'select_when:', 'color:',
48+
'tools:', '- name:'
49+
]):
50+
desc_lines.append(stripped)
51+
continue
52+
else:
53+
in_desc = False
54+
if stripped.startswith('name:'):
55+
name = stripped.split(':', 1)[1].strip().strip('\"').strip(\"'\")
56+
elif stripped.startswith('description:'):
57+
val = stripped.split(':', 1)[1].strip()
58+
if val == '|':
59+
in_desc = True
60+
else:
61+
desc_lines.append(val.strip('\"').strip(\"'\"))
62+
63+
desc = ' '.join(desc_lines)
64+
with open(sys.argv[2], 'w') as f: f.write(name)
65+
with open(sys.argv[3], 'w') as f: f.write(desc[:200])
66+
" "$file" "$name_file" "$desc_file"
67+
}
68+
69+
# Helper: check if file has agent-shim: true
70+
has_agent_shim() {
71+
python3 -c "
72+
import sys
73+
in_front = False
74+
for line in open(sys.argv[1]):
75+
stripped = line.strip()
76+
if stripped == '---':
77+
if in_front: break
78+
in_front = True
79+
continue
80+
if in_front and stripped == 'agent-shim: true':
81+
print('yes')
82+
break
83+
" "$1" 2>/dev/null
84+
}
85+
86+
tmp_name=$(mktemp)
87+
tmp_desc=$(mktemp)
88+
trap "rm -f '$tmp_name' '$tmp_desc'" EXIT
89+
90+
# --- Generate orchestrator shims ---
91+
if [ -d "$ORCH_DIR" ]; then
92+
for filepath in "$ORCH_DIR"/*.md; do
93+
[ -f "$filepath" ] || continue
94+
[ "$(has_agent_shim "$filepath")" = "yes" ] || continue
95+
96+
extract_frontmatter "$filepath" "$tmp_name" "$tmp_desc"
97+
NAME=$(cat "$tmp_name")
98+
DESC=$(cat "$tmp_desc")
99+
[ -n "$NAME" ] || continue
100+
101+
cat > "$REVIEW_DIR/_shim-${NAME}.md" << SHIM
102+
---
103+
name: $NAME
104+
description: "$DESC Use when the user mentions $NAME by name."
105+
model: inherit
106+
---
107+
108+
Run \`/ce:run $NAME \$ARGUMENTS\`
109+
SHIM
110+
111+
orch_shims="${orch_shims:+$orch_shims, }$NAME"
112+
done
113+
fi
114+
115+
# --- Generate reviewer shims ---
116+
for filepath in "$REVIEW_DIR"/*.md; do
117+
[ -f "$filepath" ] || continue
118+
filename=$(basename "$filepath")
119+
120+
# Skip shims and templates
121+
case "$filename" in _shim-*|_template-*) continue ;; esac
122+
123+
[ "$(has_agent_shim "$filepath")" = "yes" ] || continue
124+
125+
extract_frontmatter "$filepath" "$tmp_name" "$tmp_desc"
126+
NAME=$(cat "$tmp_name")
127+
DESC=$(cat "$tmp_desc")
128+
[ -n "$NAME" ] || continue
129+
130+
# Short name: first part before hyphen (avi from avi-rails-architect)
131+
SHORT_NAME=$(echo "$NAME" | cut -d'-' -f1)
132+
133+
# Don't overwrite an orchestrator shim with the same name
134+
[ -f "$REVIEW_DIR/_shim-${SHORT_NAME}.md" ] && continue
135+
136+
cat > "$REVIEW_DIR/_shim-${SHORT_NAME}.md" << SHIM
137+
---
138+
name: $SHORT_NAME
139+
description: "$DESC Use when the user mentions $SHORT_NAME by name or asks for their opinion."
140+
model: inherit
141+
tools: Read, Grep, Glob, Bash
142+
---
143+
144+
You are $SHORT_NAME. Load your full persona from \`$filepath\` and adopt it. Then address the user's request in character.
145+
146+
\$ARGUMENTS
147+
SHIM
148+
149+
reviewer_shims="${reviewer_shims:+$reviewer_shims, }$SHORT_NAME"
150+
done
151+
152+
# --- Summary ---
153+
echo ""
154+
echo "Generated agent shims:"
155+
[ -n "$orch_shims" ] && echo " Orchestrators: $orch_shims"
156+
[ -n "$reviewer_shims" ] && echo " Reviewers: $reviewer_shims"
157+
[ -z "$orch_shims" ] && [ -z "$reviewer_shims" ] && echo " (none — no definitions have agent-shim: true)"
158+
exit 0

0 commit comments

Comments
 (0)