Skip to main content
linear-integration Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/MadAppGang/claude-code --skill linear-integration명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... SOC
name linear-integration description Linear API patterns and examples for autopilot. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling. version 0.1.0 tags ["linear","api","webhook","integration"] keywords ["linear","api","webhook","issue","comment","state","attachment"]
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 import { LinearClient } from '@linear/sdk' ;
const linear = new LinearClient ({
apiKey : process.env .LINEAR_API_KEY
});
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 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 });
}
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);
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 async function createIssue (
teamId : string ,
title : string ,
description : string ,
labels : string []
): Promise <string > {
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 ;
}
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 async function transitionState (
issueId : string ,
newStateName : string
): Promise <void > {
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` );
}
await linear.updateIssue (issueId, {
stateId : targetState.id ,
});
}
Pattern 5: File Attachments async function attachFile (
issueId : string ,
filePath : string ,
fileName : string
): Promise <void > {
const uploadPayload = await linear.fileUpload (
getMimeType (filePath),
fileName,
getFileSize (filePath)
);
const fileContent = await Bun .file (filePath).arrayBuffer ();
await fetch (uploadPayload.uploadUrl , {
method : 'PUT' ,
body : fileContent,
headers : { 'Content-Type' : getMimeType (filePath) },
});
await linear.attachmentCreate ({
issueId,
url : uploadPayload.assetUrl ,
title : fileName,
});
}
Pattern 6: Comments async function addComment (
issueId : string ,
body : string
): Promise <void > {
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
const issueId = await createIssue (
teamId,
"Add user profile page" ,
"Implement user profile with avatar upload" ,
["frontend" , "feature" ]
);
await transitionState (issueId, "In Progress" );
await attachFile (issueId, "screenshot.png" , "Desktop Screenshot" );
await addComment (issueId, "Implementation complete. See attached proof." );
await transitionState (issueId, "In Review" );
Example 2: Query Autopilot Queue 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} )` );
}