Imported from mcmurrym/coding-agent-skills (
agent-skills/linear-project-autopilot/SKILL.md). Install upstream withnpx skills add mcmurrym/coding-agent-skills --skill linear-project-autopilot. Copyright stays with the author.
Linear Project Autopilot
Autonomously work through all issues in a Linear project. Implement, test, review, PR, merge, repeat.
Input
A Linear project URL, plus optional stop conditions.
Examples:
https://linear.app/teamname/project/project-slug-abc123/overviewhttps://linear.app/teamname/project/project-slug-abc123 stop after milestone M2https://linear.app/teamname/project/project-slug-abc123 stop after MCM-148
Stop conditions (optional, parsed from the user's message):
stop after milestone <name>— Complete all issues in the named milestone (and earlier milestones), then stop. Match on milestone name prefix (e.g., "M2" matches "M2: Weather API").stop after <issue-key>— Complete issues up to and including the named issue, then stop.- No stop condition — Work through all issues until done or blocked.
Workflow
Phase 1: Initialize
- Extract the project slug from the URL (the segment after
/project/, before any trailing path like/overview). - Fetch the project via Linear MCP:
get_projectwithincludeMilestones: true. - Fetch all project issues via Linear MCP:
list_issueswith the project ID,limit: 250. - If more than 250 issues, paginate with cursor until all are fetched.
- Filter out issues with status type
completedorcancelled. - Build the work queue — sort remaining issues by:
- Milestone order: Parse milestone names for ordering (e.g., "M0: ..." before "M1: ..."). If milestones don't have numeric prefixes, use their position in the milestones array. Issues without milestones go last.
- Priority within milestone: Urgent (1) > High (2) > Medium (3) > Low (4) > None (0).
- Unblocked first: If issues have Linear blocking relations (
blockedBy), push blocked issues after their blockers. - Creation date as final tiebreaker (oldest first).
- Print a summary table and immediately begin working:
## Project: <name>
## Milestones: <count> | Issues: <count> remaining
| # | Issue | Milestone | Priority | Status |
|---|-------|-----------|----------|--------|
| 1 | MCM-140 Initialize Next.js + Convex project | M0 | Urgent | Backlog |
| 2 | MCM-141 Define Convex schema | M1 | Urgent | Backlog |
| ... | ... | ... | ... | ... |
Starting work on issue #1...
Phase 2: Issue Loop
For each issue in the work queue, execute these steps. Do NOT stop between issues unless a human-needed situation is detected.
Step 1: Detect human-needed blockers BEFORE starting
Read the issue description carefully. If the issue requires ANY of these, STOP the loop immediately:
- Obtaining an API key or secret from an external service
- Configuring a webhook, OAuth app, or integration in an external dashboard
- Manual DNS, domain, or infrastructure setup
- Purchasing or subscribing to a third-party service
- Any action that requires logging into a service the agent cannot access
When stopping, print:
## PAUSED — Human action needed
**Issue:** <identifier> — <title>
**What's needed:** <specific description of the manual action>
**Instructions:** Complete this step, then say "continue" to resume.
**Remaining queue:** <count> issues
Then wait for the user to say "continue" before resuming the loop.
Step 2: Start work on the issue
Invoke the linear-start-work skill with the issue URL or key. This will:
- Fetch full issue context (description, comments, parent, sub-issues, attachments)
- Create a git branch
- Move the issue to In Progress
Step 3: Create worktree
After the branch is created, create an isolated git worktree:
git worktree add ".claude/worktrees/<branch-name>" <branch-name>
Change working directory to the worktree for all subsequent work on this issue.
Step 4: Implement with tests
Using the research output from linear-start-work:
-
Detect the project platform and tooling. On the first issue, inspect the project to understand what you're working with and what quality tooling exists or needs to be set up.
Platform detection — look for these signals:
Signal files Platform Test framework Type/compile check Linter Formatter package.jsonJS/TS (Node, Next.js, etc.) vitest, jest, mocha tsc --noEmiteslint, biome prettier, biome build.gradle.kts/pom.xmlKotlin/Java (JVM) JUnit 5, kotest ./gradlew compileKotlin/mvn compilektlint, detekt ktfmt, spotless Package.swift/*.xcodeprojSwift XCTest, swift-testing swift buildswiftlint swift-format Cargo.tomlRust built-in ( cargo test)cargo checkcargo clippycargo fmtpyproject.toml/setup.pyPython pytest mypy, pyright ruff, flake8 ruff format, black go.modGo built-in ( go test)go vetgolangci-lint gofmtFor each quality dimension, check if tooling exists. If not, set it up:
- Testing: Every project needs a test framework. If none exists, install the idiomatic one for the platform.
- Compilation / type checking: If the language has a compile step or static type checker, ensure it runs cleanly.
- Linting: If no linter is configured, install the standard one for the platform with a minimal config.
- Formatting: If no formatter is configured, install the standard one for the platform.
Use whatever is already in the project. Don't replace existing tools — augment what's missing. All tooling setup is part of the first issue's commit.
-
Implement the feature/fix as described in the issue.
-
Write unit tests that provide real value:
- Test actual behavior, not implementation details
- Cover edge cases and error paths
- Test the contract (inputs → outputs), not internals
- If the issue involves API endpoints, test request validation, success responses, and error responses
- If the issue involves data mutations, test state transitions
- Do NOT write tests that just assert the code exists or mock everything away
-
Run all validation checks. Use the commands appropriate to the detected platform:
- Tests: Run the full test suite
- Compile / type check: Run the compiler or type checker in check mode
- Lint: Run the linter with zero-warning tolerance
- Format: Run the formatter in check mode
Run ALL applicable checks. Fix any failures before proceeding.
-
If any check fails, fix the issue:
- Test failures → fix the implementation (not the tests, unless the tests are wrong)
- Type/compile errors → fix the code
- Lint errors → prefer auto-fix if the linter supports it, otherwise fix manually
- Format errors → auto-fix with the formatter Loop until all checks pass.
Step 5: Commit and push
Invoke git-add-commit-push. This stages all changes, generates a commit message from the diff, commits, and pushes.
Step 6: Self-review
Review your own changes critically:
git diff main...HEAD
Evaluate the diff for:
- Bugs: Logic errors, off-by-one, null/undefined issues, race conditions
- Security: Injection, exposed secrets, missing auth checks
- Missing edge cases: What happens with empty input? Invalid input? Concurrent access?
- Code quality: Is this the simplest correct implementation?
If you find critical issues:
- Fix them.
- Run all validation checks again to verify the fix doesn't break anything.
- Invoke
git-add-commit-pushagain (creates a second "review fix" commit).
If the code is acceptable, proceed.
Step 7: Create PR
Invoke make-pr to create a pull request. The PR description should reference the Linear issue.
Step 8: Auto-merge
Merge the PR:
gh pr merge <pr-number> --squash --delete-branch
If merge fails due to CI:
- Check CI failure output:
gh pr checks <pr-number> - Read the failure logs.
- Fix the issue in the worktree.
- Run all validation checks locally.
- Commit, push, wait for CI.
- Retry merge.
- Max 3 CI-fix attempts. After 3 failures, STOP and report the CI issue to the user.
If merge fails due to conflicts:
- Attempt rebase:
git rebase main - If rebase succeeds, force-push and retry merge.
- If rebase fails, STOP and report the conflict to the user.
Step 9: Clean up and advance
- Change working directory back to the main repo.
- Remove the worktree:
git worktree remove ".claude/worktrees/<branch-name>" - Update main:
git checkout main git pull origin main - Move the Linear issue to Done:
- Use
list_issue_statusesto find the team's "Done" status (type:completed). - Update the issue status via
save_issue.
- Use
- Print a progress update:
## Completed: <identifier> — <title> ## Progress: <completed>/<total> issues done ## Next: <next-identifier> — <next-title> - Check stop condition. If a stop condition was specified:
stop after milestone <name>: If the just-completed issue was the last issue in the target milestone, stop the loop and go to Phase 3.stop after <issue-key>: If the just-completed issue matches the target key, stop the loop and go to Phase 3.
- Continue to the next issue in the queue.
Phase 3: Completion
When all issues are processed (or all remaining issues are blocked on human actions), print a final summary:
## Project Autopilot Complete
| Status | Count |
|--------|-------|
| Completed | N |
| Skipped (human needed) | N |
| Failed | N |
### Completed Issues
- MCM-140: Initialize Next.js + Convex project (PR #1)
- MCM-141: Define Convex schema (PR #2)
- ...
### Pending (human action needed)
- MCM-150: Implement Stripe webhook handler — needs Stripe webhook secret configured
- ...
Guardrails
- Never skip unit tests. Every issue gets tests.
- Never skip type checking, linting, or formatting if the project has them configured.
- Never auto-merge if any validation check is failing (tests, types, lint, format).
- Never continue past a human-needed blocker — stop and wait.
- Never modify tests just to make them pass if the underlying code is wrong.
- The 3-attempt CI fix limit is absolute.
- If an issue's description is empty or too vague to implement, stop and ask the user for clarification rather than guessing.