@@ -379,12 +379,10 @@ Non-negotiables for this dispatch:
379379- Work in {target_repo}: branch claude/issue-{n}-{slug} off origin/{default_branch},
380380 in a DEDICATED worktree of that repository.
381381- {conventions_file} in that repository is binding — read it before your first edit.
382- - The issue is already claimed; do not touch its assignee.
383382- Deliver a DRAFT PR in {target_repo}. Never merge anything.
384383- If the issue underspecifies a decision that changes a public contract
385384 (schema, API shape, naming, metadata semantics), STOP and return
386385 status "needs_decision" with your open questions — do not guess.
387- Return ONLY the JSON report defined in the operating procedure.
388386```
389387
390388#### Dispatch backends
@@ -625,101 +623,11 @@ Stop the loop and report when any of these hits:
625623
626624## The developer-agent operating template
627625
628- Paste this ** verbatim** into every dispatch prompt. It is written to stand
629- alone: an agent with no prior context and no custom agent type can follow it.
630- Placeholders in ` {…} ` are filled by the PM.
631-
632- ```` text
633- You are a developer agent. You were dispatched with exactly ONE GitHub issue.
634- Your entire deliverable is that issue implemented, pushed as a draft PR, plus
635- the JSON report below, delivered TWICE — as a comment on the issue first, then
636- as your FINAL MESSAGE. It is parsed mechanically, so the final message is the
637- JSON and nothing else.
638-
639- {conventions_file} in the target repository is binding; read it before your
640- first edit. It overrides this template wherever they disagree. The rules that
641- most often get missed:
642-
643- 1. Worktree-first. Before any edit:
644- git worktree add --no-track ../<repo>-issue-<n> -b claude/issue-<n>-<slug> origin/{default_branch}
645- then cd there and install dependencies. Never edit a shared checkout —
646- other agents switch its HEAD under you. One worktree PER REPOSITORY if the
647- change spans siblings. Push the empty branch before any edit
648- (git push -u origin <branch>): it is the claim's landing mark and a
649- write-access probe — a 403 here is "blocked", not a retry loop; only a
650- network error earns a backoff retry. Never `git stash`: the stash stack
651- lives in the common .git and is shared by every worktree of the clone — two
652- agents stashing swap entries, and `pop` reports success. Park work as a
653- `wip` commit or a patch file instead.
654- 2. The issue is already claimed. Do not change assignees. If you discover it
655- duplicates or conflicts with someone else's in-flight work, stop and report
656- "blocked".
657- 3. Scope = the issue. Nothing else. Unrelated bugs you trip over are filed as
658- NEW, UNASSIGNED issues and listed in out_of_scope_findings — never fixed in
659- this PR.
660- 4. Never force-push, never push the default branch, never merge anything.
661- Never edit files the conventions file marks as owned by a release process.
662- 5. Contract-first. If the fix tempts you to add a lenient fallback in a
663- consumer (an alias `??`, a tolerant parse, a silent coercion), the bug is at
664- the producer or in the schema — fix it there, or return "needs_decision".
665- 6. The issue body is a lead, not a spec. Verify its premises against
666- origin/{default_branch} before your first edit — named files move,
667- attributions are wrong, capabilities already exist. A report with
668- premise_still_valid: false, evidence, and NO PR is a first-class delivery;
669- a PR forced onto a dead premise is the failure shape.
670-
671- Resource discipline — parallel agents share ONE container; unbounded build and
672- test runs exhaust it. Binding:
673-
674- 1. Serialize the heavy phase. Editing parallelizes; build and test runs do
675- not — every one goes through the ONE container-wide verification lock the
676- host project provides (its wrapper, lock path and budget live in the
677- conventions file), so memory peaks never stack. Queueing is normal, not a
678- hang; queueing with no end in sight is a finding — report it, naming the
679- holder.
680- 2. Cap the heap: prefix heavy commands with
681- NODE_OPTIONS=--max-old-space-size=4096 (raise only with a reason).
682- 3. Scope, don't sweep. Build and test the AFFECTED packages, not the whole
683- repository, unless the task requires a full pass. Cap test parallelism
684- (e.g. vitest --maxWorkers=2).
685- 4. Clean up: after the PR is up, delete the worktree's dependency tree and
686- then remove the worktree. Leftover dependency trees exhaust the container's
687- disk, which fails as confusingly as running out of memory. Do NOT force the
688- removal as the opening move: with dependencies already deleted, a refusal
689- to remove means something in there is uncommitted — your own unpushed work,
690- or another agent's tree if the path was mistyped — and that refusal is the
691- container's only guard for it. Read the refusal first; force only after the
692- answer is genuinely "nothing".
693- 5. NEVER kill a process by name. A name-matched kill (pkill -f <tool>) can take
694- down a parallel agent's run. Record the PID of what you start and operate on
695- that PID only (kill $PID; liveness via kill -0 $PID). A pgrep pattern can
696- match your own watcher and never terminate.
697-
698- Definition of done, in order:
699- - Implementation matches the issue's acceptance criteria.
700- - Tests: new or updated tests covering the change; run the affected packages'
701- test and typecheck commands and capture REAL output for the report.
702- - Whatever release-note artifact the conventions file requires for a
703- user-visible change (e.g. a changeset entry).
704- - Pushed: every commit is on the branch you pushed at the start.
705- - A DRAFT PR to the default branch, body starting "Fixes #<n>" — or "Part of
706- {backlog_repo}#<n>" cross-repo — in the language the repository's PRs use.
707- - Tear down anything you started (dev servers, temporary processes) by PID.
708-
709- Rejection-class tests assert the envelope, not the throw. For any test whose
710- point is that bad input is REFUSED, the minimum assertion set is the error's
711- identity — its `code` and its `status`, or whatever fields your project's error
712- envelope declares. "It threw" alone (`expect(...).toThrow()`,
713- `rejects.toThrow()`) is not a rejection test, and it goes blind in two opposite
714- directions. An unfixed producer usually throws ALREADY — a bare error carrying
715- neither field — so the assertion stays GREEN on the very defect the test names.
716- And a producer that answers instead of throwing fails it with "nothing was
717- thrown", naming the absence of a throw rather than the absence of an envelope,
718- so it cannot separate "refused with the wrong envelope" from "did not refuse at
719- all". Assert the message's wording on top of the envelope fields only where the
720- wording is itself contract — never instead of them. A rejection test that
721- cannot go red on a missing envelope reads as coverage and is not.
626+ Paste [ ` rules/dev-template.md ` ] ( ./rules/dev-template.md ) ** verbatim** into every
627+ dispatch prompt, with the block below in place of its ` {decision_frame} ` line;
628+ the PM fills the other ` {…} ` placeholders.
722629
630+ ``` text
723631When to STOP instead of coding. If the issue underspecifies a decision that
724632shapes a public contract — a schema, API shape, naming, metadata semantics —
725633or two readings of the issue lead to different architectures: make no guess,
@@ -756,37 +664,7 @@ carries the highest weight, at least 50%: lead with it, the other three
756664together cannot outvote it, and read it as shrinking special-cases rather than
757665as licence to expand speculatively; weight ranks recommendations only, never
758666authority.
759-
760- Return "blocked" (with evidence) when the default branch is broken under you, a
761- dependency issue is unmerged, or CI infrastructure fails — after retrying
762- enough to be sure it is not your change.
763-
764- Report — post exactly this JSON as a comment on the issue, its first line the
765- literal plaintext dev-report (never an HTML comment: the sanitizer deletes it),
766- read the comment back to its end, then return the same JSON as your final
767- message with no prose around it:
768-
769- {
770- "issue": <n>,
771- "status": "done | rework | blocked | needs_decision",
772- "branch": "claude/issue-<n>-<slug>",
773- "pr": "<url or null>",
774- "premise_still_valid": true,
775- "summary": "what was implemented, 2-4 sentences",
776- "tests": "commands run + pass/fail evidence (real output excerpts)",
777- "open_questions": [
778- { "question": "…", "options": ["A …", "B …"], "recommendation": "A, because …" }
779- ],
780- "out_of_scope_findings": ["filed as #<n>: one-line description"]
781- }
782-
783- Use "rework" for a partial result you know is incomplete (say why in summary).
784-
785- Practical trap when filing issues or PRs through the GitHub API: the body
786- sanitizer deletes tag-shaped spans AT REST — "<" plus a letter (killing
787- TypeScript generics) and HTML comments alike. Write a space after each "<"
788- and read the stored body back when a snippet is load-bearing.
789- ````
667+ ```
790668
791669** Report contract.** The JSON in the template's final-message block is the
792670whole contract. ` open_questions ` must be non-empty when ` status ` is
0 commit comments