ScriptsMay 8, 2026·3 min read

Linear SDK — TypeScript Client for Linear Agents

Linear SDK is the official TypeScript client. GraphQL-typed methods cover every Linear API surface. Drop into Inngest or Trigger.dev for issue automation.

Agent ready

This asset can be read and installed directly by agents

TokRepo exposes a universal CLI command, install contract, metadata JSON, adapter-aware plan, and raw content links so agents can judge fit, risk, and next actions.

Stage only · 5/100Stage only
Agent surface
Any MCP/CLI agent
Kind
CLI Tool
Install
Stage only
Trust
Trust: New
Entrypoint
Asset
Universal CLI install command
npx tokrepo install ade6b301-4446-4383-aa18-352b7330f90c
Intro

The Linear SDK is the official TypeScript client wrapping Linear's GraphQL API. Every method is fully typed (Issue, Project, Cycle, Team, User), with built-in pagination and rate-limit handling. Best for: agents and bots that automate Linear beyond what MCP covers — bulk imports, complex queries, scheduled triage. Works with: Node 18+, Bun, Deno. Setup time: 2 minutes.


Hello, Linear

import { LinearClient } from "@linear/sdk";

const linear = new LinearClient({ apiKey: process.env.LINEAR_API_KEY });

// Get my issues
const me = await linear.viewer;
const issues = await me.assignedIssues({ first: 50 });

for (const issue of issues.nodes) {
  console.log(`${issue.identifier}${issue.title} (${(await issue.state).name})`);
}

Create an issue with all the trimmings

const team = await linear.team("ENG");

const issue = await linear.createIssue({
  teamId: team.id,
  title: "Auth flow drops state on redirect",
  description: "**Steps to reproduce:**\n1. Login\n2. Click external link\n3. Click back\n\nState lost.",
  priority: 1,  // Urgent
  assigneeId: (await linear.viewer).id,
  labelIds: [
    (await team.labels()).nodes.find(l => l.name === "bug")?.id!,
  ],
  projectId: "your-project-id",
});

console.log(`Created ${issue.issue?.identifier}`);

Bulk triage with rate-limit awareness

import pLimit from "p-limit";

const limit = pLimit(5);  // 5 concurrent calls; SDK auto-retries on 429

const stale = await linear.issues({
  filter: {
    state: { type: { eq: "started" } },
    updatedAt: { lt: new Date(Date.now() - 14 * 86400_000) },
  },
});

await Promise.all(
  stale.nodes.map(issue =>
    limit(() =>
      issue.update({
        labelIds: [...issue.labelIds, STALE_LABEL_ID],
      }),
    ),
  ),
);

Webhook payloads (in tandem with SDK)

// Express handler
app.post("/webhooks/linear", async (req, res) => {
  if (req.body.action === "create" && req.body.type === "Issue") {
    const issue = await linear.issue(req.body.data.id);
    if ((await issue.priority) === 1) {
      await notifySlack(`🔥 Urgent issue: ${issue.title}`);
    }
  }
  res.sendStatus(200);
});

FAQ

Q: SDK vs MCP — when to use which? A: MCP for interactive agents (Claude Code asks Linear questions during a session). SDK for scheduled or webhook-driven automation (Inngest jobs, GitHub Actions, server-side bots). Many teams use both.

Q: Is the SDK rate-limit-aware? A: Yes — built-in retry with exponential backoff on 429s. For high-throughput jobs, combine with p-limit (concurrency cap) and persist progress so you can resume.

Q: Does it support Linear's GraphQL directly? A: Yes — every typed SDK method is just a wrapper over GraphQL. For queries the SDK doesn't expose, use linear.client.rawRequest(query, variables) to send arbitrary GraphQL.


Quick Use

  1. npm install @linear/sdk
  2. Generate a personal API key in Linear → Settings → API
  3. const linear = new LinearClient({ apiKey }), then call typed methods like linear.issues({ filter: ... })

Intro

The Linear SDK is the official TypeScript client wrapping Linear's GraphQL API. Every method is fully typed (Issue, Project, Cycle, Team, User), with built-in pagination and rate-limit handling. Best for: agents and bots that automate Linear beyond what MCP covers — bulk imports, complex queries, scheduled triage. Works with: Node 18+, Bun, Deno. Setup time: 2 minutes.


Hello, Linear

import { LinearClient } from "@linear/sdk";

const linear = new LinearClient({ apiKey: process.env.LINEAR_API_KEY });

// Get my issues
const me = await linear.viewer;
const issues = await me.assignedIssues({ first: 50 });

for (const issue of issues.nodes) {
  console.log(`${issue.identifier}${issue.title} (${(await issue.state).name})`);
}

Create an issue with all the trimmings

const team = await linear.team("ENG");

const issue = await linear.createIssue({
  teamId: team.id,
  title: "Auth flow drops state on redirect",
  description: "**Steps to reproduce:**\n1. Login\n2. Click external link\n3. Click back\n\nState lost.",
  priority: 1,  // Urgent
  assigneeId: (await linear.viewer).id,
  labelIds: [
    (await team.labels()).nodes.find(l => l.name === "bug")?.id!,
  ],
  projectId: "your-project-id",
});

console.log(`Created ${issue.issue?.identifier}`);

Bulk triage with rate-limit awareness

import pLimit from "p-limit";

const limit = pLimit(5);  // 5 concurrent calls; SDK auto-retries on 429

const stale = await linear.issues({
  filter: {
    state: { type: { eq: "started" } },
    updatedAt: { lt: new Date(Date.now() - 14 * 86400_000) },
  },
});

await Promise.all(
  stale.nodes.map(issue =>
    limit(() =>
      issue.update({
        labelIds: [...issue.labelIds, STALE_LABEL_ID],
      }),
    ),
  ),
);

Webhook payloads (in tandem with SDK)

// Express handler
app.post("/webhooks/linear", async (req, res) => {
  if (req.body.action === "create" && req.body.type === "Issue") {
    const issue = await linear.issue(req.body.data.id);
    if ((await issue.priority) === 1) {
      await notifySlack(`🔥 Urgent issue: ${issue.title}`);
    }
  }
  res.sendStatus(200);
});

FAQ

Q: SDK vs MCP — when to use which? A: MCP for interactive agents (Claude Code asks Linear questions during a session). SDK for scheduled or webhook-driven automation (Inngest jobs, GitHub Actions, server-side bots). Many teams use both.

Q: Is the SDK rate-limit-aware? A: Yes — built-in retry with exponential backoff on 429s. For high-throughput jobs, combine with p-limit (concurrency cap) and persist progress so you can resume.

Q: Does it support Linear's GraphQL directly? A: Yes — every typed SDK method is just a wrapper over GraphQL. For queries the SDK doesn't expose, use linear.client.rawRequest(query, variables) to send arbitrary GraphQL.


Source & Thanks

Built by Linear. MIT-licensed.

linear/linear-sdk — ⭐ Active

🙏

Source & Thanks

Built by Linear. MIT-licensed.

linear/linear-sdk — ⭐ Active

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets