Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion docs/primitives-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Transfer recipes map the same loop shape onto each host:
| 4. Verification | Create a verifier named agent with `opencode agent`; invoke via `opencode run "Verify diff" --agent verifier --file diff.patch` | `.cursor/agents/loop-verifier.md` from `templates/SKILL.md.verifier` | Add review step at end of workflow; human gate on denylist paths |
| 5. Connectors | Configure MCP or CLI bridges in `opencode.json` | Enable GitHub MCP read-only for issue/PR discovery | Configure GitHub MCP in Cascade settings |

## Appendix: Aider CLI
## Appendix: Aider CLI

Aider is CLI-first rather than a loop host with native schedulers, so map the same primitives from [Choosing a Tool](#choosing-a-tool) onto shell scripts, cron, and git branches.

Expand Down Expand Up @@ -205,6 +205,63 @@ A Gemini CLI daily triage loop:
5. Do not edit source files during the first week.
6. Save updated state for the next run.

## Appendix: Amazon Q Developer CLI

Amazon Q Developer CLI (`q chat`) is a terminal-based agent, AWS-native, with custom agent
profiles and MCP support. Map the same loop primitives onto `q chat`, custom agent configs,
context resources, and external schedulers.

| Primitive | Amazon Q Developer CLI mapping |
|-----------|--------------------------------|
| Scheduling | No native cron-style scheduler. Use external schedulers (cron, systemd timers, GitHub Actions) to invoke `q chat` non-interactively, or `q chat --resume` to continue a saved per-directory conversation on the next scheduled run. |
| Rules / Context files | Define a custom agent in `.amazonq/agents/<name>.json` (project) or `~/.aws/amazonq/cli-agents/<name>.json` (personal), and list always-on context in its `resources` field (e.g. `file://STATE.md`, `file://.amazonq/rules/**/*.md`). Use `hooks.agentSpawn` to inject fresh context (like `git status`) at session start. |
| State | Keep `STATE.md` at the repo root, referenced in the custom agent's `resources` field so it's loaded every session; each run should read then update only the relevant section. |
| Maker/checker split | No native subagent/reviewer primitive. Workaround: define two custom agents (e.g. `daily-triage.json` with write tools, `loop-verifier.json` restricted to `fs_read`/`@git` only) and run the verifier agent over the diff in a separate `q chat --agent loop-verifier` session. |
| Connectors | Configure MCP servers in `.amazonq/mcp.json` (project) or `~/.aws/amazonq/mcp.json` (global); scope tool trust per agent via `allowedTools`. Treat workspace `.amazonq/mcp.json` files from untrusted repos with caution — review before opening, since auto-loaded MCP configs have been a real attack vector for this class of tool. |
| Honest gaps | No first-class scheduler, no built-in maker/checker separation, no dedicated state-file convention — these are all manual conventions layered on top of `q chat`, same as most terminal agents without a purpose-built loop scheduler. |

Minimal transfer recipe:

```bash
mkdir -p .amazonq/agents .amazonq/rules
cp templates/SKILL.md.loop-triage .amazonq/rules/loop-triage.md
cp starters/minimal-loop/STATE.md.example STATE.md
```

`.amazonq/agents/daily-triage.json`:

```json
{
"name": "daily-triage",
"description": "Report-only daily triage agent",
"prompt": "Run loop-triage. Update STATE.md with High Priority and Watch List only. Do not edit source code in week one.",
"tools": ["fs_read", "fs_write"],
"resources": [
"file://STATE.md",
"file://.amazonq/rules/loop-triage.md"
]
}
```

### Week-one Daily Triage prompt (report-only, copy-paste)

```bash
q chat --agent daily-triage --no-interactive \
"Run loop-triage. Read STATE.md first. Update only High Priority and Watch List sections. Do not edit source code in week one."
```

Verifier pass for later L2 work — a separate, read-only-scoped agent:

```bash
git diff > diff.patch
q chat --agent loop-verifier --no-interactive \
"Act as loop-verifier. Review diff.patch against STATE.md goals. Report PASS/FAIL and do not edit files."
```

After copying: map scheduling to cron/systemd/GitHub Actions until Q has a first-class
loop scheduler. Use `.amazonq/rules/` for always-on repo guidance, separate custom agents
for maker/checker separation, and `.amazonq/mcp.json` for external tools.

### Official Documentation

https://github.com/google-gemini/gemini-cli
83 changes: 83 additions & 0 deletions stories/loop-worktree-week-two.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Week Two with loop-worktree: PR Babysitter, one fix at a time

**Pattern:** PR Babysitter
**Tool:** loop-worktree (paired with loop-context)

## What I was doing

I was running a small PR Babysitter loop: watch a PR, try a fix in isolation,
verify it, and only escalate to a human if the fix doesn't land. The part I
wanted to get right this week was making retries safe — if attempt #1 fails,
attempt #2 shouldn't be fighting attempt #1 for the same branch.

## The workflow

For each fix attempt, I create an isolated worktree keyed to the run:

```
npx @cobusgreyling/loop-worktree create --run-id pr-42-fix-1 --pattern pr-babysitter
```

That gives me a fresh checkout under `.loop-worktrees/pr-42-fix-1` on its own
branch (`loop/pr-42-fix-1`), tracked in `.loop-worktrees/manifest.json` — so
nothing touches the branch another attempt might still be using.

Once the verifier rejects an attempt, I mark it rather than deleting it
immediately — that keeps the audit trail intact:

```
npx @cobusgreyling/loop-worktree mark --run-id pr-42-fix-1 --status rejected
```

`list` gives me a quick read on what's currently tracked:

```
npx @cobusgreyling/loop-worktree list
```

And periodically I sweep anything rejected or escalated:

```
npx @cobusgreyling/loop-worktree cleanup --status rejected --older-than 24h
```

## Pairing with loop-context --check

Before letting the loop retry again, I run the ledger through
`loop-context --check` so a stuck fix doesn't just keep burning attempts:

```
npx @cobusgreyling/loop-context --check --ledger run.json --stagnation 3 --json
```

With three identical failures in a row it stayed green (`shouldContinue: true`),
but on the fourth repeat of the same error it correctly flipped to
`escalate: true` with exit code 2 — which is the signal I use to stop the loop
and hand the PR back to a human instead of trying a fifth time.

## The surprise

The gotcha that cost me the most time: `--check`'s stagnation trigger only
recognizes attempts with `"outcome": "failure"` exactly. I'd first logged
attempts as `"outcome": "fail"` — `--summary` and `--status` happily counted
those as failures and showed the repeated error, so everything *looked*
right, but `--check` never escalated no matter how many times the same error
repeated. Nothing errors out to tell you the value was wrong; the breaker
just quietly stays at "continue." Since the whole point of pairing
loop-worktree with loop-context is to stop a bad retry loop before it wastes
a worktree (and tokens) on a fix that isn't working, a silently-inert circuit
breaker is exactly the failure mode you don't want.

Separately, a smaller but good surprise: `cleanup --older-than 24h` refused
to remove a worktree I'd just marked rejected seconds earlier — it only acts
once the attempt is actually old enough (or you pass `--force`). That's the
right default; I just didn't expect it on first try and thought the command
had silently no-op'd.

## What I'd change

I'd want `--check` to validate the `outcome` field against the documented
enum and fail loudly (or at least warn) on an unrecognized value, instead of
silently treating it as a no-op for the stagnation/no-progress triggers while
`--summary` keeps counting it as a failure. Right now the two commands can
disagree about the same ledger without telling you.