Files
yellowjacket/.pi/prompts/next-issue.md
T
logan e62e12f6c6
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Failing after 35s
CI / e2e (pull_request) Skipped
docs(agent): let a scheduled run merge behind an independent review
The runs produced five green PRs and no way to land them without a person. What makes that safe to automate is not CI — the author writes the tests — but a reviewer in a fresh context: last night's caught two guards that left the whole suite green when deleted, an over-narrow sweep, and an overlay covering the artwork it was editing.

So the gate is seven conditions, and a Kind/Feature is never one of them. It can exist at all because a push to main publishes nothing here: release.yml is workflow_dispatch and the four publishers key on v* tags, so a wrong merge costs a revert rather than a package nobody can unpublish. The section says so, and says it is void if that changes.
2026-08-22 01:57:56 -04:00

9.3 KiB

description
description
Take on the next actionable backlog issue end to end, and stop

Take on exactly one issue from the YellowJacket backlog, end to end, and stop.

Repo: yonlu/yellowjacket at https://git.ljones.me — API base https://git.ljones.me/api/v1/repos/yonlu/yellowjacket, auth with -H "Authorization: token $GITEA_TOKEN". Default branch is main.

1. Orient before you pick

Read, in this order: CLAUDE.md (the architecture and the reasons behind it), .pi/journal.md (what happened last), .planning/NOTES.md (what was already considered and rejected), and .planning/plans/active/. Do not skip this because the issue looks small — most of this codebase's traps are written down in exactly one of those four places, and the ones that bite are the ones you didn't read.

2. Pick the issue

List open issues. Choose the single highest-value one that is actionable right now:

  • Order by Priority/CriticalHighMediumLow. Within a tier, prefer Reviewed/Confirmed, then Kind/Bug over Kind/Enhancement over Kind/Feature.
  • Consult issue #73 (the roadmap) — if it sequences the candidates, that ordering wins over the label ordering.
  • Skip anything labelled Status/Blocked, Status/In Progress, Status/Abandoned, Reviewed/Won't Fix, Reviewed/Duplicate, Reviewed/Invalid, or already carrying an open PR.
  • Skip anything someone else is already on. The label is not the only claim, because a concurrent session may not have applied it — several pi sessions run against this repo from separate worktrees under ~/.paseo/worktrees/. Run git ls-remote --heads origin and skip any issue whose number or slug matches an existing branch (60-…, fix/<slug>). A duplicated fix costs more than a skipped issue.
  • Skip anything that cannot be verified without hardware you do not have: physical-device Android behaviour (audio output, on-device file writes, real gesture input). A browser at 424px is not a phone — see the Chrome 113 section of CLAUDE.md.
  • Skip intermittent-failure issues unless you can reproduce the failure on demand within a few minutes. Chasing a 1-in-3 flake is an unbounded task and does not belong in a scheduled run.
  • If nothing qualifies, say so, do nothing, and stop. An empty run is a correct outcome.

3. Claim it

Add Status/In Progress to the issue and comment that you are picking it up. Then branch:

git fetch origin && git checkout -b <type>/<short-slug> origin/main

<type> matches the issue's Kind (fix/, feat/, refactor/, test/, docs/, ci/). Branch from origin/main, never by checking out main itself — this repo is worked from several git worktrees at once and main is checked out in one of them, so git checkout main fails outright.

4. Do the work

Fix the issue that was reported and nothing else. Match the surrounding code's style. Follow the constraints in CLAUDE.md rather than reasoning from first principles — where it explains why something is shaped the way it is, that shape is load-bearing and there is usually a test pinning it.

Anything else you discover becomes a new issue, not a bigger diff. File it with the right Area/, Kind/, Priority/ labels, describe the symptom before the theory, and link it from your PR. Scope creep is the failure mode this instruction exists to prevent.

If the work turns out to be materially larger than the issue implied, stop: comment on the issue with what you found and what it would actually take, remove Status/In Progress, push nothing, and end the run.

5. Verify — the right tier, not the cheapest one

Run make generate if you touched .sql or .templ, and make bindings if you changed a bound Go signature. Then run what the change actually demands:

  • Go change → make lint and make test (both cover all three build configurations).
  • Frontend component or store → make ui-test.
  • User-visible flow → make e2e against make dev-headless. Check the port first: ss -ltn | grep 34115. If it is occupied, another worktree is already running the app — do not start a second one and do not run make e2e. Attaching to someone else's build produces a green result about code that is not yours, which is worse than no result. Either choose an issue that does not need this tier, or stop and say why.
  • Anything cosmetic or layout-related → look at a screenshot. Several bugs in this repo's history were invisible to every assertion and obvious in an image.

