linear-integration
Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.
Best use case
linear-integration is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.
Teams using linear-integration should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/linear-integration/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How linear-integration Compares
| Feature / Agent | linear-integration | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
plugin: autopilot
updated: 2026-01-20
# Linear Integration
**Version:** 0.1.0
**Purpose:** Patterns for Linear API integration in autopilot workflows
**Status:** Phase 1
## When to Use
Use this skill when you need to:
- Authenticate with Linear API
- Set up webhook handlers for Linear events
- Create, read, update, or delete Linear issues
- Transition issue states in Linear workflows
- Attach files to Linear issues
- Add comments to Linear issues
## Overview
This skill provides patterns for:
- Linear API authentication
- Webhook handler setup
- Issue CRUD operations
- State transitions
- File attachments
- Comment handling
## Core Patterns
### Pattern 1: Authentication
**Personal API Key (MVP):**
```typescript
import { LinearClient } from '@linear/sdk';
const linear = new LinearClient({
apiKey: process.env.LINEAR_API_KEY
});
```
**Verification:**
```typescript
async function verifyConnection(): Promise<boolean> {
try {
const me = await linear.viewer;
console.log(`Connected as: ${me.name}`);
return true;
} catch (error) {
console.error('Linear connection failed:', error);
return false;
}
}
```
### Pattern 2: Webhook Handler
**Bun HTTP Server:**
```typescript
import { serve } from 'bun';
import { createHmac } from 'crypto';
interface LinearWebhookPayload {
action: 'created' | 'updated' | 'deleted';
type: 'Issue' | 'Comment' | 'Label';
data: {
id: string;
title?: string;
description?: string;
state: { id: string; name: string };
labels: Array<{ id: string; name: string }>;
};
}
serve({
port: process.env.AUTOPILOT_WEBHOOK_PORT || 3001,
async fetch(req: Request): Promise<Response> {
if (req.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
// Verify signature
const signature = req.headers.get('Linear-Signature');
const body = await req.text();
if (!verifySignature(body, signature)) {
return new Response('Unauthorized', { status: 401 });
}
const payload: LinearWebhookPayload = JSON.parse(body);
// Route to handler
await routeWebhook(payload);
return new Response('OK', { status: 200 });
}
});
function verifySignature(body: string, signature: string | null): boolean {
if (!signature) return false;
const hmac = createHmac('sha256', process.env.LINEAR_WEBHOOK_SECRET!);
const expectedSignature = hmac.update(body).digest('hex');
return signature === expectedSignature;
}
```
### Pattern 3: Issue Operations
**Create Issue:**
```typescript
async function createIssue(
teamId: string,
title: string,
description: string,
labels: string[]
): Promise<string> {
// Note: Linear SDK uses linear.createIssue() method
const result = await linear.createIssue({
teamId,
title,
description,
labelIds: await resolveLabelIds(labels),
assigneeId: process.env.AUTOPILOT_BOT_USER_ID,
priority: 2,
});
const issue = await result.issue;
return issue!.id;
}
```
**Query Issues:**
```typescript
async function getAutopilotTasks(teamId: string) {
const issues = await linear.issues({
filter: {
team: { id: { eq: teamId } },
assignee: { id: { eq: process.env.AUTOPILOT_BOT_USER_ID } },
state: { name: { in: ['Todo', 'In Progress'] } },
},
});
return issues.nodes;
}
```
### Pattern 4: State Transitions
**Transition State:**
```typescript
async function transitionState(
issueId: string,
newStateName: string
): Promise<void> {
// Get workflow states for the issue's team
const issue = await linear.issue(issueId);
const team = await issue.team;
const states = await team.states();
const targetState = states.nodes.find(s => s.name === newStateName);
if (!targetState) {
throw new Error(`State "${newStateName}" not found`);
}
// Note: Linear SDK uses linear.updateIssue() method
await linear.updateIssue(issueId, {
stateId: targetState.id,
});
}
```
### Pattern 5: File Attachments
**Upload and Attach:**
```typescript
async function attachFile(
issueId: string,
filePath: string,
fileName: string
): Promise<void> {
// Request upload URL
const uploadPayload = await linear.fileUpload(
getMimeType(filePath),
fileName,
getFileSize(filePath)
);
// Upload to storage
const fileContent = await Bun.file(filePath).arrayBuffer();
await fetch(uploadPayload.uploadUrl, {
method: 'PUT',
body: fileContent,
headers: { 'Content-Type': getMimeType(filePath) },
});
// Attach to issue
await linear.attachmentCreate({
issueId,
url: uploadPayload.assetUrl,
title: fileName,
});
}
```
### Pattern 6: Comments
**Add Comment:**
```typescript
async function addComment(
issueId: string,
body: string
): Promise<void> {
// Note: Linear SDK uses linear.createComment() method
await linear.createComment({
issueId,
body,
});
}
```
## Best Practices
- Always verify webhook signatures
- Use exponential backoff for API rate limits
- Cache team/state/label IDs to reduce API calls
- Handle webhook delivery failures gracefully
- Log all state transitions for audit
## Examples
### Example 1: Full Issue Lifecycle
```typescript
// Create issue
const issueId = await createIssue(
teamId,
"Add user profile page",
"Implement user profile with avatar upload",
["frontend", "feature"]
);
// Transition to In Progress
await transitionState(issueId, "In Progress");
// ... work happens ...
// Attach proof artifacts
await attachFile(issueId, "screenshot.png", "Desktop Screenshot");
// Add completion comment
await addComment(issueId, "Implementation complete. See attached proof.");
// Transition to In Review
await transitionState(issueId, "In Review");
```
### Example 2: Query Autopilot Queue
```typescript
const tasks = await getAutopilotTasks(teamId);
console.log(`Autopilot queue: ${tasks.length} tasks`);
for (const task of tasks) {
console.log(`- ${task.identifier}: ${task.title} (${task.state.name})`);
}
```Related Skills
Claudish Integration Skill
**Version:** 1.0.0
router-query-integration
Use when setting up route loaders or optimizing navigation performance. Integrates TanStack Router with TanStack Query for optimal data fetching. Covers route loaders with query prefetching, ensuring instant navigation, and eliminating request waterfalls.
api-integration
Use when integrating Apidog + OpenAPI specifications with your React app. Covers MCP server setup, type generation, and query layer integration. Use when setting up API clients, generating types from OpenAPI, or integrating with Apidog MCP.
test-skill
A test skill for validation testing. Use when testing skill parsing and validation logic.
bad-skill
This skill has invalid YAML in frontmatter
release
Plugin release process for MAG Claude Plugins marketplace. Covers version bumping, marketplace.json updates, git tagging, and common mistakes. Use when releasing new plugin versions or troubleshooting update issues.
openrouter-trending-models
Fetch trending programming models from OpenRouter rankings. Use when selecting models for multi-model review, updating model recommendations, or researching current AI coding trends. Provides model IDs, context windows, pricing, and usage statistics from the most recent week.
transcription
Audio/video transcription using OpenAI Whisper. Covers installation, model selection, transcript formats (SRT, VTT, JSON), timing synchronization, and speaker diarization. Use when transcribing media or generating subtitles.
final-cut-pro
Apple Final Cut Pro FCPXML format reference. Covers project structure, timeline creation, clip references, effects, and transitions. Use when generating FCP projects or understanding FCPXML structure.
ffmpeg-core
FFmpeg fundamentals for video/audio manipulation. Covers common operations (trim, concat, convert, extract), codec selection, filter chains, and performance optimization. Use when planning or executing video processing tasks.
statusline-customization
Configuration reference and troubleshooting for the statusline plugin — sections, themes, bar widths, and script architecture
technical-audit
Technical SEO audit methodology including crawlability, indexability, and Core Web Vitals analysis. Use when auditing pages or sites for technical SEO issues.