work-implement
Take one tracked issue, implement it, and push it so a different agent can review it — the stateless implement-unit behind work-implement-queue. One issue, one tracker (GitHub via gh or Linear via its MCP), picked per-repo by the same committed config the issue skill uses. State lives in the issue's lifecycle label, never in the agent — so a crashed run resumes instead of restarting.
This skill is the implement half of a two-loop workflow: it builds and pushes; work-review then reviews the pushed work. It never reviews its own output and never sets done — its terminal outputs are reviewRequested (handed to the review loop), blocked, or skipped (contradictory labels — reported, tracker untouched).
Opted out? If the repo config sets work to false, this skill is disabled for the repo (as are the other work-* skills) — stop immediately and tell the user the work skills are turned off in .tituskirch-skills.json. An absent work block is not disabled (it falls back to defaults). Check .work == false on the resolved config before any action — and before indexing .work.*. A missing jq or config exits non-zero too, so a pass is not evidence the config was read.
Workflow
1. Load config & resolve tracker
Resolve .tituskirch-skills.json via templates/resolve-config.sh, never by reading the raw file (REFERENCE.md states how, missing jq included); the work.* section holds tracker, label lifecycle, branch strategy, the feedback destination and Linear scope. Resolution per setting: config → default. Determine the tracker (work.tracker, falling back to issue.tracker) and confirm it is available/authenticated. Reuse the issue catalog cache for labels/teams/states.
Config schema, the full lifecycle and everything a run needs whatever its tracker: REFERENCE.md. The tracker recipes are one file each, and this step settles which: trackers/github.md, trackers/gitlab.md, trackers/linear.md, trackers/local.md.
2. Resolve the target issue
- Explicit — an id/number/key the user names (
/work-implement 42, ENG-123). A human naming the issue is the opt-in, so an unlanded prerequisite does not veto it — say so in the report and work it, the way a body contradicting the label is surfaced rather than obeyed.
- Self-select — none given → run the selection query and take the single highest-priority eligible issue (a
ready or a changes-requested issue). That query defers an issue whose prerequisite has not landed — under worktree too, since branching off a clean pr.base cannot see it (dependency ordering). None eligible → say so and stop.
3. Read the issue's state → pick the action
The lifecycle label decides what this run does — this skill is a state machine over one issue, and it only acts on the states it owns:
- fresh (
ready) → claim and implement from the body (steps 4–8).
- re-work (
changes-requested) → claim and implement from the body plus the review feedback (the reviewer's PR review / issue comment) — steps 4–8.
- resume (
working) → a previous run leased it and crashed; continue where it left off (re-assert a clean tree first).
- not ours (
reviewRequested / reviewing / needs human / done) → nothing to do here; reviewRequested, reviewing and needs human belong to work-review and the human. blocked → leave it unless the user explicitly re-runs it; report why it was blocked.
Read the whole label set, not just the lifecycle one. An issue carrying labels.needsTriage (when the repo configures it) alongside ready or changes-requested is two humans contradicting each other — "nobody has assessed this" against "approved, pick it up". Skip it: no lease, no label, no assignee, no comment — and name the contradiction in the run's report so a human clears it. Do not obey the more permissive label, and do not write blocked — the work is not blocked, a label is wrong (contradictory labels). This is a third terminal output alongside reviewRequested and blocked, and the one that leaves the tracker untouched. The check runs here, at claim time, even when a drain already partitioned the queue — the label can be added between the queue build and the lease.
4. Claim the issue (lease) — before any work
Flip the label to working (ready → working or changes-requested → working) and assign the issue to the runner first, then start. The claim is the race-breaker: a second consumer sees it is no longer eligible and skips it. Honour the single-flight lock — take it (direct run) or run under the drain's (queue). Already working with committed work → this is a resume, not a double-claim.
5. Prepare the branch
Assert a clean tree first. Then per work.branch:
worktree — a fresh branch off pr.base (e.g. dev) named for the issue. The name carries the run's queue mode: ai/<ref>-<slug> normally, ai/queue/<ref>-<slug> when work.queueBranch is on — that prefix is the only signal the repo's grouping workflow ever gets, so it is what decides whether this PR is grouped. Own branch → own PR. For a re-work, check out the issue's existing branch instead of branching fresh — which is why the mode binds to the issue, not to the round. Where the branch is cut from is pr.base either way; queueBranch moves only the name here and the PR's base at step 8.
branch:<name> — work on that shared branch (e.g. branch:dev); commits land there directly (review happens after they land — see review-after-land).
Branch naming, parallel/worktree handling and serialized integration: REFERENCE.md.
6. Implement
Re-read the issue body each run — live tracker state, not a cached memory. The body is the source of truth for scope and requirements; it is not the source of truth for eligibility — the lifecycle label settled that at step 3 and stays operative. A body line contradicting the current label ("early idea", "intentionally not ai: ready") is stale text, not a veto: do the work and surface the conflict — warn in the run's report and note it at the feedback destination. Never let it silently override the label into a block.
Read the comments too, and settle body against comment by rule rather than by escalating. The body is the scope, so a newer body edit supersedes an older comment — unless that comment explicitly revised a named earlier decision ("this revises the comment above") and the body never mentions the revision, in which case the revision is the live decision and the body is the stale text. Follow the surviving statement, and name both — the two statements, their timestamps and which one this run followed — in the report and at the feedback destination: body vs comment precedence.
- fresh → do the work the body describes.
- re-work (
changes-requested) → read the review feedback first (the reviewer's changes-requested PR review or issue/Linear comment — look in both places, since work.feedback routes only where feedback is written), address exactly that, then the body. The feedback is why this issue came back.
Test-drive whatever a test can reach. Where the change touches code, drive the tdd skill and run its loop in full — red before green, one vertical slice at a time, tests at seams rather than internals. tdd has the human confirm the seams before any test is written, and unattended there is nobody to ask: the issue body stands in for the human, so the requirements and acceptance criteria are the agreed seams (ai: ready is already a human's approval). Code touched and the body yields no seams → blocked (step 7's exit) — never seams the run picked for itself. A prose-only change (a SKILL.md edit, a README) drives tdd not at all, and that is explicitly not a block: a missing seam only blocks when there is code behind it. Red inside this step is the loop working as designed and never blocks — step 7 stays the only gate. tdd is optional: not installed → implement exactly as today, no discipline driven and no block. Note what was driven, and what came of it, on the issue / PR at step 8 — it tells work-review, it does not bind its verdict. Mechanics: REFERENCE.md.
When the issue itself is a bug, the work is the diagnosis — drive diagnosing-bugs and build a feedback loop that goes red on this bug before hypothesising, instead of reading code for a theory. Optional call: not installed, implement as today. What it changes here, and the rung of its ladder an unattended run cannot reach: REFERENCE.md.
Keep the change scoped to this one issue.
7. Verify
Run the repo's checks (the root verify key, else detected — tests, lint, build). Working in a worktree (parallel: true) means a tree with no dependencies installed — git worktree checks out tracked files only — so install from the lockfile there first, or the gate never touches the versions this branch pins (how). A run in the working tree already has them and skips it. Green → continue. Red and unfixable, spec ambiguous, or a genuine human decision needed → set blocked, comment the reason at the feedback destination — a run that blocks here has pushed no PR yet, so in pr mode that falls back to the issue — and stop; a code change whose body yields no seams is one such ambiguity, raised at step 6 and exiting here. blocked is a real outcome, not a failure to hide.
Red is the one limb of the block clause with a procedure behind it: red → drive diagnosing-bugs before calling it unfixable. "Unfixable" is the cheapest legitimate exit from a drain — it ends a run without failing it — so it is earned by a loop that was actually built, never asserted. Spec ambiguous or a genuine human decision needed → set blocked straight away; neither is a bug case, and no reproduction answers them. When the diagnosis lands on a cause outside this issue's scope, or no loop can be constructed at all (the skill's own stop rule), set blocked — commenting which loop constructions were tried and how each failed, not merely the conclusion — and stop. Optional call: not installed, block exactly as today. blocked is a real outcome, not a failure to hide. Entry points, the unreachable rung and what the comment carries: REFERENCE.md.
8. Commit, PUSH, hand off to review
The push is the moment the work becomes reviewable — it is the boundary between working and reviewRequested.
- Commit via
atomic-commit; reference the issue so the tracker links it (Refs #42 / the Linear key). atomic-commit is optional — not installed, commit directly in the repo's own Conventional Commits conventions, carrying the same reference line.
- PUSH the work: open/update the PR via
pull-request (worktree), or push the commit(s) to the shared branch (branch:<name>). pull-request is optional too, and only the worktree path reaches it at all — not installed, open the PR with the forge CLI directly, same base and head. The base is pr.base, unless work.queueBranch is on and exactly one ai/queue-* PR is open against pr.base — then it is that PR's head. Resolve it here, per issue, never once for the drain: the repo's workflow cuts the queue branch in response to the first worker PR, so it can appear mid-drain. None open is not an error — open against pr.base and carry on. Report the base you set; a workflow moving it afterwards is the design working, not drift, and is never corrected. Until this succeeds the issue stays working (a crash before the push is reclaimed as a working-orphan).
- Open that PR as a draft, and leave it a draft — every round, whether
pull-request opened it (it opens ready by default, so ask it for a draft) or the forge CLI did. This skill never marks a PR ready for review: that flip means the review believes this is finished, which is not something the author of the change gets to say, and it is work-review's to make. A re-work pushes onto whatever draft state the PR already carries and leaves it exactly as found — an already-ready PR stays ready, never goes back into draft. Why, and what a repo's workflows owe the mechanic: the draft gate. Under branch:<name> there is no PR and nothing here applies.
- Record what step 6's test discipline did — the seams read out of the body and the slices
tdd drove, or that the change was prose-only or tdd absent — in the PR body (worktree) or an issue comment (branch:<name>). It informs the reviewer; it is never a verdict, and work-review still judges the diff against the requirements.
- A rebase conflict on a shared branch stops the run, it does not retry. Under
branch:<name> the push rebases onto the branch's new tip, and push → rebase → retry answers only the race — a rebase that halts on conflicted files collides again on the next attempt. Resolve it out of the two sides' intents, driving resolving-merge-conflicts when installed and handing in the sibling issue as the other side's primary source, then re-run the checks on the resolved tree. Intents that do not carry, or checks that come back red → blocked. Never resolve by guessing on a branch others land on: REFERENCE.md.
- Move the label
working → reviewRequested — the handoff to work-review. Report the issue id / PR url.
- The skill never merges, never reviews, and never sets
done, changes-requested or needs human — those are the review loop's and the human's outputs.
Inside a work-implement-queue drain nobody waits on this worker — return reviewRequested and let the drain move on. The review loop picks the issue up next.
Guardrails
- Lease before work. Never implement an issue you have not first flipped to
working.
- Push before handoff. Only flip to
reviewRequested once the work is pushed and visible to a reviewer; local-only work stays working.
- Stateless & resumable. Read state from the tracker + git every run; carry nothing between runs.
- Only this issue. Never touch sibling issues, never merge, never close anything you were not asked to.
- Never review your own work. This skill only produces
reviewRequested, blocked or skipped; it never sets done, changes-requested, or needs human.
- The draft state is the review's to flip. Open every PR as a draft and never mark one ready — "ready for review" is a statement about the work being finished, and this skill is the one party that cannot make it. Leave an already-ready PR ready on a re-work; never push one back into draft (the draft gate).
- Contradicting labels are refused, not resolved.
needsTriage plus a lifecycle label → skip and report, writing nothing to the tracker. Never work the issue on the more permissive label, never mark it blocked, never strip either label to settle it.
- "Unfixable" is earned, not asserted. Red exits to
blocked only after a diagnosis loop was attempted, and the attempt is what the issue comment records — which loop constructions were tried, how each failed, and that the human-in-the-loop rung was unreachable unattended. A blocked with a failed loop construction behind it is evidence; one without is an opinion, and the two read identically on the issue.
- Test-drive code, not prose. A change touching code runs
tdd's red-green loop with the issue body as the confirmed seams; a prose-only change runs it not at all, and that is not a block. Code with no seams in the body is a block — the run never picks its own seams, because seams chosen after the fact land exactly where the implementation already is. A missing tdd degrades to implementing as today, never to a block.
- Every optional call carries a stated fallback.
atomic-commit, pull-request and resolving-merge-conflicts are optional calls, not preconditions: without them, commit in the repo's own conventions, open the PR with the forge CLI, and treat an unresolvable rebase conflict as blocked. A missing commit or PR helper never leaves verified work uncommitted or unpushed — the push is what the lifecycle turns on; a missing resolving-merge-conflicts takes its stated fallback, and that fallback is blocked, leaving the work unpushed on purpose. The fallback is always stated, never always a degrade — and whichever one a run took is named in its report, never left silent. One rule, one place: REFERENCE.md.
- Attribution-free & secret-free — no
Generated with/🤖 line, no session url, no agent self-naming in branches, commits, PRs or comments; scan the change and context for secrets and exclude them.
ai: ready is the approval. A human marking an issue ai: ready ("scoped + approved for an AI agent to pick up") is the opt-in, so the drain — and a direct /work-implement 42 on an already-ready/changes-requested issue — works it without re-confirming. Confirm first only when there is no such opt-in (an issue not in an approved state, or a ready-gate widened to false) — and treat it as no opt-in at all when needsTriage sits beside it, since the two labels then disagree about whether anyone assessed the issue.
Reference
Config schema, the lifecycle state machine, selection query, lease & race rules, the test discipline tdd carries and the branch strategies (worktree / branch:<name>, sequential & parallel) — everything a run needs whatever its tracker: REFERENCE.md. Why it is shaped this way: DESIGN.md.
One file per tracker recipe, and a repo reads exactly one. work.tracker (falling back to issue.tracker) is a single value, so step 1 settles the branch before any recipe is opened: trackers/github.md, trackers/gitlab.md, trackers/linear.md, trackers/local.md.
1---2name: work-implement3description: Implements a single tracked issue across GitHub (gh), GitLab (glab), Linear (MCP) or local issue files — claims it via the lifecycle label, implements on a branch (fresh from ready, or re-work from changes-requested after review feedback), runs the repo's checks, commits and PUSHES, and hands the issue to the review loop by advancing the label to review. It never reviews its own work — the separate work-review skill does that. Tracker, label lifecycle and branch strategy come from the committed config (.tituskirch-skills.json). Use when the user wants to work, implement, action or pick up one specific issue or ticket, mentions an ai-ready issue, or says things like "work issue 42", "arbeite Issue 42 ab", "implementiere Ticket X", or "address the review feedback on issue Y".4---56# work-implement78Take **one** tracked issue, implement it, and push it so a **different** agent can review it — the stateless implement-unit behind `work-implement-queue`. One issue, one tracker (**GitHub** via `gh` or **Linear** via its MCP), picked per-repo by the same committed config the `issue` skill uses. State lives in the issue's **lifecycle label**, never in the agent — so a crashed run **resumes** instead of restarting.910This skill is the **implement half** of a two-loop workflow: it builds and pushes; `work-review` then reviews the pushed work. It **never reviews its own output** and never sets `done` — its terminal outputs are `reviewRequested` (handed to the review loop), `blocked`, or `skipped` (contradictory labels — reported, tracker untouched).1112**Opted out?** If the repo config sets `work` to `false`, this skill is **disabled** for the repo (as are the other `work-*` skills) — stop immediately and tell the user the work skills are turned off in `.tituskirch-skills.json`. An _absent_ `work` block is **not** disabled (it falls back to defaults). Check `.work == false` on the resolved config before any action — and before indexing `.work.*`. A missing `jq` or config exits non-zero too, so a pass is not evidence the config was read.1314## Workflow1516### 1. Load config & resolve tracker1718Resolve `.tituskirch-skills.json` via [`templates/resolve-config.sh`](templates/resolve-config.sh), never by reading the raw file ([REFERENCE.md](REFERENCE.md#reading-the-config) states how, missing `jq` included); the `work.*` section holds tracker, label lifecycle, branch strategy, the [feedback destination](REFERENCE.md#feedback-destination) and Linear scope. Resolution per setting: **config → default**. Determine the tracker (`work.tracker`, falling back to `issue.tracker`) and confirm it is available/authenticated. Reuse the `issue` catalog cache for labels/teams/states.1920Config schema, the full lifecycle and everything a run needs whatever its tracker: [REFERENCE.md](REFERENCE.md). The tracker recipes are one file each, and this step settles which: [`trackers/github.md`](trackers/github.md), [`trackers/gitlab.md`](trackers/gitlab.md), [`trackers/linear.md`](trackers/linear.md), [`trackers/local.md`](trackers/local.md).2122### 2. Resolve the target issue2324- **Explicit** — an id/number/key the user names (`/work-implement 42`, `ENG-123`). A human naming the issue is the opt-in, so an **unlanded prerequisite** does not veto it — say so in the report and work it, the way a [body contradicting the label](REFERENCE.md#label-vs-body-precedence) is surfaced rather than obeyed.25- **Self-select** — none given → run the [selection query](REFERENCE.md#selection-query) and take the single highest-priority eligible issue (a `ready` **or** a `changes-requested` issue). That query **defers** an issue whose prerequisite has not landed — under `worktree` too, since branching off a clean `pr.base` cannot see it ([dependency ordering](REFERENCE.md#dependency-ordering)). None eligible → say so and stop.2627### 3. Read the issue's state → pick the action2829The lifecycle label decides what this run does — this skill is a **state machine over one issue**, and it only acts on the states it owns:3031- **fresh** (`ready`) → claim and implement from the body (steps 4–8).32- **re-work** (`changes-requested`) → claim and implement from the body **plus the review feedback** (the reviewer's PR review / issue comment) — steps 4–8.33- **resume** (`working`) → a previous run leased it and crashed; continue where it left off (re-assert a clean tree first).34- **not ours** (`reviewRequested` / `reviewing` / `needs human` / `done`) → nothing to do here; `reviewRequested`, `reviewing` and `needs human` belong to `work-review` and the human. `blocked` → leave it unless the user explicitly re-runs it; report why it was blocked.3536**Read the whole label set, not just the lifecycle one.** An issue carrying `labels.needsTriage` (when the repo configures it) _alongside_ `ready` or `changes-requested` is two humans contradicting each other — "nobody has assessed this" against "approved, pick it up". **Skip it: no lease, no label, no assignee, no comment** — and name the contradiction in the run's report so a human clears it. Do **not** obey the more permissive label, and do **not** write `blocked` — the work is not blocked, a label is wrong ([contradictory labels](REFERENCE.md#contradictory-labels)). This is a third terminal output alongside `reviewRequested` and `blocked`, and the one that leaves the tracker untouched. The check runs here, at claim time, even when a drain already partitioned the queue — the label can be added between the queue build and the lease.3738### 4. Claim the issue (lease) — before any work3940Flip the label to `working` (`ready → working` or `changes-requested → working`) and assign the issue to the runner **first**, then start. The claim is the race-breaker: a second consumer sees it is no longer eligible and skips it. Honour the [single-flight lock](REFERENCE.md#lease--race-rules) — take it (direct run) or run under the drain's (queue). Already `working` with committed work → this is a **resume**, not a double-claim.4142### 5. Prepare the branch4344Assert a **clean tree** first. Then per `work.branch`:4546- **`worktree`** — a fresh branch off `pr.base` (e.g. `dev`) named for the issue. **The name carries the run's queue mode**: `ai/<ref>-<slug>` normally, `ai/queue/<ref>-<slug>` when [`work.queueBranch`](REFERENCE.md#queue-branch) is on — that prefix is the only signal the repo's grouping workflow ever gets, so it is what decides whether this PR is grouped. Own branch → own PR. For a **re-work**, check out the issue's existing branch instead of branching fresh — which is why the mode binds to the **issue**, not to the round. Where the branch is **cut from** is `pr.base` either way; `queueBranch` moves only the name here and the **PR's base** at step 8.47- **`branch:<name>`** — work on that shared branch (e.g. `branch:dev`); commits land there directly (review happens **after** they land — see [review-after-land](REFERENCE.md#review-after-land)).4849Branch naming, parallel/worktree handling and serialized integration: [REFERENCE.md](REFERENCE.md#branch-strategy).5051### 6. Implement5253**Re-read the issue body each run** — live tracker state, not a cached memory. The body is the source of truth for **scope and requirements**; it is not the source of truth for **eligibility** — the lifecycle label settled that at step 3 and stays [operative](REFERENCE.md#label-vs-body-precedence). A body line contradicting the current label ("early idea", "intentionally not `ai: ready`") is stale text, not a veto: **do the work and surface the conflict** — warn in the run's report and note it at the [feedback destination](REFERENCE.md#feedback-destination). Never let it silently override the label into a block.5455**Read the comments too, and settle body against comment by rule rather than by escalating.** The body is the scope, so a newer body edit supersedes an older comment — _unless_ that comment explicitly revised a named earlier decision ("this revises the comment above") and the body never mentions the revision, in which case the revision is the live decision and the body is the stale text. Follow the surviving statement, and **name both** — the two statements, their timestamps and which one this run followed — in the report and at the feedback destination: [body vs comment precedence](REFERENCE.md#body-vs-comment-precedence).5657- **fresh** → do the work the body describes.58- **re-work** (`changes-requested`) → **read the review feedback first** (the reviewer's `changes-requested` PR review or issue/Linear comment — look in **both** places, since `work.feedback` routes only where feedback is _written_), address exactly that, then the body. The feedback is why this issue came back.5960**Test-drive whatever a test can reach.** Where the change touches **code**, drive the `tdd` skill and run its loop in full — red before green, one vertical slice at a time, tests at seams rather than internals. `tdd` has the human confirm the seams before any test is written, and unattended there is nobody to ask: **the issue body stands in for the human**, so the requirements and acceptance criteria _are_ the agreed seams (`ai: ready` is already a human's approval). **Code touched and the body yields no seams → `blocked`** (step 7's exit) — never seams the run picked for itself. A **prose-only** change (a `SKILL.md` edit, a README) drives `tdd` **not at all**, and that is explicitly not a block: a missing seam only blocks when there is code behind it. Red **inside this step** is the loop working as designed and never blocks — step 7 stays the only gate. **`tdd` is optional**: not installed → implement exactly as today, no discipline driven and no block. Note what was driven, and what came of it, on the issue / PR at step 8 — it tells `work-review`, it does not bind its verdict. Mechanics: [REFERENCE.md](REFERENCE.md#test-discipline-tdd).6162**When the issue itself is a bug, the work _is_ the diagnosis** — drive `diagnosing-bugs` and build a feedback loop that goes red on this bug **before** hypothesising, instead of reading code for a theory. **Optional call**: not installed, implement as today. What it changes here, and the rung of its ladder an unattended run cannot reach: [REFERENCE.md](REFERENCE.md#diagnosis-discipline).6364Keep the change scoped to this one issue.6566### 7. Verify6768Run the repo's checks (the root `verify` key, else detected — tests, lint, build). **Working in a worktree** (`parallel: true`) means a tree with **no dependencies installed** — `git worktree` checks out tracked files only — so **install from the lockfile there first**, or the gate never touches the versions this branch pins ([how](REFERENCE.md#running-the-repos-checks)). A run in the working tree already has them and skips it. Green → continue. **Red and unfixable, spec ambiguous, or a genuine human decision needed → set `blocked`**, comment the reason at the [feedback destination](REFERENCE.md#feedback-destination) — a run that blocks here has pushed no PR yet, so in `pr` mode that falls back to the issue — and stop; a code change whose body yields no [seams](REFERENCE.md#test-discipline-tdd) is one such ambiguity, raised at step 6 and exiting here. `blocked` is a real outcome, not a failure to hide.6970Red is the one limb of the block clause with a procedure behind it: **red → drive `diagnosing-bugs` before calling it unfixable.** "Unfixable" is the cheapest legitimate exit from a drain — it ends a run without failing it — so it is **earned by a loop that was actually built**, never asserted. **Spec ambiguous or a genuine human decision needed → set `blocked` straight away**; neither is a bug case, and no reproduction answers them. When the diagnosis lands on a cause outside this issue's scope, or **no loop can be constructed at all** (the skill's own stop rule), **set `blocked`** — commenting **which loop constructions were tried and how each failed**, not merely the conclusion — and stop. **Optional call**: not installed, block exactly as today. `blocked` is a real outcome, not a failure to hide. Entry points, the unreachable rung and what the comment carries: [REFERENCE.md](REFERENCE.md#diagnosis-discipline).7172### 8. Commit, PUSH, hand off to review7374The **push** is the moment the work becomes reviewable — it is the boundary between `working` and `reviewRequested`.7576- Commit via `atomic-commit`; reference the issue so the tracker links it (`Refs #42` / the Linear key). **`atomic-commit` is optional** — not installed, commit directly in the repo's own Conventional Commits conventions, carrying the same reference line.77- **PUSH** the work: open/update the PR via `pull-request` (worktree), or push the commit(s) to the shared branch (`branch:<name>`). **`pull-request` is optional too**, and only the `worktree` path reaches it at all — not installed, open the PR with the forge CLI directly, same base and head. The base is `pr.base`, **unless [`work.queueBranch`](REFERENCE.md#queue-branch) is on and exactly one `ai/queue-*` PR is open against `pr.base`** — then it is that PR's head. Resolve it **here, per issue**, never once for the drain: the repo's workflow cuts the queue branch in response to the first worker PR, so it can appear mid-drain. **None open is not an error** — open against `pr.base` and carry on. Report the base you **set**; a workflow moving it afterwards is the design working, not drift, and is never corrected. Until this succeeds the issue stays `working` (a crash before the push is reclaimed as a [working-orphan](REFERENCE.md#reconcile)).78- **Open that PR as a _draft_, and leave it a draft** — every round, whether `pull-request` opened it (it opens ready by default, so ask it for a draft) or the forge CLI did. This skill **never marks a PR ready for review**: that flip means _the review believes this is finished_, which is not something the author of the change gets to say, and it is `work-review`'s to make. A re-work pushes onto whatever draft state the PR already carries and **leaves it exactly as found** — an already-ready PR stays ready, never goes back into draft. Why, and what a repo's workflows owe the mechanic: [the draft gate](REFERENCE.md#the-draft-gate). Under `branch:<name>` there is no PR and nothing here applies.79- Record what [step 6's test discipline](REFERENCE.md#test-discipline-tdd) did — the seams read out of the body and the slices `tdd` drove, or that the change was prose-only or `tdd` absent — in the PR body (`worktree`) or an issue comment (`branch:<name>`). It **informs** the reviewer; it is never a verdict, and `work-review` still judges the diff against the requirements.80- **A rebase conflict on a shared branch stops the run, it does not retry.** Under `branch:<name>` the push rebases onto the branch's new tip, and `push → rebase → retry` answers only the race — a rebase that halts on **conflicted files** collides again on the next attempt. Resolve it out of the two sides' **intents**, driving `resolving-merge-conflicts` when installed and handing in the sibling issue as the other side's primary source, then **re-run the checks** on the resolved tree. Intents that do not carry, or checks that come back red → **`blocked`**. Never resolve by guessing on a branch others land on: [REFERENCE.md](REFERENCE.md#rebase-conflicts).81- Move the label `working → reviewRequested` — the handoff to `work-review`. Report the issue id / PR url.82- The skill **never merges**, never reviews, and **never sets `done`, `changes-requested` or `needs human`** — those are the review loop's and the human's outputs.8384Inside a `work-implement-queue` drain nobody waits on this worker — return `reviewRequested` and let the drain move on. The review loop picks the issue up next.8586## Guardrails8788- **Lease before work.** Never implement an issue you have not first flipped to `working`.89- **Push before handoff.** Only flip to `reviewRequested` once the work is pushed and visible to a reviewer; local-only work stays `working`.90- **Stateless & resumable.** Read state from the tracker + git every run; carry nothing between runs.91- **Only this issue.** Never touch sibling issues, never merge, never close anything you were not asked to.92- **Never review your own work.** This skill only produces `reviewRequested`, `blocked` or `skipped`; it never sets `done`, `changes-requested`, or `needs human`.93- **The draft state is the review's to flip.** Open every PR as a draft and never mark one ready — "ready for review" is a statement about the work being finished, and this skill is the one party that cannot make it. Leave an already-ready PR ready on a re-work; never push one back into draft ([the draft gate](REFERENCE.md#the-draft-gate)).94- **Contradicting labels are refused, not resolved.** `needsTriage` plus a lifecycle label → skip and report, writing nothing to the tracker. Never work the issue on the more permissive label, never mark it `blocked`, never strip either label to settle it.95- **"Unfixable" is earned, not asserted.** Red exits to `blocked` only after a diagnosis loop was attempted, and the **attempt** is what the issue comment records — which loop constructions were tried, how each failed, and that the human-in-the-loop rung was unreachable unattended. A `blocked` with a failed loop construction behind it is **evidence**; one without is an opinion, and the two read identically on the issue.96- **Test-drive code, not prose.** A change touching code runs `tdd`'s red-green loop with the issue body as the confirmed seams; a prose-only change runs it not at all, and that is not a block. Code with no seams in the body **is** a block — the run never picks its own seams, because seams chosen after the fact land exactly where the implementation already is. A missing `tdd` degrades to implementing as today, never to a block.97- **Every optional call carries a stated fallback.** `atomic-commit`, `pull-request` and `resolving-merge-conflicts` are **optional** calls, not preconditions: without them, commit in the repo's own conventions, open the PR with the forge CLI, and treat an unresolvable rebase conflict as `blocked`. A missing **commit or PR** helper never leaves verified work uncommitted or unpushed — the push is what the lifecycle turns on; a missing `resolving-merge-conflicts` takes its stated fallback, and that fallback **is** `blocked`, leaving the work unpushed on purpose. The fallback is always **stated**, never always a **degrade** — and whichever one a run took is **named in its report**, never left silent. One rule, one place: [REFERENCE.md](REFERENCE.md#optional-skill-calls).98- **Attribution-free & secret-free** — no `Generated with`/🤖 line, no session url, no agent self-naming in branches, commits, PRs or comments; scan the change and context for secrets and exclude them.99- **`ai: ready` is the approval.** A human marking an issue `ai: ready` ("scoped + approved for an AI agent to pick up") is the opt-in, so the drain — and a direct `/work-implement 42` on an already-`ready`/`changes-requested` issue — works it **without re-confirming**. Confirm first only when there is no such opt-in (an issue not in an approved state, or a ready-gate widened to `false`) — and treat it as **no opt-in at all** when `needsTriage` sits beside it, since the two labels then disagree about whether anyone assessed the issue.100101## Reference102103Config schema, the lifecycle state machine, selection query, lease & race rules, the test discipline `tdd` carries and the branch strategies (`worktree` / `branch:<name>`, sequential & parallel) — everything a run needs whatever its tracker: [REFERENCE.md](REFERENCE.md). Why it is shaped this way: [DESIGN.md](DESIGN.md).104105**One file per tracker recipe, and a repo reads exactly one.** `work.tracker` (falling back to `issue.tracker`) is a single value, so step 1 settles the branch before any recipe is opened: [`trackers/github.md`](trackers/github.md), [`trackers/gitlab.md`](trackers/gitlab.md), [`trackers/linear.md`](trackers/linear.md), [`trackers/local.md`](trackers/local.md).