PR Conventions
PRs are evidence containers, not conversation. The conversation, the ledgers, and the task tracking all live on the issue — see issue conventions. This page covers only what's PR-specific.
PR body convention
PR bodies follow the same fjx-managed / agent-managed split as ledgers:
Refs: #<N>
---
<agent-managed body>
fjx pr create prepends the fjx-managed header (Refs: #<N>) and the --- separator automatically; the --body-file you supply is the agent-managed section below. The issue link is hard-required — fjx pr create refuses to open a PR without one (--issue <N> or the current issue from cache).
We deliberately use Refs rather than Closes / Fixes / Resolves so Forgejo does not auto-close the issue when the PR merges — fjx pm close <N> is the single canonical path to a closed issue, which avoids a "closed but not yet finalized" window. Closes / Fixes / Resolves are still recognized in PR bodies for legacy/external PRs (the issue → PR linker accepts any of them).
If two open PRs both reference the same issue, fjx dev next exits with code 2 — resolve by closing all but one.
What goes in the PR
- Code, tests, docs, runbooks, and
./wiki/findings/<N>-<slug>.mdartifacts (when applicable) - A short agent-managed body describing the change — fjx handles the issue link
What does NOT go in the PR:
- Task tracking — that's the ledger on the issue (see issue conventions)
- Back-and-forth conversation — assume PR comments are not read by working agents. Comment on the issue instead.
After Handoff
Once the developer runs fjx dev done <N>, the cycle is over. The agent exits. There is no in-process wait, no poll loop — the executor will re-invoke the agent on the next tick if there is work to pick up (revision requested, new comments, blockers cleared).
On the next invocation, the dev agent's stale-check (see Dev role) finds the issue still assigned to agent-dev and resumes it: read the QA and PM ledgers, address the findings in the same worktree/branch, and re-run fjx dev done <N>.
The serial single-developer model still holds across invocations — one PR open at a time — but it's enforced by the stale-check at the start of each cycle, not by waiting in-process.