Skip to main content
linear-integration Linear API patterns and examples for autolinear. Includes authentication, webhooks, issue CRUD, state transitions, file attachments, and comment handling.
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/MadAppGang/magus-alpha --skill linear-integrationThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... SOC
Based on SOC occupation classification
More from this repository name linear-integration description Linear API patterns and examples for autolinear. 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"] user-invocable false
plugin: autolinear
updated: 2026-01-20
Linear Integration
Version: 0.1.0
Purpose: Patterns for Linear API integration in autolinear 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 .AUTOLINEAR_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 .AUTOLINEAR_BOT_USER_ID ,
priority : 2 ,
});
const issue = await result.issue ;
return issue!.id ;
}
async function getAutoLinearTasks (teamId : string ) {
const issues = await linear.issues ({
filter : {
team : { id : { eq : teamId } },
assignee : { id : { eq : process.env .AUTOLINEAR_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 AutoLinear Queue const tasks = await getAutoLinearTasks (teamId);
console .log (`AutoLinear queue: ${tasks.length} tasks` );
for (const task of tasks) {
console .log (`- ${task.identifier} : ${task.title} (${task.state.name} )` );
}