Linear
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 (
linearcommand) - Always available via Bash - 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
.env.schemawith@sensitiveannotation:# @type=string(startsWith=lin_api_) @required @sensitive LINEAR_API_KEY= -
Add
LINEAR_API_KEYto.env(never commit this file) -
Configure MCP to use environment variable:
{ "mcpServers": { "linear": { "env": { "LINEAR_API_KEY": "${LINEAR_API_KEY}" } } } } -
Use
varlock loadto validate before operations
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
## Acceptance Criteriasection with at least 2 concrete, testable checklist items. See docs/issue-template.md for the canonical template plus a populated full example. The CLIcreate-issue/create-sub-issuewill reject descriptions missing this structure; for MCPsave_issuecallers, validate the draft first withnpm run ops -- validate-description --stdin(see below). If the user provides only a title, draft the description yourself using the template below.Depth — 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
ProblemintoContextand droppingVerificationis fine when the AC is self-evidently testable — collapse deliberately, not by default.## 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:
npm run ops -- create-issue --template. See docs/issue-template.md for a fully populated example. -
Labels. Apply from the label taxonomy:
- Exactly ONE type label (
feature,bug,refactor,chore,spike) - 1-2 domain labels (
backend,frontend,security,infrastructure, etc.) - 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
mcp__linear__save_issue(or any MCP issue-create tool), pipe the draft description throughvalidate-description --stdinand only callsave_issueif it exits 0:echo "$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/create-sub-issue. MCP has no server-side gate — this pre-flight + the retroactivenpm run lint-issuesaudit are the only enforcement for the MCP path. For longer drafts in a file, use--file <path>instead of--stdin.Depth ≠ 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
save_issuewas considered and rejected: it only fires when Claude Code is the runtime, install is per-user, and the payload shape is harness-version-dependent. Runnpm run lint-issues -- --since 24hlocally or in CI to catch instruction-layer drift retroactively.