| name | linear-subagent-guide |
| description | Guides optimal Linear operations usage with caching, performance patterns, and error handling. Auto-activates when implementing CCPM commands that interact with Linear. Prevents usage of non-existent Linear MCP tools. |
| allowed-tools | ["Task"] |
Linear Subagent Guide
⛔ EXACT LINEAR MCP PARAMETERS (VERIFIED)
These are the EXACT parameter names from get_server_tools. Copy exactly.
Most Common Operations
mcp__agent-mcp-gateway__execute_tool({
server: "linear",
tool: "get_issue",
args: { id: "WORK-26" }
})
mcp__agent-mcp-gateway__execute_tool({
server: "linear",
tool: "update_issue",
args: {
id: "WORK-26",
description: "...",
state: "In Progress"
}
})
mcp__agent-mcp-gateway__execute_tool({
server: "linear",
tool: "create_comment",
args: {
issueId: "WORK-26",
body: "Comment text"
}
})
mcp__agent-mcp-gateway__execute_tool({
server: "linear",
tool: "list_comments",
args: { issueId: "WORK-26" }
})
Parameter Reference Table
| Tool | Required Parameter | Example Args |
|---|
get_issue | id | { id: "WORK-26" } |
update_issue | id | { id: "WORK-26", ... } |
create_comment | issueId, body | { issueId: "WORK-26", body: "..." } |
list_comments | issueId | { issueId: "WORK-26" } |
create_issue | title, team | { title: "...", team: "..." } |
get_project | query | { query: "ProjectName" } |
get_team | query | { query: "TeamName" } |
get_user | query | { query: "me" } |
Overview
The Linear subagent (ccpm:linear-operations) is a dedicated MCP handler that optimizes all Linear API operations in CCPM. Rather than making direct Linear MCP calls, commands should delegate to this subagent, which provides:
- 50-60% token reduction (15k-25k → 8k-12k per workflow)
- Session-level caching with 85-95% hit rates
- Performance: <50ms for cached operations (vs 400-600ms direct)
- Structured error handling with actionable suggestions
- Centralized logic for Linear operations consistency
When to Use the Linear Subagent
Use the subagent for:
- Reading issues, projects, teams, statuses
- Creating or updating issues, projects
- Managing labels and comments
- Fetching documents and cycles
- Searching Linear documentation
Never use the subagent for:
- Local file operations
- Git commands
- External API calls (except Linear)
⚠️ CRITICAL: Parameter Name Gotcha
Different Linear MCP tools use different parameter names for issue IDs:
| Tool | Parameter | WRONG | CORRECT |
|---|
get_issue | id | { issueId: "X" } ❌ | { id: "X" } ✅ |
update_issue | id | { issueId: "X" } ❌ | { id: "X" } ✅ |
create_comment | issueId | { id: "X" } ❌ | { issueId: "X" } ✅ |
list_comments | issueId | { id: "X" } ❌ | { issueId: "X" } ✅ |
First-call failures are often caused by using issueId instead of id for get_issue/update_issue.
Available Linear MCP Tools (Complete Reference)
Linear MCP provides 23 tools for interacting with Linear. This is the complete, validated list.
1. Comments (2 tools)
list_comments
List comments for a specific Linear issue.
Parameters:
issueId (string, required) - The issue ID
Example:
mcp__linear__list_comments({ issueId: "PSN-41" })
create_comment
Create a comment on a specific Linear issue.
Parameters:
issueId (string, required) - The issue ID
body (string, required) - The content of the comment as Markdown
parentId (string, optional) - A parent comment ID to reply to
Linear's Native Collapsible Syntax:
Use +++ to create collapsible sections (starts collapsed, native Linear feature):
+++ Section Title
Content here (multi-line markdown supported)
+++
Example (simple):
mcp__linear__create_comment({
issueId: "PSN-41",
body: "## Progress Update\n\nCompleted first phase."
})
Example (with collapsible section):
mcp__linear__create_comment({
issueId: "PSN-41",
body: `🔄 **Progress Update**
Completed first phase, all tests passing
+++ 📋 Detailed Context
**Changed Files:**
- src/auth.ts
- src/tests/auth.test.ts
**Next Steps:**
- Implement phase 2
- Update documentation
+++`
})
2. Cycles (1 tool)
list_cycles
Retrieve cycles for a specific Linear team.
Parameters:
teamId (string, required) - The team ID
type (string, optional) - "current", "previous", or "next"
Example:
mcp__linear__list_cycles({ teamId: "team-123", type: "current" })
3. Documents (2 tools)
get_document
Retrieve a Linear document by ID or slug.
Parameters:
id (string, required) - The document ID or slug
Example:
mcp__linear__get_document({ id: "doc-abc-123" })
list_documents
List documents in the user's Linear workspace.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional) - An ID to end at
after (string, optional) - An ID to start from
orderBy (string, optional) - "createdAt" or "updatedAt" (default: "updatedAt")
query (string, optional) - Search query
projectId (string, optional) - Filter by project ID
initiativeId (string, optional) - Filter by initiative ID
creatorId (string, optional) - Filter by creator ID
createdAt (string, optional) - ISO-8601 date-time or duration (e.g., "-P1D")
updatedAt (string, optional) - ISO-8601 date-time or duration
includeArchived (boolean, optional, default false)
Example:
mcp__linear__list_documents({ projectId: "proj-123", limit: 20 })
4. Issues (4 tools)
get_issue
Retrieve detailed information about an issue by ID.
Parameters:
id (string, required) - The issue ID (e.g., "PSN-41")
Example:
mcp__linear__get_issue({ id: "PSN-41" })
list_issues
List issues in the user's Linear workspace. Use "me" for assignee to get your issues.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional)
after (string, optional)
orderBy (string, optional) - "createdAt" or "updatedAt"
query (string, optional) - Search title or description
team (string, optional) - Team name or ID
state (string, optional) - State name or ID
cycle (string, optional) - Cycle name or ID
label (string, optional) - Label name or ID
assignee (string, optional) - User ID, name, email, or "me"
delegate (string, optional) - Agent name or ID
project (string, optional) - Project name or ID
parentId (string, optional) - Parent issue ID
createdAt (string, optional) - ISO-8601 date-time or duration
updatedAt (string, optional) - ISO-8601 date-time or duration
includeArchived (boolean, optional, default true)
Example:
mcp__linear__list_issues({ assignee: "me", state: "In Progress" })
create_issue
Create a new Linear issue.
Parameters:
title (string, required)
team (string, required) - Team name or ID
description (string, optional) - Markdown description
cycle (string, optional) - Cycle name, number, or ID
priority (number, optional) - 0=None, 1=Urgent, 2=High, 3=Normal, 4=Low
project (string, optional) - Project name or ID
state (string, optional) - State type, name, or ID
assignee (string, optional) - User ID, name, email, or "me"
delegate (string, optional) - Agent name, displayName, or ID
labels (array of strings, optional) - Label names or IDs
dueDate (string, optional) - ISO format date
parentId (string, optional) - Parent issue ID for sub-issues
links (array of objects, optional) - Each object needs url and title
Example:
mcp__linear__create_issue({
title: "Fix authentication bug",
team: "Engineering",
description: "## Problem\n\nUsers cannot login",
state: "Todo",
labels: ["bug", "critical"],
assignee: "me"
})
update_issue
Update an existing Linear issue.
Parameters:
id (string, required) - The issue ID
title (string, optional)
description (string, optional) - Markdown
priority (number, optional) - 0-4
project (string, optional) - Project name or ID
state (string, optional) - State type, name, or ID
cycle (string, optional) - Cycle name, number, or ID
assignee (string, optional) - User ID, name, email, or "me"
delegate (string, optional) - Agent name, displayName, or ID
labels (array of strings, optional) - Label names or IDs (replaces existing)
parentId (string, optional)
dueDate (string, optional) - ISO format
estimate (number, optional) - Numerical estimate value
links (array of objects, optional)
Example:
mcp__linear__update_issue({
id: "PSN-41",
state: "In Progress",
labels: ["planning", "implementation"]
})
5. Issue Statuses (2 tools)
list_issue_statuses
List available issue statuses in a Linear team.
Parameters:
team (string, required) - Team name or ID
Example:
mcp__linear__list_issue_statuses({ team: "Engineering" })
get_issue_status
Retrieve detailed information about an issue status by name or ID.
Parameters:
id (string, required) - Status ID
name (string, required) - Status name
team (string, required) - Team name or ID
Example:
mcp__linear__get_issue_status({ name: "In Progress", team: "Engineering" })
6. Labels (3 tools)
list_issue_labels
List available issue labels in a workspace or team.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional)
after (string, optional)
orderBy (string, optional) - "createdAt" or "updatedAt"
name (string, optional) - Filter by label name
team (string, optional) - Team name or ID
Example:
mcp__linear__list_issue_labels({ team: "Engineering" })
create_issue_label
Create a new Linear issue label.
Parameters:
name (string, required)
description (string, optional)
color (string, optional) - Hex color code
teamId (string, optional) - Team UUID (workspace label if omitted)
parentId (string, optional) - Parent label UUID for groups
isGroup (boolean, optional, default false) - Whether this is a label group
Example:
mcp__linear__create_issue_label({
name: "feature-request",
color: "#bb87fc",
teamId: "team-123"
})
list_project_labels
List available project labels in the Linear workspace.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional)
after (string, optional)
orderBy (string, optional)
name (string, optional)
Example:
mcp__linear__list_project_labels({ limit: 100 })
7. Projects (4 tools)
list_projects
List projects in the user's Linear workspace.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional)
after (string, optional)
orderBy (string, optional)
query (string, optional) - Search project name
state (string, optional) - State name or ID
initiative (string, optional) - Initiative name or ID
team (string, optional) - Team name or ID
member (string, optional) - User ID, name, email, or "me"
createdAt (string, optional)
updatedAt (string, optional)
includeArchived (boolean, optional, default false)
Example:
mcp__linear__list_projects({ team: "Engineering", state: "started" })
get_project
Retrieve details of a specific project.
Parameters:
query (string, required) - Project ID or name
Example:
mcp__linear__get_project({ query: "CCPM" })
create_project
Create a new project in Linear.
Parameters:
name (string, required)
team (string, required) - Team name or ID
summary (string, optional) - Max 255 chars
description (string, optional) - Markdown
state (string, optional)
startDate (string, optional) - ISO format
targetDate (string, optional) - ISO format
priority (integer, optional) - 0-4
labels (array of strings, optional)
lead (string, optional) - User ID, name, email, or "me"
Example:
mcp__linear__create_project({
name: "Q1 Authentication",
team: "Engineering",
description: "## Goals\n\n- OAuth integration\n- SSO support",
lead: "me"
})
update_project
Update an existing Linear project.
Parameters:
id (string, required)
name (string, optional)
summary (string, optional)
description (string, optional)
state (string, optional)
startDate (string, optional)
targetDate (string, optional)
priority (integer, optional) - 0-4
labels (array of strings, optional)
lead (string, optional)
Example:
mcp__linear__update_project({
id: "proj-123",
state: "completed"
})
8. Teams (2 tools)
list_teams
List teams in the user's Linear workspace.
Parameters:
limit (number, optional, max 250, default 50)
before (string, optional)
after (string, optional)
orderBy (string, optional)
query (string, optional) - Search query
includeArchived (boolean, optional, default false)
createdAt (string, optional)
updatedAt (string, optional)
Example:
mcp__linear__list_teams({ includeArchived: false })
get_team
Retrieve details of a specific Linear team.
Parameters:
query (string, required) - Team UUID, key, or name
Example:
mcp__linear__get_team({ query: "Engineering" })
9. Users (2 tools)
list_users
Retrieve users in the Linear workspace.
Parameters:
query (string, optional) - Filter by name or email
Example:
mcp__linear__list_users({ query: "john" })
get_user
Retrieve details of a specific Linear user.
Parameters:
query (string, required) - User ID, name, email, or "me"
Example:
mcp__linear__get_user({ query: "me" })
10. Documentation (1 tool)
search_documentation
Search Linear's documentation to learn about features and usage.
Parameters:
query (string, required) - Search query
page (number, optional, default 0) - Page number
Example:
mcp__linear__search_documentation({ query: "issue statuses", page: 0 })
Summary: All 23 Tools
list_comments - List comments on issue
create_comment - Add comment to issue
list_cycles - Get team cycles
get_document - Fetch Linear document
list_documents - List documents
get_issue - Fetch single issue
list_issues - Search/list issues
create_issue - Create new issue
update_issue - Update existing issue
list_issue_statuses - List workflow states
get_issue_status - Get specific status
list_issue_labels - List labels
create_issue_label - Create new label
list_project_labels - List project labels
list_projects - List projects
get_project - Get specific project
create_project - Create new project
update_project - Update existing project
list_teams - List all teams
get_team - Get specific team
list_users - List workspace users
get_user - Get specific user
search_documentation - Search Linear docs
Tool Validation: Critical Rules
Only Use Validated Tools
RULE: Every Linear operation MUST use a tool from the validated list above.
Examples of INVALID tool names that will fail:
- ❌
get_issues (correct: list_issues)
- ❌
update_comment (correct: create new comment instead)
- ❌
delete_issue (not supported)
- ❌
list_issue_statuses (correct tool, but check args)
Before Using a Tool
- Check the validated list above
- Verify the exact tool name matches
- If unsure, use
list_* variants which are widely available
- Never assume tool names—verify first
Error Prevention Strategy
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
context:
cache: true
`
Task(ccpm:linear-operations): `
operation: fetch_issue // This tool doesn't exist!
params:
issueId: PSN-29
`
Task(ccpm:linear-operations): `
operation: delete_issue // Linear MCP doesn't support deletion
params:
issueId: PSN-29
`
Using the Linear Subagent
⚠️ IMPORTANT: Command File Invocation Format
When writing CCPM command files (files in commands/), you MUST use explicit execution instructions, NOT the YAML template format shown in the examples below.
Command files must use this format:
**Use the Task tool to fetch the issue from Linear:**
Invoke the `ccpm:linear-operations` subagent:
- **Tool**: Task
- **Subagent**: ccpm:linear-operations
- **Prompt**:
operation: get_issue
params:
issueId: "{the issue ID from previous step}"
context:
cache: true
command: "work"
Why? Claude Code interprets command markdown files as executable prompts, not documentation. YAML template syntax appears as an example rather than an instruction to execute. Explicit instructions (e.g., "Use the Task tool to...") are unambiguous execution directives that ensure Claude invokes the subagent correctly.
Basic Syntax (For Documentation/Examples Only)
The examples below use YAML template format for readability. Do NOT use this format in command files—use the explicit format shown above instead.
Task(ccpm:linear-operations): `
operation: <tool_name>
params:
<param1>: <value1>
<param2>: <value2>
context:
cache: true
command: "planning:plan"
`
Enabling Caching (Recommended)
For read operations, always enable caching to achieve 85-95% hit rates:
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-123
context:
cache: true # Enable session-level caching
command: "planning:plan"
`
Providing Context for Better Errors
Include context to improve error messages and debugging:
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
state: "In Progress"
context:
cache: false # Skip cache for writes
command: "implementation:start" # Which command triggered this
purpose: "Marking task as started" # Why we're doing this
`
Shared Helpers
The _shared-linear-helpers.md file provides convenience functions that delegate to the subagent. Use these for common operations:
getOrCreateLabel(teamId, labelName)
Smart label management with automatic creation if missing:
// Use this instead of manual list + create
const label = await getOrCreateLabel(teamId, "feature-request");
Benefits:
- Deduplicates label creation logic
- Handles caching automatically
- Returns label ID or creates new one
getValidStateId(teamId, stateNameOrId)
Fuzzy state matching with suggestions on errors:
// Handles "In Progress" → actual state ID
const stateId = await getValidStateId(teamId, "In Progress");
Benefits:
- Case-insensitive matching
- Fuzzy matching for typos
- Suggests available states on error
ensureLabelsExist(teamId, labelNames)
Batch create labels if missing:
// Create multiple labels in one call
const labels = await ensureLabelsExist(teamId, [
"planning",
"implementation",
"review"
]);
Performance Optimization
Caching Strategy
Read Operations: Always enable caching
get_issue, list_issues, list_projects
- Cache hits: 85-95%
- Performance: <50ms
Write Operations: Disable caching
create_issue, update_issue, create_comment
- Always fetch fresh data
// READ: Cache enabled
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
context:
cache: true # ✅ Cached reads
`
// WRITE: Cache disabled
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
state: "Done"
context:
cache: false # ❌ Never cache writes
`
Batching Operations
When possible, batch related operations:
// ✅ GOOD: Get all needed data in one context
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
context:
cache: true
batchId: "planning-workflow"
`
// Then use Team, Project, Status in sequence
// Subsequent calls reuse cached Team/Project data
Token Reduction Comparison
| Operation | Direct MCP | Via Subagent | Savings |
|---|
| Get issue | 400ms, 2.5k tokens | <50ms, 0.8k tokens | 68% |
| Update issue | 600ms, 3.2k tokens | <50ms, 1.2k tokens | 62% |
| Create comment | 500ms, 2.8k tokens | <50ms, 1.0k tokens | 64% |
| Workflow average | 500ms, 15k tokens | <50ms, 8k tokens | -47% |
Error Handling
The Linear subagent provides structured errors with actionable suggestions.
Common Error Scenarios
STATE_NOT_FOUND
When updating an issue to a non-existent status:
error:
code: STATE_NOT_FOUND
message: "State 'In Review' not found in team"
params:
requestedState: "In Review"
teamId: "psn123"
suggestions:
- "Use 'In Progress' (exact match required)"
- "Available states: Backlog, Todo, In Progress, Done, Blocked"
- "Check team configuration in Linear"
Fix: Use exact state name or getValidStateId() helper
LABEL_NOT_FOUND
When assigning a non-existent label:
error:
code: LABEL_NOT_FOUND
message: "Label 'feature' not found"
params:
requestedLabel: "feature"
teamId: "psn123"
suggestions:
- "Label will be created automatically"
- "Use 'ensureLabelsExist()' to batch create"
- "Available labels: bug, feature-request, documentation"
Fix: Use getOrCreateLabel() or ensureLabelsExist() helpers
ISSUE_NOT_FOUND
When accessing a non-existent issue:
error:
code: ISSUE_NOT_FOUND
message: "Issue PSN-9999 not found"
params:
issueId: "PSN-9999"
suggestions:
- "Verify issue ID is correct (use Linear UI)"
- "Check team/project context"
- "Issue may have been archived"
Fix: Validate issue ID before using
Examples
Example 1: Get Issue with Caching
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
context:
cache: true
command: "planning:plan"
purpose: "Fetch task details for planning"
`
Performance: <50ms (cached)
Token cost: ~0.8k
Result: Issue object with title, description, status, labels, assignee
Example 2: Update Issue Status and Labels
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
state: "In Progress"
labels: ["planning", "implementation"]
context:
cache: false
command: "implementation:start"
purpose: "Mark task as started with relevant labels"
`
Performance: 100-200ms (no cache)
Token cost: ~1.2k
Result: Updated issue with new status and labels
Example 3: Create Comment with Context
Task(ccpm:linear-operations): `
operation: create_comment
params:
issueId: PSN-29
body: |
Progress update:
- Implemented JWT authentication
- 2 unit tests passing
- Need to fix Redis integration
Blockers:
- Redis library compatibility
context:
cache: false
command: "implementation:sync"
purpose: "Log implementation progress"
`
Performance: 150-300ms
Token cost: ~1.5k
Result: Comment added to issue with timestamp
Example 4: Using Shared Helpers
// Get or create label (delegates to subagent with caching)
const label = await getOrCreateLabel(teamId, "feature-request");
// Get valid state ID (fuzzy matching with suggestions)
const stateId = await getValidStateId(teamId, "In Progress");
// Ensure multiple labels exist
const labels = await ensureLabelsExist(teamId, [
"planning",
"implementation",
"blocked"
]);
// Now use the results
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
state: ${stateId}
labels: ${labels.map(l => l.id)}
context:
cache: false
purpose: "Apply validated status and labels"
`
Performance: <100ms total (mostly cached lookups)
Token cost: ~1.8k
Result: Reliable label/status application with error prevention
Example 5: Error Handling
// PATTERN: Try operation, handle structured errors
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
state: "Review" // Might not exist
context:
cache: false
command: "implementation:sync"
`
// If error:
// {
// code: "STATE_NOT_FOUND",
// suggestions: ["Available states: Backlog, Todo, In Progress, Done"]
// }
// RECOVERY: Use helper or ask user
const stateId = await getValidStateId(teamId, "Review");
// Or ask user: "Which status should I use?"
Pattern: Structured errors guide user or helper selection
Migration from Direct MCP
Before: Direct MCP Call (Inefficient)
// Direct call - no caching, higher token cost
Task(linear-operations): `
List issues in PSN project where status = "Todo"
`
// Result: ~2.5k tokens, 400ms, no future cache hits
After: Via Subagent (Optimized)
// Via subagent - automatic caching
Task(ccpm:linear-operations): `
operation: list_issues
params:
projectId: "PSN"
filter: {status: "Todo"}
context:
cache: true
command: "planning:plan"
`
// Result: ~0.9k tokens, <50ms, 85-95% cache hits next time
Common Pitfalls to Avoid
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
// Missing: context: cache: true
`
Task(ccpm:linear-operations): `
operation: fetch_issue_details // This doesn't exist
params:
issueId: PSN-29
`
Task(ccpm:linear-operations): `
operation: update_issue
params:
issueId: PSN-29
context:
cache: true // WRONG! Never cache writes
`
Task(ccpm:linear-operations): `
operation: get_issue
params:
issueId: PSN-29
context:
cache: true // ✅ Cache reads
command: "planning:plan"
`
Best Practices Summary
| Practice | Reason |
|---|
| Always use subagent for Linear ops | 50-60% token reduction |
| Enable caching on reads | 85-95% hit rate, <50ms performance |
| Disable caching on writes | Avoid stale data |
| Use shared helpers | Reduces duplication, better error handling |
| Validate tools against list | Prevent failures with non-existent tools |
| Provide context object | Better error messages and debugging |
| Handle structured errors | Graceful degradation and user guidance |
References
- Subagent Location:
agents/linear-operations.md
- Shared Helpers:
agents/_shared-linear-helpers.md
- Architecture Guide:
docs/architecture/linear-subagent-architecture.md
- Linear MCP Docs: Available via
search_documentation tool