Linear
Managing Linear issues, projects, and teams. Use when working with Linear tasks, creating issues, updating status, querying projects, or managing team workflows.
git clone https://github.com/wrsmith108/linear-claude-skill
git clone --depth=1 https://github.com/wrsmith108/linear-claude-skill ~/.claude/skills/wrsmith108-linear-claude-skill-linear
SKILL.mdLinear
Tools and workflows for managing issues, projects, and teams in Linear.
⚠️ Tool Availability (READ FIRST)
This skill supports multiple tool backends. Use whichever is available:
- MCP Tools (mcp__linear) - Use if available in your tool set
- Linear CLI (
command) - Always available via Bashlinear - Helper Scripts - For complex operations
If MCP tools are NOT available, use the Linear CLI via Bash:
# View an issue linear issues view ENG-123 # Create an issue linear issues create --title "Issue title" --description "Description" # Update issue status (get state IDs first) linear issues update ENG-123 -s "STATE_ID" # Add a comment linear issues comment add ENG-123 -m "Comment text" # List issues linear issues list
Do NOT report "MCP tools not available" as a blocker - use CLI instead.
🔐 Security: Varlock Integration
CRITICAL: Never expose API keys in terminal output or Claude's context.
Safe Commands (Always Use)
# Validate LINEAR_API_KEY is set (masked output) varlock load 2>&1 | grep LINEAR # Run commands with secrets injected varlock run -- npm run query -- "query { viewer { name } }" # Check schema (safe - no values) cat .env.schema | grep LINEAR
Unsafe Commands (NEVER Use)
# ❌ NEVER - exposes key to Claude's context linear config show echo $LINEAR_API_KEY printenv | grep LINEAR cat .env
Setup for New Projects
-
Create
with.env.schema
annotation:@sensitive# @type=string(startsWith=lin_api_) @required @sensitive LINEAR_API_KEY= -
Add
toLINEAR_API_KEY
(never commit this file).env -
Configure MCP to use environment variable:
{ "mcpServers": { "linear": { "env": { "LINEAR_API_KEY": "${LINEAR_API_KEY}" } } } } -
Use
to validate before operationsvarlock load
Quick Start (First-Time Users)
1. Check Your Setup
Run the setup check to verify your configuration:
npm run setup
This will check:
- LINEAR_API_KEY is set and valid
- @linear/sdk is installed
- Linear CLI availability (optional)
- MCP configuration (optional)
2. Get API Key (If Needed)
If setup reports a missing API key:
- Open Linear in your browser
- Go to Settings (gear icon) -> Security & access -> Personal API keys
- Click Create key and copy the key (starts with
)lin_api_ - Add to your environment:
# Option A: Add to shell profile (~/.zshrc or ~/.bashrc) export LINEAR_API_KEY="lin_api_your_key_here" # Option B: Add to Claude Code environment echo 'LINEAR_API_KEY=lin_api_your_key_here' >> ~/.claude/.env # Then reload your shell or restart Claude Code
3. Test Connection
Verify everything works:
npm run query -- "query { viewer { name } }"
You should see your name from Linear.
4. Common Operations
# Create issue in a project npm run ops -- create-issue "Project" "Add rate limiting to auth endpoints" "Auth endpoints have no rate limiting, allowing brute-force attacks. Add configurable limits per endpoint with 429 responses when exceeded." # Update issue status npm run ops -- status Done ENG-123 ENG-124 # Create sub-issue npm run ops -- create-sub-issue ENG-100 "Sub-task" "Details" # Update project status npm run ops -- project-status "Phase 1" completed # Show all commands npm run ops -- help
See Project Management Commands for full reference.
Issue Creation Checklist (Required)
When creating a Linear issue, always complete these three steps — even if the user doesn't mention them.
-
Detailed description with Acceptance Criteria. Every issue description MUST include an
section with at least 2 concrete, testable checklist items. See docs/issue-template.md for the canonical template plus a populated full example. The CLI## Acceptance Criteria
/create-issue
will reject descriptions missing this structure; for MCPcreate-sub-issue
callers, validate the draft first withsave_issue
(see below). If the user provides only a title, draft the description yourself using the template below.npm run ops -- validate-description --stdinDepth — default to the full six-section template. Unless the user's phrasing clearly signals brevity ("quick issue", "one-liner", "just the AC", "brief", "terse", "minimum", "short"), structure the body as Context → Problem → Proposal → Acceptance Criteria → Verification → Out of scope. The 120-char / 2-item floor is what the validator rejects, not what reviewers want. If the user gives you only a title, draft a verbose body from the full template — ask follow-up questions rather than shipping the floor. For trivial changes (typo fix, one-line config tweak), collapsing
intoProblem
and droppingContext
is fine when the AC is self-evidently testable — collapse deliberately, not by default.Verification## Context **Title:** <title> <What is changing and why. 2-4 sentences. Link prior issues, docs, or incidents that motivate this.> ## Problem <What specifically is broken, missing, or insufficient today. Name the file, flow, or behavior.> ## Proposal <What you intend to do about it. High-level approach, not implementation line-by-line.> ## Acceptance Criteria - [ ] <Concrete, testable outcome> - [ ] <Concrete, testable outcome> ## Verification <How the AC will actually be checked. Manual steps, test command, or review instruction.> ## Out of Scope - <What this issue does NOT cover — redirect to the follow-up or explain why it's deferred>Print the template on demand with:
. See docs/issue-template.md for a fully populated example.npm run ops -- create-issue --template -
Labels. Apply from the label taxonomy:
- Exactly ONE type label (
,feature
,bug
,refactor
,chore
)spike - 1-2 domain labels (
,backend
,frontend
,security
, etc.)infrastructure - Scope labels if relevant (
,blocked
,breaking-change
)tech-debt
- Exactly ONE type label (
-
Project assignment. Assign to the appropriate project based on context (active sprint, feature area, or user instruction). If no project is obvious, ask the user. In batch/subagent context, use the project associated with the parent issue or the default initiative project.
When updating an existing issue, preserve existing labels and project — only add missing labels or correct misassigned ones.
MCP tools. Before calling
(or any MCP issue-create tool), pipe the draft description throughmcp__linear__save_issueand only callvalidate-description --stdinif it exits 0:save_issueecho "$DRAFT_BODY" | npm run ops -- validate-description --stdin # exit 0 → safe to call save_issue # exit 5 → fix the description; re-pipe; try againThe CLI already gates this for
/create-issue. MCP has no server-side gate — this pre-flight + the retroactivecreate-sub-issueaudit are the only enforcement for the MCP path. For longer drafts in a file, usenpm run lint-issuesinstead of--file <path>.--stdinDepth ≠ validation. Validation passing (exit 0) only means the 120-char / 2-AC floor is met. Structure the body as the full six-section template (Context → Problem → Proposal → AC → Verification → Out of Scope) unless the user explicitly asked for brevity — see bullet #1 above.
Enforcement model. CLI + SDK paths are hard-gated; the MCP path is instruction + audit. A PreToolUse hook that intercepts
was considered and rejected: it only fires when Claude Code is the runtime, install is per-user, and the payload shape is harness-version-dependent. Runsave_issuelocally or in CI to catch instruction-layer drift retroactively.npm run lint-issues -- --since 24h
Project Planning Workflow
See Issue Creation Checklist — descriptions, labels, and project assignment are required for every issue.
Create Issues in the Correct Project from the Start
Best Practice: When planning a new phase or initiative, create the project and its issues together in a single planning session. Avoid creating issues in a catch-all project and moving them later.
Recommended Workflow
-
Create the project first:
npm run ops -- create-project "Phase X: Feature Name" "My Initiative" -
Set project state to Planned:
npm run ops -- project-status "Phase X: Feature Name" planned -
Create issues directly in the project (use
to print the canonical template first, or pass a multi-line description via heredoc):--template# Print the template to seed your description npm run ops -- create-issue --template # Create the issue with a template-shaped description npm run ops -- create-issue "Phase X: Feature Name" "Parent task" "$(cat <<'EOF' ## Context Implement the core feature with integration tests and documentation. ## Acceptance Criteria - [ ] All API endpoints return correct responses - [ ] Test coverage >80% on new modules EOF )" --labels feature,backend npm run ops -- create-sub-issue ENG-XXX "Sub-task 1" "$(cat <<'EOF' ## Context Set up database schema and migrations for the new feature tables. ## Acceptance Criteria - [ ] Migration runs cleanly on a fresh database - [ ] Rollback migration restores prior schema EOF )" -
Update project state when work begins:
npm run ops -- project-status "Phase X: Feature Name" in-progress
Why This Matters
- Traceability: Issues are linked to their project from creation
- Metrics: Project progress tracking is accurate from day one
- Workflow: No time wasted moving issues between projects
- Organization: Linear views and filters work correctly
Anti-Pattern to Avoid
❌ Creating issues in a "holding" project and moving them later:
# Don't do this create-issue "Phase 6A" "New feature" # Wrong project # Later: manually move to Phase X # Extra work
Project Management Commands
project-status
Update a project's state in Linear. Accepts user-friendly terminology that maps to Linear's API.
npm run ops -- project-status <project-name> <state>
Valid States:
| Input | Description | API Value |
|---|---|---|
| Not yet started | backlog |
| Scheduled for future | planned |
| Currently active | started |
| Temporarily on hold | paused |
| Successfully finished | completed |
| Will not be done | canceled |
Examples:
# Start working on a project npm run ops -- project-status "Phase 8: MCP Decision Engine" in-progress # Mark project complete npm run ops -- project-status "Phase 8" completed # Partial name matching works npm run ops -- project-status "Phase 8" paused
link-initiative
Link an existing project to an initiative.
npm run ops -- link-initiative <project-name> <initiative-name>
Examples:
# Link a project to an initiative npm run ops -- link-initiative "Phase 8: MCP Decision Engine" "Q1 Goals" # Partial matching works npm run ops -- link-initiative "Phase 8" "Q1 Goals"
unlink-initiative
Remove a project from an initiative.
npm run ops -- unlink-initiative <project-name> <initiative-name>
Examples:
# Remove incorrect link npm run ops -- unlink-initiative "Phase 8" "Linear Skill" # Clean up test links npm run ops -- unlink-initiative "Test Project" "Q1 Goals"
Error Handling:
- Returns error if project is not linked to the specified initiative
- Returns error if project or initiative not found
Complete Project Lifecycle Example
# 1. Create project linked to initiative npm run ops -- create-project "Phase 11: New Feature" "Q1 Goals" # 2. Set state to planned npm run ops -- project-status "Phase 11" planned # 3. Create issues in the project npm run ops -- create-issue "Phase 11" "Parent task" "Description" npm run ops -- create-sub-issue ENG-XXX "Sub-task 1" "Details" # 4. Start work - update to in-progress npm run ops -- project-status "Phase 11" in-progress # 5. Mark issues done npm run ops -- status Done ENG-XXX ENG-YYY # 6. Complete project npm run ops -- project-status "Phase 11" completed # 7. (Optional) Link to additional initiative npm run ops -- link-initiative "Phase 11" "Q2 Goals"
Tool Selection
Choose the right tool for the task:
| Priority | Tool | When to Use |
|---|---|---|
| 1 | MCP (Official Server) | Most operations - PREFERRED |
| 2 | CLI | Fast-path for reads/status updates when installed (optional) |
| 3 | Helper Scripts | Bulk operations, label taxonomy, project workflows |
| 4 | SDK scripts | Complex operations (loops, conditionals) |
| 5 | GraphQL API | Operations not supported by above |
lin
CLI (Optional Fast-Path)
linIf the
Rust binary is installed, the skill uses it automatically for:lin
- Issue status updates (
,status
,done
)wip - Listing initiatives
- Searching issues (
)search <query> - Listing issues (
)list-issues [--team X] [--state Y] - User info (
)whoami
All operations fall back silently to the SDK when
lin is unavailable.
Install (optional):
brew install aaronkwhite/tap/lin # macOS (Homebrew) cargo install lincli # Any platform with Rust
Disable: Set
LINEAR_USE_LIN=0 to skip lin even when installed.
MCP Server Configuration
Use the official Linear MCP server at
mcp.linear.app:
{ "mcpServers": { "linear": { "command": "npx", "args": ["mcp-remote", "https://mcp.linear.app/sse"], "env": { "LINEAR_API_KEY": "your_api_key" } } } }
WARNING: Do NOT use deprecated community servers. See troubleshooting.md for details.
MCP Reliability (Official Server)
| Operation | Reliability | Notes |
|---|---|---|
| Create issue | ✅ High | Full support |
| Update status | ✅ High | Use directly |
| List/Search issues | ✅ High | Supports filters, queries |
| Add comment | ✅ High | Works with issue IDs |
Quick Status Update
# Via MCP - use human-readable state names update_issue with id="issue-uuid", state="Done" # Via helper script (bulk operations) node scripts/linear-helpers.mjs update-status Done 123 124 125
Helper Script Reference
For detailed helper script usage, see troubleshooting.md.
Parallel Agent Execution
For bulk operations or background execution, use the
Linear-specialist subagent:
Task({ description: "Update Linear issues", prompt: "Mark ENG-101, ENG-102, ENG-103 as Done", subagent_type: "Linear-specialist" })
When to use
(parallel):Linear-specialist
- Bulk status updates (3+ issues)
- Project status changes
- Creating multiple issues
- Sync operations after code changes
When to use direct execution:
- Single issue queries
- Viewing issue details
- Quick status checks
- Operations needing immediate results
See sync.md for parallel execution patterns.
Image Uploads
Step 1: Extract the image from conversation context
Images shared inline in Claude Code are not saved to disk automatically — they live as base64 in the session JSONL. Use the extraction script:
# Find the current session JSONL ls -t ~/.claude/projects/<project-path>/*.jsonl | head -1 # Extract all inline images (saves to /tmp by default) npm run extract-image -- <path-to-session.jsonl> # Or specify a custom output directory npm run extract-image -- <path-to-session.jsonl> ~/Desktop
This saves images to
/tmp/shared-image-0.png, /tmp/shared-image-1.png, etc.
Always verify the extracted image with the Read tool before uploading.
Step 2: Create the issue
# Standard approach npm run ops -- create-issue "Project Name" "Issue title" "Description"
Note: If you need to target a specific team and
picks the wrong one, use GraphQL with explicitcreate-issue:teamId# Get the project's team npm run query -- 'query { projects(filter: { name: { containsIgnoreCase: "PROJECT NAME" } }) { nodes { id name teams { nodes { id name key } } } } }' # Create with explicit teamId npm run query -- 'mutation { issueCreate(input: { teamId: "TEAM_UUID", projectId: "PROJECT_UUID", title: "Issue title", description: "Description" }) { success issue { id identifier url } } }'
Step 3: Upload the image and attach to the issue
npm run upload-image -- /tmp/shared-image-0.png ENG-123 "Optional comment text"
The script will:
- Upload the file to Linear's S3 storage
- Post a comment on the issue with the image embedded as markdown
Supported formats: PNG, JPG/JPEG, GIF, WebP, SVG, PDF
Known pitfalls
| Problem | Cause | Fix |
|---|---|---|
picks wrong team | Multiple teams in workspace | Use GraphQL with explicit teamId (see Step 2) |
"Issue not found" | Issue was deleted before attaching | Ensure issue exists first |
| Image not found on disk | Shared inline, not as file | Extract from session JSONL (Step 1) |
Critical Requirements
Issues → Projects → Initiatives
Every issue MUST be attached to a project. Every project MUST be linked to an initiative.
| Entity | Must Link To | If Missing |
|---|---|---|
| Issue | Project | Not visible in project board |
| Project | Initiative | Not visible in roadmap |
See projects.md for complete project creation checklist.
Conventions
Issue Status
- Assigned to me: Set
state: "Todo" - Unassigned: Set
state: "Backlog"
Labels
Uses domain-based label taxonomy — see Issue Creation Checklist for required rules and docs/labels.md for the full taxonomy.
# Validate labels npm run ops -- labels validate "feature,security" # Suggest labels for issue npm run ops -- labels suggest "Fix XSS vulnerability"
SDK Automation Scripts
Use only when MCP tools are insufficient. For complex operations involving loops, mapping, or bulk updates, write TypeScript scripts using
@linear/sdk. See sdk.md for:
- Complete script patterns and templates
- Common automation examples (bulk updates, filtering, reporting)
- Tool selection criteria
Scripts provide full type hints and are easier to debug than raw GraphQL for multi-step operations.
GraphQL API
Fallback only. Use when operations aren't supported by MCP or SDK.
See api.md for complete documentation including:
- Authentication and setup
- Example queries and mutations
- Timeout handling patterns
- MCP timeout workarounds
- Shell script compatibility
Quick ad-hoc query:
npm run query -- "query { viewer { name } }"
Projects & Initiatives
For advanced project and initiative management patterns, see projects.md.
Quick reference - common project commands:
# Create project linked to initiative npm run ops -- create-project "Phase X: Name" "My Initiative" # Update project status npm run ops -- project-status "Phase X" in-progress npm run ops -- project-status "Phase X" completed # Link/unlink projects to initiatives npm run ops -- link-initiative "Phase X" "My Initiative" npm run ops -- unlink-initiative "Phase X" "Old Initiative"
Key topics in projects.md:
- Project creation checklist (mandatory steps)
- Content vs Description fields
- Discovery before creation
- Codebase verification before work
- Sub-issue management
- Project status updates
- Project updates (status reports)
Sync Patterns (Bulk Operations)
For bulk synchronization of code changes to Linear, see sync.md.
Quick sync commands:
# Bulk update issues to Done npm run ops -- status Done ENG-101 ENG-102 ENG-103 # Update project status npm run ops -- project-status "My Project" completed
Reference
| Document | Purpose |
|---|---|
| api.md | GraphQL API reference, timeout handling |
| sdk.md | SDK automation patterns |
| sync.md | Bulk sync patterns |
| projects.md | Project & initiative management |
| troubleshooting.md | Common issues, MCP debugging |
| docs/labels.md | Label taxonomy |
External: Linear MCP Documentation