forge-pipeline 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/forge +593 -0
- package/lib/agent.sh +264 -0
- package/lib/phases/00_spec.sh +109 -0
- package/lib/phases/01_plan.sh +83 -0
- package/lib/phases/02_implement.sh +124 -0
- package/lib/phases/03_integrate.sh +162 -0
- package/lib/phases/04_audit.sh +78 -0
- package/lib/phases/05_fix.sh +188 -0
- package/lib/phases/06_finalize.sh +79 -0
- package/lib/prompts.sh +554 -0
- package/lib/utils.sh +223 -0
- package/lib/worktree.sh +82 -0
- package/package.json +20 -0
- package/prompts/architect_spec.md +184 -0
- package/prompts/challenger_review.md +162 -0
- package/prompts/coordinator_final.md +118 -0
- package/prompts/coordinator_plan.md +151 -0
- package/prompts/junior_auditor.md +139 -0
- package/prompts/lead.md +61 -0
- package/prompts/senior_auditor.md +193 -0
- package/prompts/worker.md +143 -0
package/lib/prompts.sh
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ─────────────────────────────────────────────────────────────
|
|
3
|
+
# Forge – prompt generation and template substitution
|
|
4
|
+
# Handles prompt assembly for all agent roles.
|
|
5
|
+
# ─────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
[[ -n "${_PROMPTS_SH_LOADED:-}" ]] && return
|
|
8
|
+
_PROMPTS_SH_LOADED=1
|
|
9
|
+
|
|
10
|
+
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/utils.sh"
|
|
11
|
+
|
|
12
|
+
FORGE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
13
|
+
|
|
14
|
+
# ── Anti-attribution rules (appended to every agent prompt) ──
|
|
15
|
+
|
|
16
|
+
ANTI_ATTRIBUTION_RULES='
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## STRICT RULES — ATTRIBUTION AND COMMIT MESSAGES
|
|
20
|
+
|
|
21
|
+
These rules are NON-NEGOTIABLE and override any other instructions:
|
|
22
|
+
|
|
23
|
+
1. **NEVER mention AI, Claude, Anthropic, LLM, GPT, or any AI assistant** in:
|
|
24
|
+
- Commit messages
|
|
25
|
+
- Code comments
|
|
26
|
+
- Documentation or generated files
|
|
27
|
+
- Variable names, function names, or string literals
|
|
28
|
+
- PR titles, PR descriptions, or branch names
|
|
29
|
+
|
|
30
|
+
2. **Commit messages must look human-written** using conventional commits:
|
|
31
|
+
- `feat: add user authentication endpoints`
|
|
32
|
+
- `fix: resolve race condition in cart service`
|
|
33
|
+
- `refactor: extract validation logic into shared utils`
|
|
34
|
+
- `test: add integration tests for payment flow`
|
|
35
|
+
- `docs: update API documentation`
|
|
36
|
+
|
|
37
|
+
3. **Do NOT add any attribution headers** such as:
|
|
38
|
+
- "Co-Authored-By" with any AI name
|
|
39
|
+
- "Generated by" anything
|
|
40
|
+
- "Created with" any tool name
|
|
41
|
+
- Any similar attribution to automated tools
|
|
42
|
+
|
|
43
|
+
4. **Do NOT reference this pipeline** in any output code, comments, or commits. No mentions of "forge pipeline", "autonomous agents", or "automated coding".
|
|
44
|
+
|
|
45
|
+
5. **Code comments should be natural** — explain the "why", not reference how the code was produced.
|
|
46
|
+
'
|
|
47
|
+
|
|
48
|
+
# ── Augment tools integration ────────────────────────────────
|
|
49
|
+
|
|
50
|
+
get_augment_tools_flag() {
|
|
51
|
+
local config_file="${FORGE_ROOT}/.forge/config.json"
|
|
52
|
+
if [[ ! -f "$config_file" ]]; then
|
|
53
|
+
echo ""
|
|
54
|
+
return
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
local augment_available
|
|
58
|
+
augment_available=$(jq -r '(.augment_available // .AUGMENT_AVAILABLE) // empty' "$config_file" 2>/dev/null)
|
|
59
|
+
|
|
60
|
+
if [[ "$augment_available" == "true" ]]; then
|
|
61
|
+
local tool_name
|
|
62
|
+
tool_name=$(jq -r '(.augment_tool_name // .AUGMENT_TOOL_NAME) // empty' "$config_file" 2>/dev/null)
|
|
63
|
+
if [[ -n "$tool_name" ]]; then
|
|
64
|
+
echo "$tool_name"
|
|
65
|
+
return
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
echo ""
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ── Build allowed tools per role ─────────────────────────────
|
|
73
|
+
|
|
74
|
+
build_allowed_tools() {
|
|
75
|
+
local role="$1"
|
|
76
|
+
local augment_tool
|
|
77
|
+
augment_tool=$(get_augment_tools_flag)
|
|
78
|
+
|
|
79
|
+
local tools=""
|
|
80
|
+
|
|
81
|
+
case "$role" in
|
|
82
|
+
worker)
|
|
83
|
+
tools="Read,Write,Bash"
|
|
84
|
+
;;
|
|
85
|
+
lead)
|
|
86
|
+
tools="Read,Write,Bash"
|
|
87
|
+
;;
|
|
88
|
+
auditor_senior)
|
|
89
|
+
tools="Read,Bash(find),Bash(cat),Bash(grep),Bash(wc),Bash(ls)"
|
|
90
|
+
;;
|
|
91
|
+
auditor_junior)
|
|
92
|
+
tools="Read,Bash(find),Bash(cat),Bash(grep),Bash(ls)"
|
|
93
|
+
;;
|
|
94
|
+
architect)
|
|
95
|
+
tools="Read,Write,Bash(find),Bash(cat),Bash(ls),Bash(head)"
|
|
96
|
+
;;
|
|
97
|
+
challenger)
|
|
98
|
+
tools="Read,Write,Bash(find),Bash(cat),Bash(ls)"
|
|
99
|
+
;;
|
|
100
|
+
coordinator)
|
|
101
|
+
tools="Read,Write,Bash(find),Bash(cat),Bash(ls)"
|
|
102
|
+
;;
|
|
103
|
+
integration)
|
|
104
|
+
tools="Read,Write,Bash"
|
|
105
|
+
;;
|
|
106
|
+
fix)
|
|
107
|
+
tools="Read,Write,Bash"
|
|
108
|
+
;;
|
|
109
|
+
*)
|
|
110
|
+
log_warn "Unknown role '$role' – defaulting to Read,Bash"
|
|
111
|
+
tools="Read,Bash"
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
|
|
115
|
+
if [[ -n "$augment_tool" ]]; then
|
|
116
|
+
tools="${tools},${augment_tool}"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
echo "$tools"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# ── Architect prompt ─────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
generate_architect_prompt() {
|
|
125
|
+
local prompt=""
|
|
126
|
+
|
|
127
|
+
# Base template
|
|
128
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/architect_spec.md" 2>/dev/null)
|
|
129
|
+
prompt+=$'\n\n'
|
|
130
|
+
|
|
131
|
+
# User requirement
|
|
132
|
+
prompt+="## USER REQUIREMENT"$'\n\n'
|
|
133
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/requirement.md" 2>/dev/null)
|
|
134
|
+
prompt+=$'\n\n'
|
|
135
|
+
|
|
136
|
+
# Existing repo structure
|
|
137
|
+
prompt+="## EXISTING REPO STRUCTURE"$'\n\n'
|
|
138
|
+
prompt+='```'$'\n'
|
|
139
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/repo-tree.txt" 2>/dev/null)
|
|
140
|
+
prompt+=$'\n```\n\n'
|
|
141
|
+
|
|
142
|
+
# Existing key files
|
|
143
|
+
prompt+="## EXISTING KEY FILES"$'\n\n'
|
|
144
|
+
prompt+='```'$'\n'
|
|
145
|
+
local key_files
|
|
146
|
+
key_files=$(cd "${FORGE_ROOT}" && cat README.md package.json pyproject.toml Cargo.toml go.mod 2>/dev/null || echo "New project")
|
|
147
|
+
prompt+="$key_files"
|
|
148
|
+
prompt+=$'\n```\n\n'
|
|
149
|
+
|
|
150
|
+
# Instruction
|
|
151
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
152
|
+
prompt+="Write your spec to ${FORGE_ROOT}/.forge/spec/spec.md"$'\n'
|
|
153
|
+
|
|
154
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
155
|
+
|
|
156
|
+
echo "$prompt"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# ── Architect revision prompt ────────────────────────────────
|
|
160
|
+
|
|
161
|
+
generate_architect_revision_prompt() {
|
|
162
|
+
local prompt=""
|
|
163
|
+
|
|
164
|
+
# Base template
|
|
165
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/architect_spec.md" 2>/dev/null)
|
|
166
|
+
prompt+=$'\n\n'
|
|
167
|
+
|
|
168
|
+
prompt+="**NOTE: This is a REVISION pass. Review the challenger's feedback and update your spec accordingly.**"$'\n\n'
|
|
169
|
+
|
|
170
|
+
# Current spec
|
|
171
|
+
prompt+="## YOUR CURRENT SPEC"$'\n\n'
|
|
172
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
173
|
+
prompt+=$'\n\n'
|
|
174
|
+
|
|
175
|
+
# Challenger's review
|
|
176
|
+
prompt+="## CHALLENGER'S REVIEW"$'\n\n'
|
|
177
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/review.json" 2>/dev/null)
|
|
178
|
+
prompt+=$'\n\n'
|
|
179
|
+
|
|
180
|
+
# User requirement
|
|
181
|
+
prompt+="## USER REQUIREMENT"$'\n\n'
|
|
182
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/requirement.md" 2>/dev/null)
|
|
183
|
+
prompt+=$'\n\n'
|
|
184
|
+
|
|
185
|
+
# Existing repo structure
|
|
186
|
+
prompt+="## EXISTING REPO STRUCTURE"$'\n\n'
|
|
187
|
+
prompt+='```'$'\n'
|
|
188
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/repo-tree.txt" 2>/dev/null)
|
|
189
|
+
prompt+=$'\n```\n\n'
|
|
190
|
+
|
|
191
|
+
# Instruction
|
|
192
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
193
|
+
prompt+="Update your spec at ${FORGE_ROOT}/.forge/spec/spec.md addressing the challenger's feedback."$'\n'
|
|
194
|
+
|
|
195
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
196
|
+
|
|
197
|
+
echo "$prompt"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# ── Challenger prompt ────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
generate_challenger_prompt() {
|
|
203
|
+
local prompt=""
|
|
204
|
+
|
|
205
|
+
# Base template
|
|
206
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/challenger_review.md" 2>/dev/null)
|
|
207
|
+
prompt+=$'\n\n'
|
|
208
|
+
|
|
209
|
+
# Original user requirement
|
|
210
|
+
prompt+="## ORIGINAL USER REQUIREMENT"$'\n\n'
|
|
211
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/requirement.md" 2>/dev/null)
|
|
212
|
+
prompt+=$'\n\n'
|
|
213
|
+
|
|
214
|
+
# Architect's spec
|
|
215
|
+
prompt+="## ARCHITECT'S SPEC"$'\n\n'
|
|
216
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
217
|
+
prompt+=$'\n\n'
|
|
218
|
+
|
|
219
|
+
# Existing repo structure
|
|
220
|
+
prompt+="## EXISTING REPO STRUCTURE"$'\n\n'
|
|
221
|
+
prompt+='```'$'\n'
|
|
222
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/repo-tree.txt" 2>/dev/null)
|
|
223
|
+
prompt+=$'\n```\n\n'
|
|
224
|
+
|
|
225
|
+
# Instruction
|
|
226
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
227
|
+
prompt+="Write your review to ${FORGE_ROOT}/.forge/spec/review.json"$'\n'
|
|
228
|
+
|
|
229
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
230
|
+
|
|
231
|
+
echo "$prompt"
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# ── Coordinator prompt ───────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
generate_coordinator_prompt() {
|
|
237
|
+
local prompt=""
|
|
238
|
+
|
|
239
|
+
# Base template
|
|
240
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/coordinator_plan.md" 2>/dev/null)
|
|
241
|
+
prompt+=$'\n\n'
|
|
242
|
+
|
|
243
|
+
# Approved technical spec
|
|
244
|
+
prompt+="## APPROVED TECHNICAL SPEC"$'\n\n'
|
|
245
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
246
|
+
prompt+=$'\n\n'
|
|
247
|
+
|
|
248
|
+
# Original user requirement
|
|
249
|
+
prompt+="## ORIGINAL USER REQUIREMENT"$'\n\n'
|
|
250
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/requirement.md" 2>/dev/null)
|
|
251
|
+
prompt+=$'\n\n'
|
|
252
|
+
|
|
253
|
+
# Repo structure
|
|
254
|
+
prompt+="## REPO STRUCTURE"$'\n\n'
|
|
255
|
+
prompt+='```'$'\n'
|
|
256
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/repo-tree.txt" 2>/dev/null)
|
|
257
|
+
prompt+=$'\n```\n\n'
|
|
258
|
+
|
|
259
|
+
# Existing key files
|
|
260
|
+
prompt+="## EXISTING KEY FILES"$'\n\n'
|
|
261
|
+
prompt+='```'$'\n'
|
|
262
|
+
local key_files
|
|
263
|
+
key_files=$(cd "${FORGE_ROOT}" && cat README.md package.json pyproject.toml Cargo.toml go.mod 2>/dev/null || echo "New project")
|
|
264
|
+
prompt+="$key_files"
|
|
265
|
+
prompt+=$'\n```\n\n'
|
|
266
|
+
|
|
267
|
+
# JSON schema for plan.json
|
|
268
|
+
prompt+="## PLAN JSON SCHEMA"$'\n\n'
|
|
269
|
+
prompt+='The plan.json file MUST follow this exact schema:'$'\n\n'
|
|
270
|
+
prompt+='```json'$'\n'
|
|
271
|
+
prompt+='{
|
|
272
|
+
"project_type": "greenfield | incremental",
|
|
273
|
+
"leads": [
|
|
274
|
+
{
|
|
275
|
+
"name": "lead-<module-name>",
|
|
276
|
+
"module": "<module-name>",
|
|
277
|
+
"description": "<what this lead is responsible for>",
|
|
278
|
+
"dependencies": ["<other lead names this depends on, if any>"],
|
|
279
|
+
"workers": [
|
|
280
|
+
{
|
|
281
|
+
"name": "worker-<task-name>",
|
|
282
|
+
"task": "<concise task description>",
|
|
283
|
+
"files": ["<list of files this worker will create or modify>"],
|
|
284
|
+
"spec_excerpt": "<relevant portion of the spec for this task>"
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
}
|
|
288
|
+
]
|
|
289
|
+
}'
|
|
290
|
+
prompt+=$'\n```\n\n'
|
|
291
|
+
|
|
292
|
+
# Instruction
|
|
293
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
294
|
+
prompt+="Write your implementation plan to ${FORGE_ROOT}/.forge/plan.json"$'\n'
|
|
295
|
+
|
|
296
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
297
|
+
|
|
298
|
+
echo "$prompt"
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
# ── Lead prompt ──────────────────────────────────────────────
|
|
302
|
+
|
|
303
|
+
generate_lead_prompt() {
|
|
304
|
+
local lead_name="$1"
|
|
305
|
+
local lead_json="$2"
|
|
306
|
+
|
|
307
|
+
local module_name
|
|
308
|
+
module_name=$(echo "$lead_json" | jq -r '.module // .name' 2>/dev/null)
|
|
309
|
+
|
|
310
|
+
local workers_json
|
|
311
|
+
workers_json=$(echo "$lead_json" | jq -c '.workers // []' 2>/dev/null)
|
|
312
|
+
|
|
313
|
+
local prompt=""
|
|
314
|
+
|
|
315
|
+
# Base template
|
|
316
|
+
local template
|
|
317
|
+
template=$(cat "${FORGE_DIR}/prompts/lead.md" 2>/dev/null)
|
|
318
|
+
|
|
319
|
+
if [[ -n "$template" ]]; then
|
|
320
|
+
# Perform substitutions
|
|
321
|
+
template="${template//\{MODULE_NAME\}/$module_name}"
|
|
322
|
+
template="${template//\{WORKER_DEFINITIONS_FROM_PLAN\}/$workers_json}"
|
|
323
|
+
prompt+="$template"
|
|
324
|
+
else
|
|
325
|
+
prompt+="# Lead Agent: ${lead_name}"$'\n'
|
|
326
|
+
prompt+="Module: ${module_name}"$'\n\n'
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
prompt+=$'\n\n'
|
|
330
|
+
|
|
331
|
+
# Spec content for reference
|
|
332
|
+
prompt+="## TECHNICAL SPEC"$'\n\n'
|
|
333
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
334
|
+
prompt+=$'\n\n'
|
|
335
|
+
|
|
336
|
+
# Worker definitions
|
|
337
|
+
prompt+="## WORKER DEFINITIONS"$'\n\n'
|
|
338
|
+
prompt+='```json'$'\n'
|
|
339
|
+
prompt+="$workers_json"
|
|
340
|
+
prompt+=$'\n```\n\n'
|
|
341
|
+
|
|
342
|
+
# Workflow instructions
|
|
343
|
+
prompt+="## DETAILED WORKFLOW INSTRUCTIONS"$'\n\n'
|
|
344
|
+
prompt+="You are the lead for module **${module_name}**. You are running as a Claude Code instance inside a git worktree at \`${FORGE_ROOT}/.forge/worktrees/${lead_name}\`. Follow these steps exactly:"$'\n\n'
|
|
345
|
+
|
|
346
|
+
prompt+="### Step 1: Create worktrees for each worker"$'\n'
|
|
347
|
+
prompt+="For each worker in your workers list, create a git worktree branching off YOUR lead branch:"$'\n'
|
|
348
|
+
prompt+='```bash'$'\n'
|
|
349
|
+
prompt+="cd ${FORGE_ROOT}"$'\n'
|
|
350
|
+
prompt+="git worktree add ${FORGE_ROOT}/.forge/worktrees/<worker-name> -b forge/<worker-name> forge/${lead_name}"$'\n'
|
|
351
|
+
prompt+='```'$'\n\n'
|
|
352
|
+
|
|
353
|
+
prompt+="### Step 2: Write task spec files"$'\n'
|
|
354
|
+
prompt+="For each worker, write a detailed task specification as a markdown file. Include the task description, file list, and relevant spec excerpts from the worker definitions above."$'\n'
|
|
355
|
+
prompt+='```bash'$'\n'
|
|
356
|
+
prompt+="mkdir -p ${FORGE_ROOT}/.forge/tasks"$'\n'
|
|
357
|
+
prompt+="# Write detailed task to ${FORGE_ROOT}/.forge/tasks/<worker-name>.md"$'\n'
|
|
358
|
+
prompt+='```'$'\n'
|
|
359
|
+
prompt+="The task file should contain everything the worker needs: what to build, which files to create/modify, relevant API contracts, data models, conventions to follow, and a reminder to commit changes when done."$'\n\n'
|
|
360
|
+
|
|
361
|
+
prompt+="### Step 3: Spawn workers via tmux"$'\n'
|
|
362
|
+
prompt+="Launch each worker as a separate Claude Code instance in its own tmux session. IMPORTANT: Use \`forge-\` prefix for session names."$'\n'
|
|
363
|
+
prompt+='```bash'$'\n'
|
|
364
|
+
prompt+="# For each worker:"$'\n'
|
|
365
|
+
prompt+="touch ${FORGE_ROOT}/.forge/status/<worker-name>.expected"$'\n'
|
|
366
|
+
prompt+="tmux new-session -d -s \"forge-<worker-name>\" \\"$'\n'
|
|
367
|
+
prompt+=" \"cd ${FORGE_ROOT}/.forge/worktrees/<worker-name> && claude -p \\\"\\\$(cat ${FORGE_ROOT}/.forge/tasks/<worker-name>.md)\\\" --allowedTools 'Read,Write,Bash' 2>&1 | tee ${FORGE_ROOT}/.forge/logs/<worker-name>.log; echo done > ${FORGE_ROOT}/.forge/status/<worker-name>.done\""$'\n'
|
|
368
|
+
prompt+='```'$'\n\n'
|
|
369
|
+
|
|
370
|
+
prompt+="### Step 4: Poll for worker completion"$'\n'
|
|
371
|
+
prompt+="Monitor workers by checking for .done files. Poll every 30 seconds:"$'\n'
|
|
372
|
+
prompt+='```bash'$'\n'
|
|
373
|
+
prompt+="# Loop until all workers are done"$'\n'
|
|
374
|
+
prompt+="while true; do"$'\n'
|
|
375
|
+
prompt+=" done_count=\$(ls ${FORGE_ROOT}/.forge/status/worker-*.done 2>/dev/null | wc -l | tr -d ' ')"$'\n'
|
|
376
|
+
prompt+=" expected_count=\$(ls ${FORGE_ROOT}/.forge/status/worker-*.expected 2>/dev/null | wc -l | tr -d ' ')"$'\n'
|
|
377
|
+
prompt+=" echo \"Workers: \${done_count}/\${expected_count} done\""$'\n'
|
|
378
|
+
prompt+=" [ \"\$done_count\" -ge \"\$expected_count\" ] && break"$'\n'
|
|
379
|
+
prompt+=" sleep 30"$'\n'
|
|
380
|
+
prompt+="done"$'\n'
|
|
381
|
+
prompt+='```'$'\n'
|
|
382
|
+
prompt+="Also check if any tmux session died without creating a .done file — if so, the worker crashed. You may respawn it (max 2 retries)."$'\n\n'
|
|
383
|
+
|
|
384
|
+
prompt+="### Step 5: Review each worker's output"$'\n'
|
|
385
|
+
prompt+="For each completed worker, review its changes:"$'\n'
|
|
386
|
+
prompt+='```bash'$'\n'
|
|
387
|
+
prompt+="cd ${FORGE_ROOT}/.forge/worktrees/<worker-name>"$'\n'
|
|
388
|
+
prompt+="git log --oneline forge/${lead_name}..HEAD"$'\n'
|
|
389
|
+
prompt+="git diff forge/${lead_name}..HEAD"$'\n'
|
|
390
|
+
prompt+='```'$'\n'
|
|
391
|
+
prompt+="Check: Does the code match the task spec? Is it well-structured? Are there obvious bugs?"$'\n'
|
|
392
|
+
prompt+="If a worker's output is poor, write fix instructions and respawn (max 2 retries per worker)."$'\n\n'
|
|
393
|
+
|
|
394
|
+
prompt+="### Step 6: Merge all worker branches into your lead branch"$'\n'
|
|
395
|
+
prompt+="After all workers pass review, merge them sequentially:"$'\n'
|
|
396
|
+
prompt+='```bash'$'\n'
|
|
397
|
+
prompt+="cd ${FORGE_ROOT}/.forge/worktrees/${lead_name}"$'\n'
|
|
398
|
+
prompt+="git merge --no-ff forge/<worker-name> -m \"Merge <worker-name> implementation\""$'\n'
|
|
399
|
+
prompt+="# Repeat for each worker"$'\n'
|
|
400
|
+
prompt+='```'$'\n'
|
|
401
|
+
prompt+="Resolve any merge conflicts if they occur (they should be rare since workers own exclusive files)."$'\n\n'
|
|
402
|
+
|
|
403
|
+
prompt+="### Step 7: Write review and signal completion"$'\n'
|
|
404
|
+
prompt+='```bash'$'\n'
|
|
405
|
+
prompt+="# Write a review summary"$'\n'
|
|
406
|
+
prompt+="cat > ${FORGE_ROOT}/.forge/reviews/${lead_name}-review.json << 'EOF'"$'\n'
|
|
407
|
+
prompt+='{"lead": "'"${lead_name}"'", "module": "'"${module_name}"'", "status": "complete", "workers_merged": [...], "issues": [...]}'$'\n'
|
|
408
|
+
prompt+="EOF"$'\n\n'
|
|
409
|
+
prompt+="# Signal completion"$'\n'
|
|
410
|
+
prompt+="echo \"done\" > ${FORGE_ROOT}/.forge/status/${lead_name}.done"$'\n'
|
|
411
|
+
prompt+='```'$'\n\n'
|
|
412
|
+
|
|
413
|
+
prompt+="## FORGE_ROOT"$'\n\n'
|
|
414
|
+
prompt+="All absolute paths use: \`${FORGE_ROOT}\`"$'\n'
|
|
415
|
+
prompt+="Your worktree is at: \`${FORGE_ROOT}/.forge/worktrees/${lead_name}\`"$'\n'
|
|
416
|
+
prompt+="Your branch is: \`forge/${lead_name}\`"$'\n'
|
|
417
|
+
|
|
418
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
419
|
+
|
|
420
|
+
echo "$prompt"
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
# ── Worker prompt ────────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
generate_worker_prompt() {
|
|
426
|
+
local worker_name="$1"
|
|
427
|
+
local task_description="$2"
|
|
428
|
+
local file_list="$3"
|
|
429
|
+
local spec_excerpt="$4"
|
|
430
|
+
|
|
431
|
+
local prompt=""
|
|
432
|
+
|
|
433
|
+
# Base template
|
|
434
|
+
local template
|
|
435
|
+
template=$(cat "${FORGE_DIR}/prompts/worker.md" 2>/dev/null)
|
|
436
|
+
|
|
437
|
+
if [[ -n "$template" ]]; then
|
|
438
|
+
template="${template//\{TASK_DESCRIPTION\}/$task_description}"
|
|
439
|
+
template="${template//\{FILE_LIST\}/$file_list}"
|
|
440
|
+
template="${template//\{SPEC_EXCERPT_RELEVANT_TO_THIS_TASK\}/$spec_excerpt}"
|
|
441
|
+
prompt+="$template"
|
|
442
|
+
else
|
|
443
|
+
prompt+="# Worker Agent: ${worker_name}"$'\n\n'
|
|
444
|
+
prompt+="## TASK DESCRIPTION"$'\n\n'
|
|
445
|
+
prompt+="$task_description"$'\n\n'
|
|
446
|
+
prompt+="## FILES TO WORK ON"$'\n\n'
|
|
447
|
+
prompt+="$file_list"$'\n\n'
|
|
448
|
+
prompt+="## RELEVANT SPEC EXCERPT"$'\n\n'
|
|
449
|
+
prompt+="$spec_excerpt"$'\n\n'
|
|
450
|
+
fi
|
|
451
|
+
|
|
452
|
+
prompt+=$'\n\n'
|
|
453
|
+
|
|
454
|
+
# Completion instruction
|
|
455
|
+
prompt+="## COMPLETION"$'\n\n'
|
|
456
|
+
prompt+="When done, commit all changes and create the completion marker:"$'\n'
|
|
457
|
+
prompt+='```bash'$'\n'
|
|
458
|
+
prompt+="touch ${FORGE_ROOT}/.forge/status/${worker_name}.done"$'\n'
|
|
459
|
+
prompt+='```'$'\n'
|
|
460
|
+
|
|
461
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
462
|
+
|
|
463
|
+
echo "$prompt"
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
# ── Senior auditor prompt ───────────────────────────────────
|
|
467
|
+
|
|
468
|
+
generate_senior_auditor_prompt() {
|
|
469
|
+
local prompt=""
|
|
470
|
+
|
|
471
|
+
# Base template
|
|
472
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/senior_auditor.md" 2>/dev/null)
|
|
473
|
+
prompt+=$'\n\n'
|
|
474
|
+
|
|
475
|
+
# Context
|
|
476
|
+
prompt+="## CONTEXT"$'\n\n'
|
|
477
|
+
prompt+="You are auditing the fully integrated codebase after all modules have been merged."$'\n'
|
|
478
|
+
prompt+="Review the entire project for correctness, consistency, and completeness."$'\n\n'
|
|
479
|
+
|
|
480
|
+
# FORGE_ROOT
|
|
481
|
+
prompt+="## FORGE_ROOT"$'\n\n'
|
|
482
|
+
prompt+="All absolute paths use: ${FORGE_ROOT}"$'\n\n'
|
|
483
|
+
|
|
484
|
+
# Spec for reference
|
|
485
|
+
prompt+="## APPROVED SPEC"$'\n\n'
|
|
486
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
487
|
+
prompt+=$'\n\n'
|
|
488
|
+
|
|
489
|
+
# Plan for reference
|
|
490
|
+
prompt+="## IMPLEMENTATION PLAN"$'\n\n'
|
|
491
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/plan.json" 2>/dev/null)
|
|
492
|
+
prompt+=$'\n\n'
|
|
493
|
+
|
|
494
|
+
# Instruction
|
|
495
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
496
|
+
prompt+="Write the consolidated audit report to ${FORGE_ROOT}/.forge/audit/consolidated-audit.json"$'\n'
|
|
497
|
+
prompt+="Write the audit plan to ${FORGE_ROOT}/.forge/audit/senior-audit-plan.json"$'\n'
|
|
498
|
+
prompt+="Each junior auditor should write their findings to ${FORGE_ROOT}/.forge/audit/junior-{name}.json"$'\n'
|
|
499
|
+
|
|
500
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
501
|
+
|
|
502
|
+
echo "$prompt"
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
# ── Final report prompt ─────────────────────────────────────
|
|
506
|
+
|
|
507
|
+
generate_final_report_prompt() {
|
|
508
|
+
local user_prompt="$1"
|
|
509
|
+
|
|
510
|
+
local prompt=""
|
|
511
|
+
|
|
512
|
+
# Base template
|
|
513
|
+
prompt+=$(cat "${FORGE_DIR}/prompts/coordinator_final.md" 2>/dev/null)
|
|
514
|
+
prompt+=$'\n\n'
|
|
515
|
+
|
|
516
|
+
# Original task
|
|
517
|
+
prompt+="## ORIGINAL TASK"$'\n\n'
|
|
518
|
+
prompt+="$user_prompt"$'\n\n'
|
|
519
|
+
|
|
520
|
+
# Approved spec
|
|
521
|
+
prompt+="## APPROVED SPEC"$'\n\n'
|
|
522
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/spec/spec.md" 2>/dev/null)
|
|
523
|
+
prompt+=$'\n\n'
|
|
524
|
+
|
|
525
|
+
# Plan
|
|
526
|
+
prompt+="## IMPLEMENTATION PLAN"$'\n\n'
|
|
527
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/plan.json" 2>/dev/null)
|
|
528
|
+
prompt+=$'\n\n'
|
|
529
|
+
|
|
530
|
+
# Lead reviews
|
|
531
|
+
prompt+="## LEAD REVIEWS"$'\n\n'
|
|
532
|
+
local lead_reviews
|
|
533
|
+
lead_reviews=$(cat "${FORGE_ROOT}"/.forge/reviews/*.json 2>/dev/null || echo "No lead reviews available")
|
|
534
|
+
prompt+="$lead_reviews"$'\n\n'
|
|
535
|
+
|
|
536
|
+
# Audit results
|
|
537
|
+
prompt+="## AUDIT RESULTS"$'\n\n'
|
|
538
|
+
prompt+=$(cat "${FORGE_ROOT}/.forge/audit/consolidated-audit.json" 2>/dev/null || echo "No audit results available")
|
|
539
|
+
prompt+=$'\n\n'
|
|
540
|
+
|
|
541
|
+
# Fix reports
|
|
542
|
+
prompt+="## FIX REPORTS"$'\n\n'
|
|
543
|
+
local fix_reports
|
|
544
|
+
fix_reports=$(cat "${FORGE_ROOT}"/.forge/fixes/*.json 2>/dev/null || echo "No fix reports available")
|
|
545
|
+
prompt+="$fix_reports"$'\n\n'
|
|
546
|
+
|
|
547
|
+
# Instruction
|
|
548
|
+
prompt+="## INSTRUCTION"$'\n\n'
|
|
549
|
+
prompt+="Write the final project report to ${FORGE_ROOT}/.forge/DONE.md"$'\n'
|
|
550
|
+
|
|
551
|
+
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
552
|
+
|
|
553
|
+
echo "$prompt"
|
|
554
|
+
}
|