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 [<N>] — start the next cycle in one shot: pick (or load <N>), set up the worktree at ../worktrees/<project>-<N>, claim (label + assignee + initial ledger), and print <!-- pm:brief:dev --> to stdout. Run from the main checkout, not a worktree. One worktree, one branch, one PR per issue across all phasesproposeapply 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 <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:

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