Take a Linear issue all the way to PR open, CI green, review comments addressed, and Linear updated. There is exactly one explicit checkpoint — plan approval — and even that is conditional: routine changes run straight through.
The phases below gather the Linear context and prepare git. The actual work — grilling you on the open design decisions, exploring, planning, reviewing, implementing, gating, shipping — lives in the shared build loop.
Read references/build-loop.md now. It is the body of this skill, not optional
background. This file supplies the Linear bindings it asks for.
Philosophy (hold these throughout)
- A ticket is a pointer, not a specification. Requirements get negotiated in comments as often as they are written in the description. Read those first, then grill the user on what is still open — a wrong assumption costs one question here and an implementation at Step F.
- Never invent a requirement. An issue that fails to fetch, a description that is empty, an attachment nobody attached — name it and ask. An issue key is not a specification either.
- The repository is the system of record. A Linear status, a label, a blocker marked done —
none of those are evidence. Confirm a dependency against
git logand the code. - No architecture is assumed. Read what this repo actually does and follow it. Never plan against a pattern it does not use, and never propose adopting one; that is a separate conversation, not a side effect of a ticket.
- Evidence beats claims. You run the gates yourself and paste their real output — a subagent reporting "tests pass" is a claim, the gate's own output is evidence. Same for CI: a run that never registered is not a green run, and an absent CI is not a green CI.
- One checkpoint, and it has to be earned. Step E stops the run only when the change's shape demands it. Stopping on a routine fix teaches the user to skim your plans; not stopping on a schema migration is how you lose them.
- Autonomy ends at the PR. Push it, open it, babysit it to green — never merge, never enable auto-complete, never deploy.
- A silent run is a run nobody trusts. Say which step you are on, what you just changed, and
what you are waiting for — in plain sentences the person who wrote the ticket can follow, not in
raw tool output. See § Say what you are doing in
references/build-loop.md. - A finished subissue is marked finished. Each child that is implemented, gated and pushed moves to the team's completed state as it closes. The parent is what waits on the PR.
- Keep the tracker footprint minimal. Status and comments on the issue you are building, and nothing else in Linear, ever.
Autonomy contract
- Act and self-verify by default. No option menus, no "should I proceed?" on green.
- Linear writes on this issue are pre-authorized — the status and comments of
TICKETand of any subissue you actively work. Never ask permission for those, and never write anything else in Linear. - This skill pushes branches and opens pull requests without asking. It never merges a PR, never enables auto-complete, and never deploys.
- Escalate only for the cases listed in
references/build-loop.md§ Escalation. Otherwise keep going.
Arguments
Parse $ARGUMENTS:
- Issue identifier — a Linear key like
ABC-123, or alinear.app/<workspace>/issue/ABC-123/<slug>URL (extract the key). If absent, list the caller's assigned, unstarted-or-in-progress issues withlist_issuesand ask which one viaAskUserQuestion. skip-checkpoint— or freeform "skip the plan checkpoint" / "run straight to PR". The user's opt-in for routine issues: force the Step E skip. Honor it only when explicitly given, and never over a user who asked to see a plan.
There is no brief-file or inline-description path. This skill starts from a Linear issue; if you don't have one, ask for one.
Phase 0 — Resolve the bindings and check the tooling
Two things have to hold before Phase 1. Both are cheap to check here and expensive to discover later.
0a. The Linear binding
The Linear MCP server is registered under different names in different setups, so the
tool prefix varies: mcp__linear__* in some sessions, mcp__linear-server__* in
others. Determine which prefix this session actually exposes and use it consistently.
If neither is available, stop and say so — point the user at the Linear MCP server
setup. Never infer an issue's content from its key.
Everything below names operations bare (get_issue, save_issue); prepend the prefix
you resolved.
0b. The GitHub path — prerequisites
Steps H and I push a branch, open the PR and read CI through gh. Check it now: an
unauthenticated gh discovered at Step H costs a full implementation before it
surfaces. Report what is missing and install nothing yourself.
| Tool | Check | macOS | Windows | Linux |
|---|---|---|---|---|
gh CLI |
gh --version |
brew install gh |
winget install GitHub.cli |
the distro's gh package, or cli.github.com |
gh authentication |
gh auth status |
gh auth login |
gh auth login |
gh auth login |
a GitHub origin |
git remote get-url origin |
— | — | — |
If gh is missing or unauthenticated, say so and ask whether to continue anyway:
everything through Step G still runs, and the work would stop at the push with the
branch intact. If origin is not a GitHub remote, name the host and stop — this
skill's OPEN-PR and CI bindings are GitHub-only, and ado-plan-build is the
sibling for Azure Repos.
Phase 1 — Gather Linear context
Run these in parallel:
get_issuefor the key — include relations (parent, blocking, related). Note the team ID and project ID.list_issueswithparentId= the issue ID — the subissues.list_comments— prior discussion and decisions. Requirements are frequently negotiated in comments rather than written in the description; read them before concluding anything is unspecified.get_project, if the issue belongs to one — goals and scope.list_cyclesfor the team withtype: "current"— what else is in flight.
Resolve the team's real workflow states with list_issue_statuses before any status
write. "In Progress", "In Review" and "Done" are conventions, not guarantees — teams
rename and reorder them. Resolve three states by type, not by name: the
started one for in-progress, the team's review state (typically the last started
or unstarted state before completion) for in-review, and the completed one that
subissues land in when they close. Say which state you picked for each. If nothing
plausibly matches, pick the closest by type, name it, and continue — a status write is
never worth blocking the work.
Phase 2 — Prepare the git environment
- Default branch:
git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'. git fetch origin.- If the working tree is dirty, stop and report. Do not stash, do not discard.
git checkout <default-branch> && git pull --ff-only origin <default-branch>.- Create the feature branch. Prefer the
branchNameLinear itself suggests on the issue; otherwisefeature/<ISSUE-KEY>-<short-slug>. The branch name must contain the Linear key. If you are already on that branch with prior work on it, stay on it and continue rather than recreating it.
Phase 3 — Present the issue summary
Print a concise summary: title, status, priority, assignee, project, current cycle, branch name, subissues (key / title / status), blocking and related issues, and the decisions buried in the comments.
Print the subissues even when there is only one — that list is what Step A asks the user to choose from, and it is the work list for the rest of the run.
Linear status is not authoritative. Flag every blocker that isn't done, and before
treating a dependency as met, confirm it against git log and the code rather than
against a green label.
Phase 4 — Run the build loop
Follow references/build-loop.md, Steps A → J, with these bindings.
| Binding | Linear / GitHub |
|---|---|
TICKET |
the Linear issue — the parent |
SUB-TICKETS |
its subissues — list_issues with parentId to list, save_comment / save_issue against the child's id |
STATUS→IN-PROGRESS |
save_issue with the team's started-type state (Phase 1) |
STATUS→IN-REVIEW |
save_issue with the team's review state (Phase 1) — used on the parent, which waits on the PR |
STATUS→DONE |
save_issue with the team's completed-type state (Phase 1) — used on a subissue once it is implemented, gated and pushed |
COMMENT |
save_comment on the issue |
BRANCH |
the Phase 2 branch |
LINK-TOKEN |
the issue key (ABC-123) — this is what Linear's GitHub integration matches on. Each Step F.6 commit carries the sub-issue's own key; the PR title carries the parent's. With no subissues the work list is TICKET itself, so its key is the one in every commit as well |
OPEN-PR |
gh pr create --title "<key>: <title>" --body "<body>" |
CI |
gh pr checks <pr> --watch to wait; gh run view <run-id> --log-failed for logs; gh run rerun <run-id> --failed to retry a flaky job |
PR-COMMENTS |
gh pr view <pr> --comments for the conversation; gh api repos/{owner}/{repo}/pulls/{n}/comments for inline threads; reply with gh pr comment or the API |
gh pr checks --watch blocks until the checks settle, which is the right way to wait —
it beats polling. If the repo has no CI configured at all, say so and skip straight to
the review-comment half of Step I; an absent CI is not a green CI.
Notes
- What this skill is pre-approved to do. Read and write files in the repo, run the
repo's own build/test commands, write to this Linear issue, push its branch, and
open a PR. It will not merge, deploy, or touch anything else in Linear. If that is
more autonomy than you want on a given ticket, run it without
skip-checkpointand stop it at the Step E checkpoint. - The plan file. Step C writes
.claude/plans/<TICKET>.mdand keeps it current while the work runs — a working notebook, never staged and never committed on the skill's initiative. Step J asks what to do with it. - Keep secrets out of the shell and the commit. Don't stage
.envfiles, keys, or tokens, and don't echo secret values into commands, commit messages, or PR bodies. - Deleting the plan file is the one step that asks.
allowed-toolsis static and<TICKET>is not, so no grant can say "this ticket's plan and no other" — aBash(rm .claude/plans/*)would authorise deleting every other ticket's plan too. The grant is therefore absent on purpose: Step J's "Delete it" runsrm .claude/plans/<TICKET>.md, exactly that path, and costs one permission prompt. One prompt for the only destructive step in the run, right after the user chose it, is the correct trade. - The Bash allowlist is narrowed to the subcommands this run actually uses, so a
package publish, an arbitrary GitHub API mutation or an unrelated tool prompts instead
of running silently.
gh apiis scoped to the inline-review-comment path — the one place the skill needs it. Two grants stay wide on purpose and are worth knowing about:git add/git pushandnpx. A glob cannot express "not-A" or "not--force", and the gate a repo defines may legitimately benpx <anything>; the controls there are the textual rules inreferences/build-loop.md(stage only what the item touched, nevergit add -A, never force-push, never merge). A team that wants a hard boundary rather than an instruction should addpermissions.denyrules insettings.json— deny wins over any allowlist, including this one. - Gate commands. The mainstream runners (
make,npm/pnpm/yarn,pytest,go,cargo,dotnet,mvn/gradle,bundle,composer) are pre-approved. If your repo's gate isn't among them, run it and approve the prompt — never skip or fake a gate to avoid a permission dialog.
References
| Reference | Used by | What it covers |
|---|---|---|
build-loop.md |
Phase 4 | The body of the skill: Steps A → J — grilling the user, exploring, drafting the plan, the three-lens adversarial review, the conditional approval checkpoint, test-first implementation, the repo's gates, commit/push/PR, the CI-and-review-comments watch loop, and the complete Escalation list |
Troubleshooting
| Symptom | Almost always | Confirm with |
|---|---|---|
Neither mcp__linear__* nor mcp__linear-server__* is exposed |
The Linear MCP server is not registered, or the workspace is not trusted so a project-scoped server never loaded | /mcp. A pending-approval server behaves exactly like an absent one |
gh fails to authenticate at Step H, after the whole build |
Phase 0b was skipped | gh auth status before Phase 1 — that is what 0b is for. Recover with gh auth login and resume from Step H; the branch and commits survive |
gh pr checks --watch returns instantly with no checks |
Either the repo has no CI, or the first run has not registered yet on a just-pushed branch | gh run list --branch <branch>. If there genuinely is no CI, say so and skip to the review-comment half of Step I — an absent CI is not a green CI, and Step J must name it as a skipped gate |
| The status write lands in the wrong column | The state was matched by name. Teams rename and reorder states, so "In Progress" is a convention, not a guarantee | list_issue_statuses and match by state type (started, the team's review state, completed). Name the state you picked |
| Subissues sit in progress after their work shipped | Step F.6.4 was skipped, or the completed state was never resolved in Phase 1 |
Each child closes into STATUS→DONE as Step F.6 finishes it; only the parent stays in review, waiting on the PR |
| Linear never links the commit or the PR to the issue | A key is missing, or the wrong one is used. Branch and PR title carry the PARENT key; each Step F.6 commit carries its own sub-issue's key — one key in all three is impossible once a run covers several sub-issues, and a commit under the parent key leaves the child with nothing attached | Branch name and PR title: parent key. Each commit: the key of the sub-issue it closes. Linear's GitHub integration matches on whichever key it finds |
| Phase 2 stops on a dirty working tree | By design. Stashing someone's uncommitted work is not this skill's call | git status. Commit or stash it yourself, then re-run |
| Two subagents overwrite each other's edits in Step F | Steps that converge on the same file were dispatched in parallel | Step F.2: converging steps stay serial in one agent. Parallelize the thinking (subagents return diffs, you apply them), not the writes |
EnterPlanMode errors, or the plan is presented twice |
The session was already in plan mode | Step E: when already in plan mode, go straight to ExitPlanMode |
| The same gate fails three times in a row | Not a reason to keep iterating — classify it: test, code, environment, or plan drift | Step F.5, and § Escalation in build-loop.md. An ambiguous failure is an escalation, never a guess |