@unimatrix27/ralph-harness 1.0.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/CONTRIBUTING.md +89 -0
- package/README.md +401 -0
- package/dist/bin/ralph-bootstrap-aws.d.ts +3 -0
- package/dist/bin/ralph-bootstrap-aws.d.ts.map +1 -0
- package/dist/bin/ralph-bootstrap-aws.js +43 -0
- package/dist/bin/ralph-bootstrap-aws.js.map +1 -0
- package/dist/bin/ralph-fire.d.ts +3 -0
- package/dist/bin/ralph-fire.d.ts.map +1 -0
- package/dist/bin/ralph-fire.js +59 -0
- package/dist/bin/ralph-fire.js.map +1 -0
- package/dist/bin/ralph-gsm.d.ts +3 -0
- package/dist/bin/ralph-gsm.d.ts.map +1 -0
- package/dist/bin/ralph-gsm.js +93 -0
- package/dist/bin/ralph-gsm.js.map +1 -0
- package/dist/bin/ralph-orchestrate.d.ts +3 -0
- package/dist/bin/ralph-orchestrate.d.ts.map +1 -0
- package/dist/bin/ralph-orchestrate.js +20 -0
- package/dist/bin/ralph-orchestrate.js.map +1 -0
- package/dist/bin/ralph-sync-credential.d.ts +3 -0
- package/dist/bin/ralph-sync-credential.d.ts.map +1 -0
- package/dist/bin/ralph-sync-credential.js +44 -0
- package/dist/bin/ralph-sync-credential.js.map +1 -0
- package/dist/bin/ralph-sync-github-pat.d.ts +3 -0
- package/dist/bin/ralph-sync-github-pat.d.ts.map +1 -0
- package/dist/bin/ralph-sync-github-pat.js +93 -0
- package/dist/bin/ralph-sync-github-pat.js.map +1 -0
- package/dist/bin/ralph-tail-logs.d.ts +3 -0
- package/dist/bin/ralph-tail-logs.d.ts.map +1 -0
- package/dist/bin/ralph-tail-logs.js +72 -0
- package/dist/bin/ralph-tail-logs.js.map +1 -0
- package/dist/bin/ralph-validate-config.d.ts +3 -0
- package/dist/bin/ralph-validate-config.d.ts.map +1 -0
- package/dist/bin/ralph-validate-config.js +41 -0
- package/dist/bin/ralph-validate-config.js.map +1 -0
- package/dist/lib/aws-bootstrap.d.ts +53 -0
- package/dist/lib/aws-bootstrap.d.ts.map +1 -0
- package/dist/lib/aws-bootstrap.js +438 -0
- package/dist/lib/aws-bootstrap.js.map +1 -0
- package/dist/lib/aws-clients.d.ts +17 -0
- package/dist/lib/aws-clients.d.ts.map +1 -0
- package/dist/lib/aws-clients.js +25 -0
- package/dist/lib/aws-clients.js.map +1 -0
- package/dist/lib/claude-runner.d.ts +21 -0
- package/dist/lib/claude-runner.d.ts.map +1 -0
- package/dist/lib/claude-runner.js +101 -0
- package/dist/lib/claude-runner.js.map +1 -0
- package/dist/lib/credential-syncer.d.ts +27 -0
- package/dist/lib/credential-syncer.d.ts.map +1 -0
- package/dist/lib/credential-syncer.js +116 -0
- package/dist/lib/credential-syncer.js.map +1 -0
- package/dist/lib/ec2-orchestrator.d.ts +38 -0
- package/dist/lib/ec2-orchestrator.d.ts.map +1 -0
- package/dist/lib/ec2-orchestrator.js +469 -0
- package/dist/lib/ec2-orchestrator.js.map +1 -0
- package/dist/lib/env-loader.d.ts +18 -0
- package/dist/lib/env-loader.d.ts.map +1 -0
- package/dist/lib/env-loader.js +120 -0
- package/dist/lib/env-loader.js.map +1 -0
- package/dist/lib/fire-launcher.d.ts +59 -0
- package/dist/lib/fire-launcher.d.ts.map +1 -0
- package/dist/lib/fire-launcher.js +320 -0
- package/dist/lib/fire-launcher.js.map +1 -0
- package/dist/lib/gh-runner.d.ts +13 -0
- package/dist/lib/gh-runner.d.ts.map +1 -0
- package/dist/lib/gh-runner.js +50 -0
- package/dist/lib/gh-runner.js.map +1 -0
- package/dist/lib/github-state-mutator.d.ts +11 -0
- package/dist/lib/github-state-mutator.d.ts.map +1 -0
- package/dist/lib/github-state-mutator.js +179 -0
- package/dist/lib/github-state-mutator.js.map +1 -0
- package/dist/lib/phase-result-schemas.d.ts +88 -0
- package/dist/lib/phase-result-schemas.d.ts.map +1 -0
- package/dist/lib/phase-result-schemas.js +180 -0
- package/dist/lib/phase-result-schemas.js.map +1 -0
- package/dist/lib/post-hoc-agent-stuck-checker.d.ts +26 -0
- package/dist/lib/post-hoc-agent-stuck-checker.d.ts.map +1 -0
- package/dist/lib/post-hoc-agent-stuck-checker.js +142 -0
- package/dist/lib/post-hoc-agent-stuck-checker.js.map +1 -0
- package/dist/lib/prompt-renderer.d.ts +4 -0
- package/dist/lib/prompt-renderer.d.ts.map +1 -0
- package/dist/lib/prompt-renderer.js +30 -0
- package/dist/lib/prompt-renderer.js.map +1 -0
- package/dist/lib/security-runner.d.ts +7 -0
- package/dist/lib/security-runner.d.ts.map +1 -0
- package/dist/lib/security-runner.js +53 -0
- package/dist/lib/security-runner.js.map +1 -0
- package/dist/lib/structured-log-emitter.d.ts +53 -0
- package/dist/lib/structured-log-emitter.d.ts.map +1 -0
- package/dist/lib/structured-log-emitter.js +122 -0
- package/dist/lib/structured-log-emitter.js.map +1 -0
- package/dist/lib/target-config-schema.d.ts +28 -0
- package/dist/lib/target-config-schema.d.ts.map +1 -0
- package/dist/lib/target-config-schema.js +157 -0
- package/dist/lib/target-config-schema.js.map +1 -0
- package/dist/lib/user-data-renderer.d.ts +20 -0
- package/dist/lib/user-data-renderer.d.ts.map +1 -0
- package/dist/lib/user-data-renderer.js +75 -0
- package/dist/lib/user-data-renderer.js.map +1 -0
- package/lib/cloud-init/system-setup.sh +338 -0
- package/package.json +55 -0
- package/prompts/discovery.md +182 -0
- package/prompts/implementation.md +161 -0
- package/prompts/review.md +135 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# ralph-harness — discovery call
|
|
2
|
+
|
|
3
|
+
You are running on a throwaway EC2 worker, in a fresh clone of the target
|
|
4
|
+
GitHub repository. Your job is **discovery**: pick the single highest-priority
|
|
5
|
+
open issue that is ready for an autonomous agent, OR decide that no work is
|
|
6
|
+
ready right now. You will not write code in this call — only inspect state and
|
|
7
|
+
emit a structured decision.
|
|
8
|
+
|
|
9
|
+
This prompt is generic. Every target-specific value comes from runtime
|
|
10
|
+
substitution and the surfaced target context below; do not hard-code anything
|
|
11
|
+
about the target.
|
|
12
|
+
|
|
13
|
+
## Inputs
|
|
14
|
+
|
|
15
|
+
- Target repo: `{{RALPH_TARGET_REPO}}`
|
|
16
|
+
- Default branch: `{{RALPH_DEFAULT_BRANCH}}`
|
|
17
|
+
- Working directory (fresh clone, on default branch): `{{RALPH_WORK_DIR}}`
|
|
18
|
+
- Build command (informational): `{{RALPH_BUILD_CMD}}`
|
|
19
|
+
- Test command (informational): `{{RALPH_TEST_CMD}}`
|
|
20
|
+
- Branch prefix (informational): `{{RALPH_BRANCH_PREFIX}}`
|
|
21
|
+
|
|
22
|
+
You have `gh` authenticated against the target repo. You have `jq`. You may
|
|
23
|
+
use the `serena`, `morph-mcp`, `context7`, `github`, and
|
|
24
|
+
`sequential-thinking` MCPs. You do NOT have a memory MCP — every iteration
|
|
25
|
+
starts with fresh context, and that is intentional.
|
|
26
|
+
|
|
27
|
+
## Output contract — you MUST write all four files
|
|
28
|
+
|
|
29
|
+
Write every file under `/tmp/ralph/`. Create the directory if missing
|
|
30
|
+
(`mkdir -p /tmp/ralph`). Use `jq -n` or `cat <<EOF` style — never echo a
|
|
31
|
+
secret, never include a token in any file.
|
|
32
|
+
|
|
33
|
+
1. `/tmp/ralph/decision.json` — the decision itself. Exactly one of three
|
|
34
|
+
shapes:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{"status": "PICKED", "issue": <int>, "reasoning": "<≤500 chars>"}
|
|
38
|
+
{"status": "ALL_BLOCKED", "reasoning": "<≤500 chars>"}
|
|
39
|
+
{"status": "NONE", "reasoning": "<≤500 chars>"}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`status=NONE` means there are zero open `ready-for-agent` candidates
|
|
43
|
+
after the `[log] *` filter. `status=ALL_BLOCKED` means every candidate
|
|
44
|
+
has at least one unsatisfied blocker. `status=PICKED` requires `issue`
|
|
45
|
+
to be the integer issue number you chose.
|
|
46
|
+
|
|
47
|
+
2. `/tmp/ralph/issue.json` — the full `gh` JSON payload of the picked
|
|
48
|
+
issue (or `{}` for `NONE` / `ALL_BLOCKED`). Use exactly:
|
|
49
|
+
|
|
50
|
+
gh issue view <n> --repo {{RALPH_TARGET_REPO}} \
|
|
51
|
+
--json number,title,body,labels,milestone,url,author,state \
|
|
52
|
+
> /tmp/ralph/issue.json
|
|
53
|
+
|
|
54
|
+
3. `/tmp/ralph/crafted-prompt.md` — the implementation prompt the next
|
|
55
|
+
claude call will receive. See "Crafting the impl prompt" below. For
|
|
56
|
+
`NONE` / `ALL_BLOCKED`, write a one-line file explaining the
|
|
57
|
+
non-pick.
|
|
58
|
+
|
|
59
|
+
4. `/tmp/ralph/milestone-log.json` — pointer to the cross-iteration log
|
|
60
|
+
issue:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{"milestone": "<name>", "log_issue": <int>}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
If the picked issue has no milestone, set `milestone` to the empty
|
|
67
|
+
string and `log_issue` to `null` and skip the find-or-create step.
|
|
68
|
+
For `NONE` / `ALL_BLOCKED`, write `{}`.
|
|
69
|
+
|
|
70
|
+
## Procedure
|
|
71
|
+
|
|
72
|
+
### 1. List candidates
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
gh issue list --repo {{RALPH_TARGET_REPO}} \
|
|
76
|
+
--state open --label ready-for-agent \
|
|
77
|
+
--json number,title,body,labels,milestone,url \
|
|
78
|
+
--limit 100
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Drop any candidate whose title starts with `[log] ` (literal prefix —
|
|
82
|
+
case-sensitive, exact match including the trailing space). The harness's
|
|
83
|
+
own milestone-log issues carry that prefix and must never be picked.
|
|
84
|
+
|
|
85
|
+
If the post-filter list is empty, write `decision.json` with
|
|
86
|
+
`status=NONE`, write the placeholder files for the other three outputs,
|
|
87
|
+
and stop.
|
|
88
|
+
|
|
89
|
+
### 2. Parse `## Blocked by` and verify dependencies
|
|
90
|
+
|
|
91
|
+
For each candidate, parse the `## Blocked by` heading in the body, if
|
|
92
|
+
present. Each line under that heading should reference a blocker as
|
|
93
|
+
`#<n>` (one per line; ignore blank lines and bullet markers). If the
|
|
94
|
+
heading is absent, the candidate has zero blockers.
|
|
95
|
+
|
|
96
|
+
A candidate is **eligible** only if every referenced blocker satisfies
|
|
97
|
+
BOTH:
|
|
98
|
+
|
|
99
|
+
- the blocker issue is `state == CLOSED`
|
|
100
|
+
- the blocker has at least one merged closing PR (cross-reference via
|
|
101
|
+
`gh issue view <n> --json closedByPullRequestsReferences` and check
|
|
102
|
+
that some PR in that list has `state == MERGED`)
|
|
103
|
+
|
|
104
|
+
If a referenced blocker cannot be found at all, treat it as unsatisfied
|
|
105
|
+
(do not silently ignore typos).
|
|
106
|
+
|
|
107
|
+
If no candidate is eligible, write `decision.json` with
|
|
108
|
+
`status=ALL_BLOCKED` and stop.
|
|
109
|
+
|
|
110
|
+
### 3. Judge priority
|
|
111
|
+
|
|
112
|
+
Among eligible candidates, pick exactly one. Weigh:
|
|
113
|
+
|
|
114
|
+
- issue body content (clarity of acceptance criteria, scope size,
|
|
115
|
+
apparent risk)
|
|
116
|
+
- milestone alignment (issues attached to the earliest-due open
|
|
117
|
+
milestone outrank issues on later or no milestones)
|
|
118
|
+
- explicit `priority/*` or severity labels if present
|
|
119
|
+
|
|
120
|
+
Tie-break: lowest issue number wins (oldest first).
|
|
121
|
+
|
|
122
|
+
### 4. Surface target conventions into the impl prompt
|
|
123
|
+
|
|
124
|
+
The implementation call (next slice) needs to follow the target repo's
|
|
125
|
+
conventions. Read these files from `{{RALPH_WORK_DIR}}` if they exist —
|
|
126
|
+
treat each as best-effort, missing files are fine:
|
|
127
|
+
|
|
128
|
+
- `CLAUDE.md`
|
|
129
|
+
- `AGENTS.md`
|
|
130
|
+
- `CONTEXT.md`
|
|
131
|
+
- any file under `docs/adr/` (architecture decision records)
|
|
132
|
+
|
|
133
|
+
Quote the salient sections verbatim into the crafted impl prompt under a
|
|
134
|
+
clearly-labeled "Target conventions" section. Do not summarize away
|
|
135
|
+
material the impl call will need (commit message style, branch naming
|
|
136
|
+
rules, build/test gotchas, do-not-touch directories).
|
|
137
|
+
|
|
138
|
+
### 5. Find-or-create the milestone log issue
|
|
139
|
+
|
|
140
|
+
If the picked issue has a milestone, find or create
|
|
141
|
+
`[log] <milestone>` (label `meta:milestone-log`) and record the issue
|
|
142
|
+
number in `milestone-log.json`. The orchestrator ships a helper —
|
|
143
|
+
`gsm::find_or_create_milestone_log_issue` — but you can run the
|
|
144
|
+
equivalent `gh` calls directly. Idempotent: existing log issue with
|
|
145
|
+
that exact title is reused.
|
|
146
|
+
|
|
147
|
+
### 6. Craft the impl prompt
|
|
148
|
+
|
|
149
|
+
Write `/tmp/ralph/crafted-prompt.md`. Include, in this order:
|
|
150
|
+
|
|
151
|
+
1. Picked issue: number, title, URL, full body, label list, milestone.
|
|
152
|
+
2. Acceptance criteria (extracted verbatim from the issue body if a
|
|
153
|
+
`## Acceptance criteria` or similar heading is present).
|
|
154
|
+
3. Suggested branch name: `{{RALPH_BRANCH_PREFIX}}/<n>-<slug>` where
|
|
155
|
+
`<slug>` is a short kebab-case form of the issue title (≤40 chars,
|
|
156
|
+
ASCII alnum + dashes).
|
|
157
|
+
4. Build command and test command (from the inputs above).
|
|
158
|
+
5. Default branch (PR base): `{{RALPH_DEFAULT_BRANCH}}`.
|
|
159
|
+
6. Target conventions section (from step 4).
|
|
160
|
+
7. Recent caveman log entries from the milestone-log issue (if any) —
|
|
161
|
+
fetch the last 20 comments and quote them verbatim.
|
|
162
|
+
8. The literal line `Closes #<n>` so the impl call can paste it into
|
|
163
|
+
the PR body.
|
|
164
|
+
|
|
165
|
+
Keep the impl prompt focused on what the implementation call needs —
|
|
166
|
+
not a transcript of your discovery work.
|
|
167
|
+
|
|
168
|
+
{{PROMPT_EXTENSION}}
|
|
169
|
+
|
|
170
|
+
## Final instructions
|
|
171
|
+
|
|
172
|
+
- Do not open a PR, do not push a branch, do not edit any file under
|
|
173
|
+
`{{RALPH_WORK_DIR}}`. This call is read-only on the target's working
|
|
174
|
+
tree.
|
|
175
|
+
- Do not write anything to stdout that you wouldn't want grepped from
|
|
176
|
+
CloudWatch — emit a short status line at the very end summarizing the
|
|
177
|
+
decision (e.g. `discovery: picked #42`, `discovery: NONE`,
|
|
178
|
+
`discovery: ALL_BLOCKED`).
|
|
179
|
+
- All four output files MUST exist when you exit, even if the decision
|
|
180
|
+
is `NONE` or `ALL_BLOCKED`. The orchestrator branches on
|
|
181
|
+
`decision.json.status` and will fail the run if any of the four files
|
|
182
|
+
is missing.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# ralph-harness — implementation call
|
|
2
|
+
|
|
3
|
+
You are running on a throwaway EC2 worker, in a fresh clone of the
|
|
4
|
+
target GitHub repository. The discovery call already picked one open
|
|
5
|
+
`ready-for-agent` issue and wrote the crafted context (issue body,
|
|
6
|
+
acceptance criteria, target conventions, recent caveman log entries) at
|
|
7
|
+
the bottom of this prompt under "Crafted context from discovery". Your
|
|
8
|
+
job in this call is to **implement the picked issue end-to-end on a
|
|
9
|
+
fresh branch and open a PR**.
|
|
10
|
+
|
|
11
|
+
This prompt is generic. Every target-specific value comes from runtime
|
|
12
|
+
substitution and the crafted context; do not hard-code anything about
|
|
13
|
+
the target.
|
|
14
|
+
|
|
15
|
+
## Inputs
|
|
16
|
+
|
|
17
|
+
- Target repo: `{{RALPH_TARGET_REPO}}`
|
|
18
|
+
- Default branch (PR base): `{{RALPH_DEFAULT_BRANCH}}`
|
|
19
|
+
- Working directory (fresh clone, on default branch): `{{RALPH_WORK_DIR}}`
|
|
20
|
+
- Build command: `{{RALPH_BUILD_CMD}}`
|
|
21
|
+
- Test command: `{{RALPH_TEST_CMD}}`
|
|
22
|
+
- Branch prefix: `{{RALPH_BRANCH_PREFIX}}`
|
|
23
|
+
- Agent-stuck label: `{{RALPH_AGENT_STUCK_LABEL}}`
|
|
24
|
+
- Launch tag (embed in the PR body, see below): `{{RALPH_LAUNCH_TAG}}`
|
|
25
|
+
|
|
26
|
+
You have `gh` authenticated against the target repo. You have `jq`. You
|
|
27
|
+
may use the `serena`, `morph-mcp`, `context7`, `github`, and
|
|
28
|
+
`sequential-thinking` MCPs. You do NOT have a memory MCP — every
|
|
29
|
+
iteration starts with fresh context, and that is intentional.
|
|
30
|
+
|
|
31
|
+
## Output contract — write `/tmp/ralph/impl-result.json`
|
|
32
|
+
|
|
33
|
+
Exactly one of two shapes. Write this file before you exit, no matter
|
|
34
|
+
what happens:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{"status": "PR_OPENED", "issue": <int>, "pr_number": <int>, "pr_url": "<url>", "branch": "<name>"}
|
|
38
|
+
{"status": "AGENT_STUCK", "issue": <int>, "reason": "<≤500 chars>"}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The orchestrator branches on `status` and surfaces the result as the
|
|
42
|
+
phase-end status marker for CloudWatch.
|
|
43
|
+
|
|
44
|
+
## Procedure
|
|
45
|
+
|
|
46
|
+
### 1. Read the crafted context
|
|
47
|
+
|
|
48
|
+
The "Crafted context from discovery" section below contains the picked
|
|
49
|
+
issue (number, full body, acceptance criteria, milestone, suggested
|
|
50
|
+
branch name, target conventions, recent milestone-log entries).
|
|
51
|
+
Internalize it before you touch code. The file
|
|
52
|
+
`/tmp/ralph/crafted-prompt.md` holds the same content; the picked issue
|
|
53
|
+
number is also in `/tmp/ralph/issue.json` under `.number`.
|
|
54
|
+
|
|
55
|
+
### 2. Check out a fresh branch
|
|
56
|
+
|
|
57
|
+
`cd {{RALPH_WORK_DIR}}`. Branch off `{{RALPH_DEFAULT_BRANCH}}`. Branch
|
|
58
|
+
name: `{{RALPH_BRANCH_PREFIX}}/<n>-<slug>` where `<n>` is the picked
|
|
59
|
+
issue number and `<slug>` is the kebab-case slug from the discovery
|
|
60
|
+
context (≤40 chars, ASCII alnum + dashes).
|
|
61
|
+
|
|
62
|
+
### 3. Implement
|
|
63
|
+
|
|
64
|
+
Make the smallest correct change that satisfies every acceptance
|
|
65
|
+
criterion in the crafted context. Follow the target's conventions
|
|
66
|
+
surfaced under "Target conventions" (commit-message style, do-not-touch
|
|
67
|
+
directories, build/test gotchas).
|
|
68
|
+
|
|
69
|
+
After every meaningful edit, run `{{RALPH_BUILD_CMD}}` and
|
|
70
|
+
`{{RALPH_TEST_CMD}}` and read the failures. Fix and re-run. Don't push
|
|
71
|
+
until both are green.
|
|
72
|
+
|
|
73
|
+
### 4. Bounded escape — `agent-stuck`
|
|
74
|
+
|
|
75
|
+
Self-stop and label the source issue if ANY of these hits:
|
|
76
|
+
|
|
77
|
+
- more than 3 build/test fix iterations on the same failure surface
|
|
78
|
+
- more than 15 file edits without a green build
|
|
79
|
+
- self-judged futility — the issue cannot be solved with the
|
|
80
|
+
information available (e.g. missing target-side context that should
|
|
81
|
+
exist but does not)
|
|
82
|
+
|
|
83
|
+
To self-stop:
|
|
84
|
+
|
|
85
|
+
1. Apply the `{{RALPH_AGENT_STUCK_LABEL}}` label to the source issue:
|
|
86
|
+
|
|
87
|
+
gh issue edit <n> --repo {{RALPH_TARGET_REPO}} \
|
|
88
|
+
--add-label "{{RALPH_AGENT_STUCK_LABEL}}"
|
|
89
|
+
|
|
90
|
+
2. Do NOT push a branch. Do NOT open a PR. Do NOT swap labels. Do
|
|
91
|
+
NOT append a milestone-log entry.
|
|
92
|
+
3. Write `/tmp/ralph/impl-result.json` with `status=AGENT_STUCK`,
|
|
93
|
+
`issue=<n>`, and a one-paragraph `reason` explaining what blocked
|
|
94
|
+
you. Use `jq -n` so the file is valid JSON.
|
|
95
|
+
4. Exit cleanly.
|
|
96
|
+
|
|
97
|
+
### 5. On green build — commit, push, open PR
|
|
98
|
+
|
|
99
|
+
One atomic commit with a message that follows the target's commit
|
|
100
|
+
style. Push the branch (`git push -u origin <branch>`). Open the PR:
|
|
101
|
+
|
|
102
|
+
gh pr create \
|
|
103
|
+
--repo {{RALPH_TARGET_REPO}} \
|
|
104
|
+
--base {{RALPH_DEFAULT_BRANCH}} \
|
|
105
|
+
--head <branch> \
|
|
106
|
+
--title "<one-line title>" \
|
|
107
|
+
--body "<body>"
|
|
108
|
+
|
|
109
|
+
The PR body MUST include, on their own lines:
|
|
110
|
+
|
|
111
|
+
Closes #<n>
|
|
112
|
+
|
|
113
|
+
<!-- ralph-launch: {{RALPH_LAUNCH_TAG}} -->
|
|
114
|
+
|
|
115
|
+
The first line auto-closes the source issue when the PR merges. The
|
|
116
|
+
HTML comment is invisible to humans but greppable; the launcher uses
|
|
117
|
+
it to correlate post-hoc when the EC2 was hard-killed before this
|
|
118
|
+
call could record state.
|
|
119
|
+
|
|
120
|
+
### 6. Swap label and append milestone log
|
|
121
|
+
|
|
122
|
+
Swap `ready-for-agent` → `ready-for-human` on the source issue:
|
|
123
|
+
|
|
124
|
+
gh issue edit <n> --repo {{RALPH_TARGET_REPO}} \
|
|
125
|
+
--remove-label ready-for-agent --add-label ready-for-human
|
|
126
|
+
|
|
127
|
+
If `/tmp/ralph/milestone-log.json` has a non-null `log_issue`, append
|
|
128
|
+
one caveman-format comment on it:
|
|
129
|
+
|
|
130
|
+
#<n> | <one-line summary of what shipped> | <gotcha or '-'>
|
|
131
|
+
|
|
132
|
+
via `gh issue comment <log_issue> --repo {{RALPH_TARGET_REPO}}
|
|
133
|
+
--body "<line>"`. One comment, no transcript dump.
|
|
134
|
+
|
|
135
|
+
### 7. Write the result file
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
jq -n \
|
|
139
|
+
--argjson n <issue-number> \
|
|
140
|
+
--argjson p <pr-number> \
|
|
141
|
+
--arg u "<pr-url>" \
|
|
142
|
+
--arg b "<branch-name>" \
|
|
143
|
+
'{status:"PR_OPENED", issue:$n, pr_number:$p, pr_url:$u, branch:$b}' \
|
|
144
|
+
> /tmp/ralph/impl-result.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
{{PROMPT_EXTENSION}}
|
|
148
|
+
|
|
149
|
+
## Final instructions
|
|
150
|
+
|
|
151
|
+
- The four files written by the discovery call are still present under
|
|
152
|
+
`/tmp/ralph/` (`decision.json`, `issue.json`, `crafted-prompt.md`,
|
|
153
|
+
`milestone-log.json`). Read them; do not overwrite them.
|
|
154
|
+
- Never echo a token, the OAuth credential, or any environment value
|
|
155
|
+
beginning with `GITHUB_` / `GH_` / `ANTHROPIC_` to stdout. CloudWatch
|
|
156
|
+
is the surface for these logs.
|
|
157
|
+
- Emit a short status line at the very end summarizing what happened
|
|
158
|
+
(e.g. `implementation: PR #123 opened`,
|
|
159
|
+
`implementation: agent_stuck #<n>`).
|
|
160
|
+
- `/tmp/ralph/impl-result.json` MUST exist when you exit. The
|
|
161
|
+
orchestrator fails the run if it is missing or not valid JSON.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# ralph-harness — review call
|
|
2
|
+
|
|
3
|
+
You are running on a throwaway EC2 worker, in a fresh clone of the
|
|
4
|
+
target GitHub repository. The implementation call already opened a PR
|
|
5
|
+
on this branch for the picked issue. The bash orchestrator slept for
|
|
6
|
+
ten minutes before invoking you, to give the configured external
|
|
7
|
+
review bot time to post its consolidated verdict on the PR.
|
|
8
|
+
|
|
9
|
+
Your job in this call is to **fetch the PR feedback, filter it to the
|
|
10
|
+
configured review bot, and (if a verdict is present) apply ONE
|
|
11
|
+
revision pass — push, then exit**. This is the only revision round.
|
|
12
|
+
No follow-up rounds, no polling for newer reviews, no agent-vs-agent
|
|
13
|
+
ping-pong.
|
|
14
|
+
|
|
15
|
+
This prompt is generic. Every target-specific value comes from
|
|
16
|
+
runtime substitution; do not hard-code anything about the target.
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
|
|
20
|
+
- Target repo: `{{RALPH_TARGET_REPO}}`
|
|
21
|
+
- Default branch (PR base): `{{RALPH_DEFAULT_BRANCH}}`
|
|
22
|
+
- Working directory (fresh clone, on default branch): `{{RALPH_WORK_DIR}}`
|
|
23
|
+
- Build command: `{{RALPH_BUILD_CMD}}`
|
|
24
|
+
- Test command: `{{RALPH_TEST_CMD}}`
|
|
25
|
+
- Source issue number: `{{RALPH_ISSUE_NUMBER}}`
|
|
26
|
+
- PR number: `{{RALPH_PR_NUMBER}}`
|
|
27
|
+
- PR branch: `{{RALPH_PR_BRANCH}}`
|
|
28
|
+
- Review bot username: `{{RALPH_REVIEW_BOT_USERNAME}}`
|
|
29
|
+
- Review bot source: `{{RALPH_REVIEW_BOT_SOURCE}}` (one of: `comment`, `review`)
|
|
30
|
+
|
|
31
|
+
You have `gh` authenticated against the target repo. You have `jq`.
|
|
32
|
+
You may use the `serena`, `morph-mcp`, `context7`, `github`, and
|
|
33
|
+
`sequential-thinking` MCPs. You do NOT have a memory MCP — every
|
|
34
|
+
iteration starts with fresh context, and that is intentional.
|
|
35
|
+
|
|
36
|
+
## Output contract — write `/tmp/ralph/review-result.json`
|
|
37
|
+
|
|
38
|
+
Exactly one of two shapes. Write this file before you exit, no matter
|
|
39
|
+
what happens:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{"status": "NO_REVIEW", "reason": "<≤500 chars>"}
|
|
43
|
+
{"status": "REVISION_APPLIED", "issue": <int>, "pr_number": <int>,
|
|
44
|
+
"summary": "<≤200 chars>",
|
|
45
|
+
"gotcha": "<≤200 chars or empty>"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The orchestrator branches on `status`, surfaces the result as the
|
|
49
|
+
phase-end status marker for CloudWatch, and on `REVISION_APPLIED`
|
|
50
|
+
appends one caveman-format line to the milestone-log issue (via
|
|
51
|
+
`gsm::append_caveman_log`) using `summary` and `gotcha`.
|
|
52
|
+
|
|
53
|
+
## Procedure
|
|
54
|
+
|
|
55
|
+
### 1. Fetch PR comments + reviews
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
gh pr view {{RALPH_PR_NUMBER}} --repo {{RALPH_TARGET_REPO}} \
|
|
59
|
+
--json comments,reviews \
|
|
60
|
+
> /tmp/ralph/pr-feedback.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Filter to the configured review bot
|
|
64
|
+
|
|
65
|
+
`{{RALPH_REVIEW_BOT_SOURCE}}` decides which collection to scan:
|
|
66
|
+
|
|
67
|
+
- `comment` — scan `.comments[]` for entries where
|
|
68
|
+
`.author.login == "{{RALPH_REVIEW_BOT_USERNAME}}"`
|
|
69
|
+
- `review` — scan `.reviews[]` for entries where
|
|
70
|
+
`.author.login == "{{RALPH_REVIEW_BOT_USERNAME}}"`
|
|
71
|
+
|
|
72
|
+
ONLY the configured `review_bot` is consulted. Other reviewers
|
|
73
|
+
(Copilot, humans, other bots) are out of scope for this call —
|
|
74
|
+
ignore them entirely. Do not let a Copilot review prompt a revision.
|
|
75
|
+
|
|
76
|
+
### 3. No verdict from the configured bot → no-op clean exit
|
|
77
|
+
|
|
78
|
+
If the filter returns zero entries:
|
|
79
|
+
|
|
80
|
+
1. Do NOT push, comment, label, or touch any state.
|
|
81
|
+
2. Write `/tmp/ralph/review-result.json` with `status=NO_REVIEW`
|
|
82
|
+
and a one-line `reason` (e.g.
|
|
83
|
+
`"no comments from <bot> within the 10-minute window"`).
|
|
84
|
+
3. Exit cleanly. The orchestrator skips the caveman log entry on
|
|
85
|
+
`NO_REVIEW`.
|
|
86
|
+
|
|
87
|
+
### 4. Verdict present → ONE revision pass
|
|
88
|
+
|
|
89
|
+
Take the most recent matching entry as the review verdict. Check out
|
|
90
|
+
the PR branch:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
cd {{RALPH_WORK_DIR}}
|
|
94
|
+
git fetch origin {{RALPH_PR_BRANCH}}
|
|
95
|
+
git checkout {{RALPH_PR_BRANCH}}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Apply ONE pass that addresses the actionable feedback. Run
|
|
99
|
+
`{{RALPH_BUILD_CMD}}` and `{{RALPH_TEST_CMD}}` after each meaningful
|
|
100
|
+
edit until both are green. Make one atomic commit (message style:
|
|
101
|
+
`review: address <bot> feedback`) and push:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
git push origin {{RALPH_PR_BRANCH}}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
DO NOT loop. DO NOT fetch newer reviews after pushing. DO NOT engage
|
|
108
|
+
in further rounds. The harness's contract is exactly one revision
|
|
109
|
+
round per iteration.
|
|
110
|
+
|
|
111
|
+
### 5. Write the result file
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
jq -n \
|
|
115
|
+
--argjson n {{RALPH_ISSUE_NUMBER}} \
|
|
116
|
+
--argjson p {{RALPH_PR_NUMBER}} \
|
|
117
|
+
--arg s "<one-line summary of what changed>" \
|
|
118
|
+
--arg g "<one-line gotcha or empty>" \
|
|
119
|
+
'{status:"REVISION_APPLIED", issue:$n, pr_number:$p, summary:$s, gotcha:$g}' \
|
|
120
|
+
> /tmp/ralph/review-result.json
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
{{PROMPT_EXTENSION}}
|
|
124
|
+
|
|
125
|
+
## Final instructions
|
|
126
|
+
|
|
127
|
+
- One revision round only. Do not poll for follow-up reviews.
|
|
128
|
+
- Never echo a token, the OAuth credential, or any environment value
|
|
129
|
+
beginning with `GITHUB_` / `GH_` / `ANTHROPIC_` to stdout.
|
|
130
|
+
CloudWatch is the surface for these logs.
|
|
131
|
+
- Emit a short status line at the very end summarizing what
|
|
132
|
+
happened (e.g. `review: NO_REVIEW`,
|
|
133
|
+
`review: REVISION_APPLIED pr=<m>`).
|
|
134
|
+
- `/tmp/ralph/review-result.json` MUST exist when you exit. The
|
|
135
|
+
orchestrator fails the run if it is missing or not valid JSON.
|