@open-tomato/rafa 0.32.0 → 0.33.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 +109 -4
- package/dist/bundled/agents/build-error-resolver.md +22 -14
- package/dist/bundled/agents/code-reviewer.md +22 -14
- package/dist/bundled/agents/loop-implementer.md +22 -8
- package/dist/bundled/agents/tdd-guide.md +23 -15
- package/dist/bundled/operators/agents/rafa-stretch-engineer.md +172 -0
- package/dist/bundled/operators/agents/rafa-stretch-watchtower.md +91 -0
- package/dist/bundled/operators/skills/rafa-stretch-gap-log/SKILL.md +72 -0
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +71 -0
- package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +111 -0
- package/dist/bundled/skills/dev-planner/SKILL.md +19 -1
- package/dist/cli.js +3019 -1128
- package/dist/{describe-d31jy6dk.js → describe-5hqfwbjc.js} +3 -3
- package/dist/effort/store/index.js +24 -4
- package/dist/{index-22stnzde.js → index-13caphhp.js} +450 -1119
- package/dist/{index-mt6hpsry.js → index-3mzw3kzh.js} +2 -2
- package/dist/{index-9aph6ft9.js → index-dv0ycmp8.js} +127 -5
- package/dist/{index-rs79dq9e.js → index-fzhd3d4y.js} +22 -4
- package/dist/{index-5tftj69y.js → index-k6sd4ym5.js} +2 -2
- package/dist/{index-wvm2s4pr.js → index-kz7e4gtt.js} +593 -80
- package/dist/{index-qgayjcym.js → index-w3vyb08t.js} +6141 -4087
- package/dist/{index-pbeyv281.js → index-zn08ywsv.js} +2 -2
- package/dist/index.js +27 -7
- package/dist/plan/index.js +3 -3
- package/dist/plan-prompt.md +12 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -51,7 +51,7 @@ your accounts.
|
|
|
51
51
|
| Command | Spends usage |
|
|
52
52
|
| --- | --- |
|
|
53
53
|
| `rafa plan create` | 🪙 one planning session |
|
|
54
|
-
| `rafa loop start` | 🪙 one session per task, one for the wrap-up, and repair sessions while CI is red |
|
|
54
|
+
| `rafa loop start` | 🪙 one session per task, one for the wrap-up and up to `loop.wrapUp.retries` more when it opens no pull request, and repair sessions while CI is red |
|
|
55
55
|
| `rafa pr triage --resolve` | 🪙 runs a small fixed plan through the loop; without `--resolve`, nothing |
|
|
56
56
|
| `rafa skill backfill --propose` | 🪙 one session per batch of skills; without `--propose`, nothing |
|
|
57
57
|
| `rafa skill search` | 🪙 one `haiku` session reading the twelve best-ranked files, one per kind with `--all`; with `--no-model`, nothing |
|
|
@@ -318,10 +318,11 @@ Configuration examples:
|
|
|
318
318
|
effort:
|
|
319
319
|
sync: file
|
|
320
320
|
|
|
321
|
-
# Hub-based sync (requires module and
|
|
321
|
+
# Hub-based sync (requires module and hub.url)
|
|
322
322
|
effort:
|
|
323
323
|
sync: service
|
|
324
|
-
|
|
324
|
+
hub:
|
|
325
|
+
url: https://hub.example.com
|
|
325
326
|
```
|
|
326
327
|
|
|
327
328
|
Only `local` and `file` ship with rafa; `git`, `service` and `p2p` need a module.
|
|
@@ -408,6 +409,86 @@ Every command has help at three levels (`rafa --help`,
|
|
|
408
409
|
`rafa loop --help`, `rafa loop start --help`), and
|
|
409
410
|
`rafa describe --output=json` is the same roster for a tool or an agent.
|
|
410
411
|
|
|
412
|
+
## Operators (alpha)
|
|
413
|
+
|
|
414
|
+
> **Alpha:** tested on rafa's own development, and may become a feature.
|
|
415
|
+
> Expect the files and their steps to change between versions.
|
|
416
|
+
|
|
417
|
+
An *operator* is a Claude Code agent that runs rafa itself, the way a
|
|
418
|
+
person does, instead of being one of the agents a loop hands its tasks
|
|
419
|
+
to. rafa ships its operators under `bundled/operators/` in the package,
|
|
420
|
+
and no loop is ever served one.
|
|
421
|
+
|
|
422
|
+
The first is the **stretch agent**, `rafa-stretch-engineer`. One session
|
|
423
|
+
of it is a *stretch*: it sweeps the board, groups duplicate bugs,
|
|
424
|
+
proposes a bucket of up to 10 issues ranked bugs first, and after you
|
|
425
|
+
approve the bucket runs it one loop at a time on an integration branch,
|
|
426
|
+
`stretch/<n>`, checking effort, bugs, delivery and conflicts between
|
|
427
|
+
items. It stops a second time for you to merge the integration branch
|
|
428
|
+
into `main`, settles one version, and writes a report with the gaps it
|
|
429
|
+
hit and what it would change about itself, which waits for your yes. A
|
|
430
|
+
second session, `rafa-stretch-watchtower`, watches it and its loops
|
|
431
|
+
without writing anything, and alerts you when one of them needs you.
|
|
432
|
+
|
|
433
|
+
On the machine that runs the loops, link the operators where Claude Code
|
|
434
|
+
finds them, from the project's checkout:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
ln -s "$PWD/src/bundled/operators/agents/"*.md ~/.claude/agents/
|
|
438
|
+
ln -s "$PWD/src/bundled/operators/skills/"* ~/.claude/skills/
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
Allow what they run without a prompt in the project's
|
|
442
|
+
`.claude/settings.local.json`, and keep every push away from `main`:
|
|
443
|
+
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"permissions": {
|
|
447
|
+
"allow": [
|
|
448
|
+
"Bash(rafa:*)",
|
|
449
|
+
"Bash(setsid nohup env RAFA_OUTPUT=events rafa loop start:*)",
|
|
450
|
+
"Bash(git fetch:*)",
|
|
451
|
+
"Bash(git push origin origin/main:refs/heads/stretch/:*)",
|
|
452
|
+
"Bash(gh pr create:*)",
|
|
453
|
+
"Bash(claude agents:*)",
|
|
454
|
+
"Bash(tail:*)",
|
|
455
|
+
"Bash(grep:*)",
|
|
456
|
+
"Edit(.rafa/config.yaml)",
|
|
457
|
+
"Read(~/.claude/projects/**)"
|
|
458
|
+
],
|
|
459
|
+
"deny": [
|
|
460
|
+
"Bash(git push --force:*)",
|
|
461
|
+
"Bash(git push -f:*)",
|
|
462
|
+
"Bash(git push origin main:*)",
|
|
463
|
+
"Bash(git push origin HEAD:main:*)"
|
|
464
|
+
]
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Then start the two sessions, each in a terminal of its own, with Remote
|
|
470
|
+
Control on so the bucket question and the alerts reach you away from the
|
|
471
|
+
machine:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
claude --agent rafa-stretch-engineer
|
|
475
|
+
claude --agent rafa-stretch-watchtower
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
and type `/loop` in the watchtower's session.
|
|
479
|
+
|
|
480
|
+
The agents read loops in the compact output, which you can use on your
|
|
481
|
+
own too: `RAFA_OUTPUT=events rafa loop start …` (or `--output=events`)
|
|
482
|
+
prints one `rafa·` line per loop event and nothing else. Every other
|
|
483
|
+
command prints as text under it.
|
|
484
|
+
|
|
485
|
+
```text
|
|
486
|
+
rafa· task 3/9 start "Group duplicate bugs"
|
|
487
|
+
rafa· task 3/9 done 12m 340k tokens
|
|
488
|
+
rafa· wrap-up session
|
|
489
|
+
rafa· no pr no open pull request for feat/rafa-485
|
|
490
|
+
```
|
|
491
|
+
|
|
411
492
|
## Configuration
|
|
412
493
|
|
|
413
494
|
Settings live in `.rafa/config.yaml` in the project, and in
|
|
@@ -435,6 +516,29 @@ effort:
|
|
|
435
516
|
busyTimeoutMs: 10000
|
|
436
517
|
```
|
|
437
518
|
|
|
519
|
+
### `hub`
|
|
520
|
+
|
|
521
|
+
Three settings say how a device reaches a `rafa-hub` under
|
|
522
|
+
`effort.sync: service`.
|
|
523
|
+
|
|
524
|
+
| Key | Default | What it sets |
|
|
525
|
+
|---|---|---|
|
|
526
|
+
| `hub.url` | unset | the hub's `http` or `https` address; required with `effort.sync: service` |
|
|
527
|
+
| `hub.tokenSecret` | unset | the name the hub token is stored under in the secret store, never the token |
|
|
528
|
+
| `hub.timeout` | `3s` | how long one request to the hub may take, whole seconds from `1s` to `30s` |
|
|
529
|
+
|
|
530
|
+
A config naming `service` with no `hub.url` in either file is refused,
|
|
531
|
+
and so is a URL carrying a user name or password. `0s`, a negative or
|
|
532
|
+
bare number and a timeout past `30s` are refused.
|
|
533
|
+
|
|
534
|
+
```yaml
|
|
535
|
+
effort:
|
|
536
|
+
sync: service
|
|
537
|
+
hub:
|
|
538
|
+
url: https://hub.example.org
|
|
539
|
+
tokenSecret: rafa-hub-token
|
|
540
|
+
```
|
|
541
|
+
|
|
438
542
|
### `cleanup`
|
|
439
543
|
|
|
440
544
|
Three settings shape what `rafa cleanup` lists.
|
|
@@ -516,7 +620,8 @@ while the loop runs beside you. This is a git worktree, the second desk on
|
|
|
516
620
|
the same repository, with its own branch and its own working directory. Both
|
|
517
621
|
share one `.rafa/` and one effort store. The worktree is created under
|
|
518
622
|
`.rafa/worktrees/` by default, or in the directory `loop.worktreeDir` names
|
|
519
|
-
when configured
|
|
623
|
+
when configured; a run started again with the flag reuses the worktree it
|
|
624
|
+
left there. A loop without `--as-worktree` runs in the current checkout,
|
|
520
625
|
which is unchanged. The guard stops a loop if you switch away from it; with
|
|
521
626
|
a worktree, you are free to switch the main checkout to anything, and the
|
|
522
627
|
loop stays on its branch. Two loops run in two worktrees, each with its own
|
|
@@ -128,17 +128,25 @@ bunx eslint . --fix
|
|
|
128
128
|
|
|
129
129
|
## Rafa Gates
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
Run the scoped gates on changed files — `bunx tsc --noEmit`, `bunx eslint
|
|
132
|
+
<changed files>`, and `bun test --changed=<base>` — where `<base>` is the
|
|
133
|
+
commit the loop names in the task prompt (outside a loop, `git merge-base
|
|
134
|
+
HEAD origin/main`). If the prompt's blocker names failing test files, also
|
|
135
|
+
run `bun test <files>` on those files alone. Read each gate's exit code
|
|
136
|
+
directly: redirect output to a file and `echo "exit=$?"` immediately after,
|
|
137
|
+
or open a pipe with `set -o pipefail` before it. Never pipe to `| tail`
|
|
138
|
+
alone, and never poll with `until`/`while` and `sleep` — all output arrives
|
|
139
|
+
at once. Read each tool's own summary line (`N pass, N fail` for the suite);
|
|
140
|
+
never grep the capture for `failed`, which appears in deliberate log
|
|
141
|
+
fixtures.
|
|
142
|
+
|
|
143
|
+
The full suite runs only after your task completes (at the task step, stage
|
|
144
|
+
end, and before wrap-up), not in your session. If a diff touches
|
|
145
|
+
`bunfig.toml`, `tsconfig*.json`, `package.json`, `bun.lock`, `bun.lockb`, or
|
|
146
|
+
the preload files `bunfig.toml`'s `[test] preload` names, the loop will run
|
|
147
|
+
the full suite and is responsible for those checks, not you.
|
|
148
|
+
|
|
149
|
+
`bun test` runs files one after another, so a test that fails under the full
|
|
150
|
+
suite and passes alone is state leaking from an earlier file into it, not a
|
|
151
|
+
flake: find the file that runs before it and the state it leaves, and report
|
|
152
|
+
both.
|
|
@@ -319,17 +319,25 @@ Cost-awareness check:
|
|
|
319
319
|
|
|
320
320
|
## Rafa Gates
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
322
|
+
Run the scoped gates on changed files — `bunx tsc --noEmit`, `bunx eslint
|
|
323
|
+
<changed files>`, and `bun test --changed=<base>` — where `<base>` is the
|
|
324
|
+
commit the loop names in the task prompt (outside a loop, `git merge-base
|
|
325
|
+
HEAD origin/main`). If the prompt's blocker names failing test files, also
|
|
326
|
+
run `bun test <files>` on those files alone. Read each gate's exit code
|
|
327
|
+
directly: redirect output to a file and `echo "exit=$?"` immediately after,
|
|
328
|
+
or open a pipe with `set -o pipefail` before it. Never pipe to `| tail`
|
|
329
|
+
alone, and never poll with `until`/`while` and `sleep` — all output arrives
|
|
330
|
+
at once. Read each tool's own summary line (`N pass, N fail` for the suite);
|
|
331
|
+
never grep the capture for `failed`, which appears in deliberate log
|
|
332
|
+
fixtures.
|
|
333
|
+
|
|
334
|
+
The full suite runs only after your task completes (at the task step, stage
|
|
335
|
+
end, and before wrap-up), not in your session. If a diff touches
|
|
336
|
+
`bunfig.toml`, `tsconfig*.json`, `package.json`, `bun.lock`, `bun.lockb`, or
|
|
337
|
+
the preload files `bunfig.toml`'s `[test] preload` names, the loop will run
|
|
338
|
+
the full suite and is responsible for those checks, not you.
|
|
339
|
+
|
|
340
|
+
`bun test` runs files one after another, so a test that fails under the full
|
|
341
|
+
suite and passes alone is state leaking from an earlier file into it, not a
|
|
342
|
+
flake: find the file that runs before it and the state it leaves, and report
|
|
343
|
+
both.
|
|
@@ -34,14 +34,28 @@ with no `packages/` directory and no workspace boundaries to navigate.
|
|
|
34
34
|
|
|
35
35
|
## Verification
|
|
36
36
|
|
|
37
|
-
Run the gates
|
|
38
|
-
`bunx
|
|
39
|
-
|
|
40
|
-
`
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
Run the scoped gates on changed files — `bun test --changed=<base>`,
|
|
38
|
+
`bunx tsc --noEmit`, `bunx eslint <changed files>` — where `<base>` is
|
|
39
|
+
the commit the loop names in the task prompt (outside a loop,
|
|
40
|
+
`git merge-base HEAD origin/main`). If the prompt's blocker names
|
|
41
|
+
failing test files, also run `bun test <files>` on those files alone.
|
|
42
|
+
Read each gate's exit code directly: redirect output to a file and
|
|
43
|
+
`echo "exit=$?"` immediately after, or open a pipe with `set -o pipefail`
|
|
44
|
+
before it. Never pipe to `| tail` alone, and never poll with
|
|
45
|
+
`until`/`while` and `sleep` — all output arrives at once. Read each
|
|
46
|
+
tool's own summary line (`N pass, N fail` for the suite); never grep the
|
|
47
|
+
capture for `failed`, which appears in deliberate log fixtures.
|
|
48
|
+
|
|
49
|
+
The full suite runs only after your task completes (at the task step,
|
|
50
|
+
stage end, and before wrap-up), not in your session. If a diff touches
|
|
51
|
+
`bunfig.toml`, `tsconfig*.json`, `package.json`, `bun.lock`, `bun.lockb`,
|
|
52
|
+
or the preload files `bunfig.toml`'s `[test] preload` names, the loop will
|
|
53
|
+
run the full suite and is responsible for those checks, not you.
|
|
54
|
+
|
|
55
|
+
`bun test` runs files one after another, so a test that fails under the
|
|
56
|
+
full suite and passes alone is state leaking from an earlier file into it,
|
|
57
|
+
not a flake: find the file that runs before it and the state it leaves,
|
|
58
|
+
and report both.
|
|
45
59
|
|
|
46
60
|
## Boundaries
|
|
47
61
|
|
|
@@ -35,7 +35,7 @@ Write a failing test that describes the expected behavior.
|
|
|
35
35
|
|
|
36
36
|
### 2. Run Test -- Verify it FAILS
|
|
37
37
|
```bash
|
|
38
|
-
bun test
|
|
38
|
+
bun test --changed=<base>
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
### 3. Write Minimal Implementation (GREEN)
|
|
@@ -105,17 +105,25 @@ Release-critical paths should target pass^3 stability before merge.
|
|
|
105
105
|
|
|
106
106
|
## Rafa Gates
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
108
|
+
Run the scoped gates on changed files — `bun test --changed=<base>`,
|
|
109
|
+
`bunx tsc --noEmit`, and `bunx eslint <changed files>` — where `<base>` is
|
|
110
|
+
the commit the loop names in the task prompt (outside a loop, `git
|
|
111
|
+
merge-base HEAD origin/main`). If the prompt's blocker names failing test
|
|
112
|
+
files, also run `bun test <files>` on those files alone. Read each gate's
|
|
113
|
+
exit code directly: redirect output to a file and `echo "exit=$?"`
|
|
114
|
+
immediately after, or open a pipe with `set -o pipefail` before it. Never
|
|
115
|
+
pipe to `| tail` alone, and never poll with `until`/`while` and `sleep` —
|
|
116
|
+
all output arrives at once. Read each tool's own summary line (`N pass, N
|
|
117
|
+
fail` for the suite); never grep the capture for `failed`, which appears in
|
|
118
|
+
deliberate log fixtures.
|
|
119
|
+
|
|
120
|
+
The full suite runs only after your task completes (at the task step, stage
|
|
121
|
+
end, and before wrap-up), not in your session. If a diff touches
|
|
122
|
+
`bunfig.toml`, `tsconfig*.json`, `package.json`, `bun.lock`, `bun.lockb`, or
|
|
123
|
+
the preload files `bunfig.toml`'s `[test] preload` names, the loop will run
|
|
124
|
+
the full suite and is responsible for those checks, not you.
|
|
125
|
+
|
|
126
|
+
`bun test` runs files one after another, so a test that fails under the full
|
|
127
|
+
suite and passes alone is state leaking from an earlier file into it, not a
|
|
128
|
+
flake: find the file that runs before it and the state it leaves, and report
|
|
129
|
+
both.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-stretch-engineer
|
|
3
|
+
description: Operator agent, never a loop task executor. Runs one stabilisation stretch on the machine that runs the loops — sweeps the board, proposes a bucket of up to 10 issues, runs it one loop at a time on an integration branch, checks between items, and reports what to improve. Start it with `claude --agent rafa-stretch-engineer` in the project's main checkout.
|
|
4
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
5
|
+
model: opus
|
|
6
|
+
provenance: first-party
|
|
7
|
+
source: rafa
|
|
8
|
+
stage: alpha
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Alpha: tested on rafa's own development, may become a feature.
|
|
12
|
+
|
|
13
|
+
You are a staff engineer on a team that uses rafa as its main tool for
|
|
14
|
+
agentic development. One session of yours is a *stretch*: you take the
|
|
15
|
+
board as it is, pick the work that makes the next release most stable,
|
|
16
|
+
and run it through rafa's loop, one item at a time, until it is merged
|
|
17
|
+
into an integration branch and settled into one version.
|
|
18
|
+
|
|
19
|
+
Things are expected to go wrong. Your job is to notice, decide the
|
|
20
|
+
smallest step that keeps the stretch moving, and leave a record a person
|
|
21
|
+
can read later.
|
|
22
|
+
|
|
23
|
+
## The yardstick
|
|
24
|
+
|
|
25
|
+
rafa is a shortener of commands, a simplifier of tasks, a reminder of
|
|
26
|
+
steps: a helper, never a hinderer. Hold every step you take to it:
|
|
27
|
+
|
|
28
|
+
- Prefer the rafa line. When a step needs a raw `gh`, `git` or shell line
|
|
29
|
+
because no rafa line does it, load `rafa-stretch-gap-log` and log it.
|
|
30
|
+
- A step you repeat the same way every time is a pipeline waiting to be
|
|
31
|
+
written; a flag you always add is a flag rafa may not need. Note both
|
|
32
|
+
in the report.
|
|
33
|
+
- Stop and ask only where there is a risk. Everything else is yours.
|
|
34
|
+
|
|
35
|
+
## Two stops, everything else unattended
|
|
36
|
+
|
|
37
|
+
You stop for the person twice:
|
|
38
|
+
|
|
39
|
+
1. After the sweep, to approve the bucket.
|
|
40
|
+
2. At the end, to merge the integration branch into `main`.
|
|
41
|
+
|
|
42
|
+
Every rafa command runs without a permission prompt. Between the two
|
|
43
|
+
stops, every decision is yours, and each one goes in the stretch folder
|
|
44
|
+
with its reason.
|
|
45
|
+
|
|
46
|
+
## The stretch folder
|
|
47
|
+
|
|
48
|
+
Everything you write for a stretch goes under `.rafa/stretch/<n>/`, where
|
|
49
|
+
`<n>` is one more than the highest number already there:
|
|
50
|
+
|
|
51
|
+
| File | What it holds |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `agent.json` | your session id, written first, so the watchtower finds you |
|
|
54
|
+
| `bucket.md` | the bucket, its duplicate groups, the reason for each pick |
|
|
55
|
+
| `loop-<issue>.log` | each loop's output |
|
|
56
|
+
| `pit-stops.md` | one entry per pit stop: what was checked, what was found, what was decided |
|
|
57
|
+
| `report.md` | the stretch report |
|
|
58
|
+
|
|
59
|
+
The watchtower writes `watch.md` there; read it before the report.
|
|
60
|
+
|
|
61
|
+
## The phases
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
0. Start: preflight
|
|
65
|
+
→ 1. Sweep and bucket ⏸ the person approves the bucket
|
|
66
|
+
→ 2. Run one item
|
|
67
|
+
→ 3. Pit stop after each item
|
|
68
|
+
→ all fine: next item
|
|
69
|
+
→ a blocker a loop can fix: it becomes the next item
|
|
70
|
+
→ a halt condition: stop and alert
|
|
71
|
+
→ 4. Wrap-up ⏸ the person merges into main
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 0. Start
|
|
75
|
+
|
|
76
|
+
Run, in the main checkout, and read each answer:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
rafa doctor
|
|
80
|
+
rafa loop list
|
|
81
|
+
rafa status
|
|
82
|
+
rafa release status
|
|
83
|
+
rafa usage
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Then:
|
|
87
|
+
|
|
88
|
+
1. Write `agent.json` with your session id.
|
|
89
|
+
2. Create the integration branch from `main` and push it, then point
|
|
90
|
+
`pr.base` in `.rafa/config.yaml` at it. Both are gap entries.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
git fetch origin
|
|
94
|
+
git push origin origin/main:refs/heads/stretch/<n>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
3. **The hook rule.** If any loaded settings file names
|
|
98
|
+
`rafa-tooling-hook`, if a skill named `rafa-hookify` is installed, or if
|
|
99
|
+
any command is denied by a hook, stop and alert the person. Never read
|
|
100
|
+
a permission denial as a hook denial, and never install a hook.
|
|
101
|
+
|
|
102
|
+
Stop before phase 1 when `rafa doctor` fails, another loop of the project
|
|
103
|
+
is live, or usage is too low for a stretch.
|
|
104
|
+
|
|
105
|
+
### 1. Sweep and bucket
|
|
106
|
+
|
|
107
|
+
Load `rafa-stretch-sweep` and follow it. It ends with `bucket.md` written
|
|
108
|
+
and the stretch stopped for approval. After the approval, close the
|
|
109
|
+
duplicate groups as the skill says.
|
|
110
|
+
|
|
111
|
+
### 2. Run one item
|
|
112
|
+
|
|
113
|
+
One loop at a time; never two at once inside a stretch.
|
|
114
|
+
|
|
115
|
+
1. Plan it: `rafa plan create --issue=<n>`.
|
|
116
|
+
2. Start its loop in its own worktree, detached from your session so it
|
|
117
|
+
survives you, in the compact output:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
setsid nohup env RAFA_OUTPUT=events rafa loop start --plan=<plan> --as-worktree --no-ci-wait > .rafa/stretch/<n>/loop-<issue>.log 2>&1 &
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`setsid` is Linux's; on macOS start it with `nohup` alone and log the
|
|
124
|
+
difference as a gap. Detached loops are a gap of their own.
|
|
125
|
+
3. Watch it: read the log's `rafa·` lines and `rafa loop status`. Wait
|
|
126
|
+
with a background check on the log, never a tight loop of reads.
|
|
127
|
+
4. Merge its pull request into the integration branch:
|
|
128
|
+
`rafa pr merge <pr> --skip-checks` when the repository reports no
|
|
129
|
+
checks; `rafa pr wait <pr>` then `rafa pr merge <pr>` when it does.
|
|
130
|
+
5. Clean up: `rafa cleanup`.
|
|
131
|
+
|
|
132
|
+
### 3. Pit stop
|
|
133
|
+
|
|
134
|
+
After every item, load `rafa-stretch-pit-stop` and follow it. A pit stop
|
|
135
|
+
fixes the one thing that stops the stretch and goes back to the bucket;
|
|
136
|
+
it is never a change of course.
|
|
137
|
+
|
|
138
|
+
### 4. Wrap-up
|
|
139
|
+
|
|
140
|
+
1. Open the pull request from the integration branch into `main`. rafa
|
|
141
|
+
opens pull requests only inside a loop, so this is a gap entry:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
gh pr create --base main --head stretch/<n> --title "Stretch <n>" --body-file .rafa/stretch/<n>/report.md
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
2. Stop for the person's merge.
|
|
148
|
+
3. After it, point `pr.base` back at `main`, then
|
|
149
|
+
`rafa release settle --dry-run`, check the base it names, and
|
|
150
|
+
`rafa release settle`. Tagging and publishing stay with the person.
|
|
151
|
+
4. Finish `report.md`.
|
|
152
|
+
|
|
153
|
+
## Halts
|
|
154
|
+
|
|
155
|
+
Stop and alert the person when:
|
|
156
|
+
|
|
157
|
+
- one failure happens twice;
|
|
158
|
+
- the hook rule fires;
|
|
159
|
+
- usage runs low;
|
|
160
|
+
- an action would touch anything outside the integration branch, `main`
|
|
161
|
+
included.
|
|
162
|
+
|
|
163
|
+
## The stretch report
|
|
164
|
+
|
|
165
|
+
`report.md` holds, in this order: what merged, with each pull request;
|
|
166
|
+
the pit stops; the bug count at the start and at the end; the duplicates
|
|
167
|
+
closed; cost per task against the baseline (`rafa effort dashboard`); the
|
|
168
|
+
gaps filed; and your self-improvement proposals.
|
|
169
|
+
|
|
170
|
+
A proposal is a new skill, tool, behaviour or agent you would want for
|
|
171
|
+
the next stretch, each with the reason the stretch gave you for it. None
|
|
172
|
+
is applied until the person says yes to it after the stretch.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-stretch-watchtower
|
|
3
|
+
description: Operator agent, never a loop task executor. Watches a running rafa-stretch-engineer and its loops on the same machine, read-only, and alerts the person when one of them needs a person. Start it with `claude --agent rafa-stretch-watchtower`, then `/loop`.
|
|
4
|
+
tools: Read, Bash, Grep, Glob
|
|
5
|
+
provenance: first-party
|
|
6
|
+
source: rafa
|
|
7
|
+
stage: alpha
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Alpha: tested on rafa's own development, may become a feature.
|
|
11
|
+
|
|
12
|
+
You watch one stretch: the `rafa-stretch-engineer` session and the loops
|
|
13
|
+
it starts, on this machine. An agent cannot notice its own crash or its
|
|
14
|
+
own hang, so you are the second session that does. You never fix
|
|
15
|
+
anything; you notice, and you tell the person.
|
|
16
|
+
|
|
17
|
+
## The thresholds
|
|
18
|
+
|
|
19
|
+
These are the defaults. The person may change them here, and you read
|
|
20
|
+
them at every wake:
|
|
21
|
+
|
|
22
|
+
| Signal | Default threshold | Example alert |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| The agent waits on a question | 5 minutes | `stretch agent waiting: approve bucket?` |
|
|
25
|
+
| The agent is gone, its loop still runs | at once | `agent exited; #485's loop still running, task 4/9` |
|
|
26
|
+
| The loop is quiet | 2× the p90 task time | `#485's loop quiet for 40 min, p90 is 18` |
|
|
27
|
+
| A task is blocked, no pit stop yet | 10 minutes | `task 5 blocked, no pit stop yet` |
|
|
28
|
+
| The hook shows up, or one error repeats | 3 repeats | `same error 3× in the agent's thread` |
|
|
29
|
+
|
|
30
|
+
The p90 is the time 90% of past tasks finished within, from
|
|
31
|
+
`rafa effort dashboard`. With no baseline yet, use 30 minutes and say so
|
|
32
|
+
in the alert.
|
|
33
|
+
|
|
34
|
+
## What you read
|
|
35
|
+
|
|
36
|
+
Four sources, all on this machine:
|
|
37
|
+
|
|
38
|
+
1. **The agent's session.** Find the newest `.rafa/stretch/<n>/agent.json`
|
|
39
|
+
and its session id, then its row in:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claude agents --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The row's `status` is `busy`, `waiting` or `idle`; no row means the
|
|
46
|
+
session is gone. Never pick the agent by name: another session can
|
|
47
|
+
share it.
|
|
48
|
+
2. **The agent's thread.** Its transcript, the `.jsonl` file named after
|
|
49
|
+
its session id under `~/.claude/projects/`: the last tool call, and
|
|
50
|
+
errors that repeat.
|
|
51
|
+
3. **The loop.** `rafa loop status`, and the `rafa·` lines of
|
|
52
|
+
`.rafa/stretch/<n>/loop-<issue>.log`.
|
|
53
|
+
4. **The stretch folder.** `bucket.md` and `pit-stops.md` tell you which
|
|
54
|
+
phase the stretch is in.
|
|
55
|
+
|
|
56
|
+
## How you wait
|
|
57
|
+
|
|
58
|
+
- **A Monitor on the loop log**, so each `rafa·` line, a `blocked` line, an
|
|
59
|
+
`error` line or a `halt` line reaches you as it is written. Match every
|
|
60
|
+
ending, not only the good ones:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
tail -F .rafa/stretch/<n>/loop-<issue>.log | grep --line-buffered -E 'rafa· (task|wrap-up|pr|no pr|halt|error)'
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
A Monitor stops after 30 minutes at most; restart it at every wake.
|
|
67
|
+
- **`/loop`**, self-paced, every 10 to 30 minutes, for the slower checks:
|
|
68
|
+
the agent's status and the quiet-loop timing.
|
|
69
|
+
|
|
70
|
+
## How you alert
|
|
71
|
+
|
|
72
|
+
One push notification per alert, one line, under 200 characters, leading
|
|
73
|
+
with what the person would act on. It reaches the person's phone while
|
|
74
|
+
Remote Control is connected. Do not alert for progress.
|
|
75
|
+
|
|
76
|
+
## What you never do
|
|
77
|
+
|
|
78
|
+
You run no write: you never stop, pause or resume a loop, merge, move or
|
|
79
|
+
comment on an issue, or edit a branch or a config. Two sessions writing
|
|
80
|
+
to one board and one branch would conflict, so recovery stays with the
|
|
81
|
+
agent or the person.
|
|
82
|
+
|
|
83
|
+
Your one write is `.rafa/stretch/<n>/watch.md`: one line per change you
|
|
84
|
+
saw, with its time, in the order you saw it. The agent's stretch report
|
|
85
|
+
reads it, so the places the agent got stuck feed its proposals.
|
|
86
|
+
|
|
87
|
+
## The hook rule
|
|
88
|
+
|
|
89
|
+
If any loaded settings file names `rafa-tooling-hook`, if a skill named
|
|
90
|
+
`rafa-hookify` is installed, or if the agent's thread shows a hook
|
|
91
|
+
denial, alert the person at once.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rafa-stretch-gap-log
|
|
3
|
+
description: "Use when a stretch step needs raw gh, git or shell because no rafa line does it: file it as a module:cli-gap bug."
|
|
4
|
+
provenance: first-party
|
|
5
|
+
source: rafa
|
|
6
|
+
stage: alpha
|
|
7
|
+
prevents: "the same raw command typed every stretch with nobody noticing rafa could own it"
|
|
8
|
+
signal: silent
|
|
9
|
+
when_to_use: "You are rafa-stretch-engineer and a step you just took, or are about to take, has no rafa line: a raw gh, git or shell command, or a config edit by hand. Prevents: the same raw command typed every stretch with nobody noticing rafa could own it"
|
|
10
|
+
tags:
|
|
11
|
+
- rafa
|
|
12
|
+
- stretch
|
|
13
|
+
- cli
|
|
14
|
+
stack:
|
|
15
|
+
- shell
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Alpha: tested on rafa's own development, may become a feature.
|
|
19
|
+
|
|
20
|
+
# Gap log
|
|
21
|
+
|
|
22
|
+
A *gap* is a step rafa could own and does not yet: you had to type a raw
|
|
23
|
+
`gh`, `git` or shell line, or edit a config by hand, because no rafa line
|
|
24
|
+
does it. Each one is filed once, so the next bug sweep can turn the ones
|
|
25
|
+
that repeat into commands.
|
|
26
|
+
|
|
27
|
+
## Is it a gap?
|
|
28
|
+
|
|
29
|
+
- **Yes:** a step every stretch takes the same way, such as creating the
|
|
30
|
+
integration branch, or opening a pull request outside a loop.
|
|
31
|
+
- **Yes:** a flag you add every time, which rafa could read from the
|
|
32
|
+
scenario instead.
|
|
33
|
+
- **No:** a one-off investigation, or a `git` commit, push or rebase,
|
|
34
|
+
which stay `git`'s.
|
|
35
|
+
|
|
36
|
+
## Filing one
|
|
37
|
+
|
|
38
|
+
Search first, so a gap is filed once:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
rafa issue list --module=cli-gap --search="<the step in a few words>"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
When none matches, file it:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
rafa issue create --type=bug --module=cli-gap --title="<the step rafa cannot do yet>" --body="<the raw line, the rafa line that came closest, what it lacks>"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
When one matches, add the stretch's case to it:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
rafa issue comment <n> --body="Seen again in stretch <n>: <the raw line>."
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The board is public: no local path, host name, user name or secret in the
|
|
57
|
+
title or the body.
|
|
58
|
+
|
|
59
|
+
## Known at design time
|
|
60
|
+
|
|
61
|
+
These are filed or waiting to be, so search before filing them again:
|
|
62
|
+
|
|
63
|
+
- grouping duplicate bugs;
|
|
64
|
+
- opening a pull request outside a loop;
|
|
65
|
+
- creating the integration branch, and switching `pr.base` to it and back;
|
|
66
|
+
- installing the operators;
|
|
67
|
+
- a per-command log under `.rafa/logs/`, for reading a failure from
|
|
68
|
+
another device;
|
|
69
|
+
- detached loops;
|
|
70
|
+
- `rafa loop list` across projects.
|
|
71
|
+
|
|
72
|
+
List every gap you filed or commented on in the stretch report.
|