# Developer (`agent-dev`) DEV is the **worker**. It claims issues, follows the brief PM wrote, opens PRs, and hands off for review. DEV is the role with the highest output volume and the tightest leash. DEV is the only working agent with code-write authority. Every commit, every branch, every PR in the FJX workflow originates here. ## The cycle 1. `fjx dev next []` — start the next cycle in one shot: pick (or load ``), set up the worktree at `../worktrees/-`, claim (label + assignee + initial ledger), and print `` to stdout. Run from the main checkout, not a worktree. **One worktree, one branch, one PR per issue across all phases** — `propose` → `apply` reuses the same worktree. 2. `cd` into the printed worktree path and follow the brief to the right phase prompt. 3. Work. Keep the ledger current (`fjx dev ledger --body-file ./tmp/ledger.md --status working`). Mark tasks complete with evidence (commit SHA or explanation); add new tasks for any directives that arrive on the issue. 4. Open the PR with `fjx pr create --title --head <branch> --body-file ./tmp/pr-body.md`. `Refs: #<N>` is prepended for you; do not write it yourself. 5. Final ledger update (`--status review`), then `fjx dev done <N>` — assigns the linked PR to `$FJX_OWNER`, transitions the issue to `agent/review`, and reassigns the issue to `agent-pm` for routing. Run `just validate` before submitting a PR. Fix any failures and re-run until clean. If the PR comes back (issue reassigned with `agent/review`), read the QA and PM ledgers, address the findings in the same worktree/branch, and re-run `fjx dev done <N>`. ### Stale-check startup Before running `fjx dev next` to pick up new work, first check for anything already assigned: ```sh fjx issue list --assignee agent-dev --state open fjx pr list --assignee agent-dev --state open ``` If results exist, resume that work rather than claiming something new. This is the stopgap for dropped sessions, crashes, or interrupted cycles. ### Serial single-developer model Finish the current PR before claiming the next issue. This avoids merge conflicts and keeps the feedback cycle tight. The stale-check above is the enforcement point — each cycle starts by checking for prior assignments before picking up new work. ## Phases The brief routes DEV to one of four phase prompts. Each has a distinct output shape and scope rule: - **`simple`** — typo, comment, obvious one-line fix. Issue body is the spec. Most common derailment: "while I'm here" cleanups that turn a simple change into a non-simple change. - **`investigate`** — veracity, root cause, and impact are unknown. Output is a `wiki/findings/<N>-<slug>.md` file, not necessarily code. Investigation IS the work. - **`propose`** — draft a spec via `/openspec-propose`. Output is a **draft** PR with the proposal only — no implementation. Wait for `/spec-approved` or `/spec-rejected`. - **`apply`** — implement an approved spec via `/openspec-apply-change`. Same worktree and branch as the proposal — spec commits stay, implementation lands on top, draft PR is marked ready. Finish with `/openspec-archive-change`. Routing is by brief, not by label. The phase lives in the PM brief, not in `agent/*` labels. ## The tight leash The DEV prompt is deliberately imperative. Two reasons: DEV's output volume is highest (so prompt-level slop compounds fastest), and DEV's actions have the largest blast radius (commits, PRs, branches). Concretely: - **Operating directive on `fjx` usage.** If a `fjx` command errors, default assumption is *you invoked it wrong* — run `--help`, don't reach for the raw API. Named anti-pattern in the prompt. - **Evidence-required blocker checklist.** A blocker ledger entry must cite four things: `--help` output, error grep evidence, brief re-read step, one-line classification. Without all four, the blocker reads as "I gave up after one try" and is sent back. - **Hard action surface.** No editing `.forgejo/workflows/*`, `Justfile`, or other CI/tooling files unless the issue explicitly says so. No force-push, no `--no-verify`, no `git reset --hard` on shared refs. Never commit on `main`. - **Bounded retries.** Cap `just validate` fix attempts at 10. Cap merge-conflict resolution at 3. After 5 validate-fix cycles on one issue, or 3 bootstrap cycles without a merged PR, stop and wait. - **Stay in scope.** New findings are filed as separate issues, not absorbed into the current PR. No drive-by refactors, no "while I'm here" cleanups. ## Blockers If you hit something you can't get past, **report it — don't go silent and don't quietly downgrade the work.** An error is not automatically a blocker. Before you may declare one, the blocker ledger entry MUST cite evidence of all four checks: - `fjx <subcommand> --help` output for the failing command (paste the relevant line). - The verbatim error and the result of grepping `./wiki` and the issue ledger for the same symptom. - The phase prompt and brief re-read — name the step you re-checked. - A one-line classification: `just validate` flake, tool collision (`rtk`), fjx gap, or unknown. A blocker without all four reads as "I gave up after one try" and will be sent back. Only with the checks recorded, **before stopping work**: 1. `fjx dev ledger --body-file ./tmp/ledger.md --status blocked` with the blocker section filled in: the error verbatim, what you tried, why each attempt failed, and the smallest concrete unblock you need. 2. Apply the `agent/blocked` label: `fjx issue label <N> -A agent/blocked`. 3. Exit cleanly. Do not hand off as if work is complete. Recording the blocker IS the way to finish the cycle when you can't. Blockers move; the unrecorded blocker is the one that stays stuck. ## Hard rules - No `--no-verify` on git hooks. If a hook fails, fix the cause. - No force-push, no `git reset --hard` on shared refs. - Never commit on `main`. - Branch from current `main`: `git fetch origin && git checkout -b <type>/<short-slug> origin/main` (type ∈ `feat`, `fix`, `chore`, `docs`). - Do not edit `.forgejo/workflows/*`, `Justfile`, or other CI/tooling files unless the issue explicitly authorizes it. - Do not close or reopen issues other than the one you claimed. - One worktree, one branch, one PR per issue across all phases. ## Why the leash is tight here DEV is where the cost of slop compounds fastest. A PM that drifts wastes a few tokens on a clumsy brief. A QA that drifts produces a wrong verdict that the human still reviews. A DEV that drifts ships a bad commit, mangles the branch, or pushes a force update that loses work. The narrow prompt and bounded retries are the trade-off for giving DEV the only code-write keys in the system. ## See also - The DEV bootstrap prompt: [`src/prompts/dev-bootstrap.md`](https://git.tfks.net/tfks/fjx/src/branch/main/src/prompts/dev-bootstrap.md) - Phase prompts: [`dev-simple.md`](https://git.tfks.net/tfks/fjx/src/branch/main/src/prompts/dev-simple.md), [`dev-investigate.md`](https://git.tfks.net/tfks/fjx/src/branch/main/src/prompts/dev-investigate.md), [`dev-propose.md`](https://git.tfks.net/tfks/fjx/src/branch/main/src/prompts/dev-propose.md), [`dev-apply.md`](https://git.tfks.net/tfks/fjx/src/branch/main/src/prompts/dev-apply.md) - [Issue conventions](../primitives/issue.md) (ledger model, task discipline) - [PR conventions](../primitives/pr.md) (body format, handoff)