Skip to main content
ClaudeWave
ES, Spanish
Skill286 estrellas del repoactualizado 7mo ago

linear-integration

This Linear integration skill provides code patterns for connecting autopilot workflows to the Linear API, enabling authentication, webhook event handling, and CRUD operations on issues, state transitions, file attachments, and comments. Use it when building automation that needs to create or modify Linear issues, respond to Linear events in real time, or synchronize data between Linear and other systems.

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/MadAppGang/claude-code /tmp/linear-integration && cp -r /tmp/linear-integration/plugins/autopilot/skills/linear-integration ~/.claude/skills/linear-integration
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

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})`);
}
adr-documentationSkill

Architecture Decision Records (ADR) documentation practice. Use when documenting architectural decisions, recording technical trade-offs, creating decision logs, or establishing architectural patterns. Trigger keywords - "ADR", "architecture decision", "decision record", "trade-offs", "architectural decision", "decision log".

agent-coordination-disciplineSkill

Use when deciding whether to launch an agent, selecting which agent to use, or coordinating multiple agents. Covers delegation criteria, external-model patterns, task isolation, and agent selection strategies.

api-designSkill

Use when designing REST or GraphQL APIs, defining endpoints, implementing pagination/filtering, handling API versioning, or establishing API documentation with OpenAPI/Swagger.

api-integrationSkill

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.

api-spec-analyzerSkill

Analyzes API documentation from OpenAPI specs to provide TypeScript interfaces, request/response formats, and implementation guidance. Use when implementing API integrations, debugging API errors (400, 401, 404), replacing mock APIs, verifying data types, or when user mentions endpoints, API calls, or backend integration.

architect-detectiveSkill

Use when analyzing architecture and system design. Find design patterns, map layers, identify core abstractions via PageRank. Uses claudemem AST structural analysis for efficient architecture investigation.

auditSkill

On-demand security and code quality audit. Use when checking for vulnerabilities, security issues, code smells, or compliance problems. Trigger keywords - "audit", "security check", "vulnerability scan", "code quality", "compliance", "security audit".

auth-patternsSkill

Use when implementing authentication (JWT, sessions, OAuth), authorization (RBAC, ABAC), password hashing, MFA, or security best practices for backend services.