A tier you skipped is a claim you did not check. If a tier fails for reasons unrelated to your change, say so explicitly rather than quietly moving on.

6. Keep the documentation true

If you changed structure, behaviour, or a constraint, update CLAUDE.md in the same commit. That file is this project's memory; a change that leaves it describing the old shape is worse than no change. Append a short entry to .pi/journal.md covering what you did, what you verified, and what you left open.

7. Commit and open the PR

Conventional Commits, imperative subject, ≤72 chars, scope optional. The body explains why. Push the branch — never push to main, never force-push.

Open the PR:

curl -sS -X POST \
  -H "Authorization: token $GITEA_TOKEN" \
  -H "Content-Type: application/json" \
  https://git.ljones.me/api/v1/repos/yonlu/yellowjacket/pulls \
  -d '{"head":"<branch>","base":"main","title":"<subject>","body":"<body>"}'

The body states: what the issue was, what you changed and why, which verification tiers you ran and their results, anything you deliberately did not do, and Closes #<n>.

Then wait for CI (ci.yml, jobs check and e2e) and report the result on the PR. If it fails, read the log — gitea_ci's job_logs 404s on this Gitea build, so use GET /api/v1/repos/yonlu/yellowjacket/actions/runs/<run>/jobs for per-step status and GET /api/v1/repos/yonlu/yellowjacket/actions/jobs/<id>/logs for the log — and fix it. Two consecutive failed CI runs on the same cause: stop, comment what you know on the PR, and leave it for a human.

Do not merge, and do not review your own work. Comment on the issue linking the PR, leave Status/In Progress on, and end the run. Whether this merges is decided by a reviewer that did not write it — see below. A CI run is not a review: it proves the tests you wrote pass, which is exactly the thing an author is worst placed to judge.

Finally

Report in three lines: which issue you took, what state it is in (PR open / CI green / stopped and why), and any issues you filed.


The merge gate

This half is not run by the author. It is run against a PR by someone who has not seen the branch before, and it decides whether the work lands on its own or waits for a human.

A push to main publishes nothing here — release.yml is workflow_dispatch only and all four publishers key on v* tags — so the cost of a wrong merge is a bad commit on main and the time to revert it. That is the whole reason this gate can exist. If that ever changes, this section is void.

Merge only when every one of these is true. Any single no means leave it open.

  1. An independent review of the diff returns MERGE or MERGE WITH NITS. CHANGES NEEDED, or a review that could not reach a verdict, means a human looks.
  2. CI / check (pull_request) and CI / e2e (pull_request) are success on the PR's current head. Ignore the (push) contexts — they are skipped by design and Gitea folds skipped into a combined state of pending that never clears.
  3. The PR is mergeable with no conflicts, rebased onto current main.
  4. The diff touches none of: .gitea/workflows/, .releaserc.yml, packaging/, build/, scripts/gitea-release.sh, backend/database/sql/schemas/, backend/database/staleshape*.go, go.mod, go.sum. These either publish to somewhere a mistake cannot be taken back from, or can destroy a database that a user cannot rebuild.
  5. The issue is Kind/Bug, Kind/Testing, Kind/Documentation or Kind/Enhancement. A Kind/Feature is a design decision and is never auto-merged, however green it is.
  6. The diff is under ~600 changed lines across under ~15 files. Past that, "a reviewer read it" stops being a claim anyone should take on trust.
  7. The PR does not claim to have verified something no tier here can see. A change whose evidence would have to come from a physical device is reported, not merged.

When it merges, use {"Do":"merge"} on POST /api/v1/repos/yonlu/yellowjacket/pulls/<n>/merge. Then check the issue actually closed — a squash or an edited merge message drops the Closes footer — and close it by hand with a comment naming the commit if it did not. unclaim.yml strips Status/In Progress on close; if the label is still there a minute later, strip it yourself.

When it does not merge, say so on the PR in one paragraph: which condition failed and what would satisfy it. Leave the PR open, leave the label on, and file the review's substantive findings as issues so they are searchable rather than buried in a PR comment.

A nit is not a blocker, and it is not free either. A MERGE WITH NITS merges, and each nit worth keeping becomes an issue. Do not fix nits on the branch: that is a second author pass with no second review, which is the thing this gate exists to prevent.