linear · git:20260717.672f619 · 2026-07-17 · sha256 ae22d2870253a304

linear git:20260717.672f619A

Immutable. This exact content is served forever at /api/v1/blob/ae22d2870253a304.

---
name: linear
description: >-
  Manage Linear teams, projects, cycles, issues, comments, workflow state, and documents from a terminal through
  Linear's public GraphQL API. Use when a user asks to list, search, inspect, create, update,
  move, or comment on Linear work, or to find Linear documents. Do not use to embed a live agent
  inside Linear or to build an MCP integration.
license: MIT
compatibility: Requires Python 3.8+; network access and a Linear personal API key or OAuth access token for live API requests.
metadata:
  service: Linear
  api: GraphQL
  graphql-docs: https://linear.app/developers/graphql
  oauth-docs: https://linear.app/developers/oauth-2-0-authentication
  rate-limit-docs: https://linear.app/developers/rate-limiting
  agent-interaction-docs: https://linear.app/developers/agent-interaction
allowed-tools: Bash Read
---

# Linear

Use `scripts/linear` from this skill directory. It is a small, dependency-free wrapper around
Linear's public GraphQL API, not an MCP server. Use command-specific `--help` rather than copying
the full command reference into a response.

## Setup

1. Inspect the available command and relevant noun: `scripts/linear --help` and `scripts/linear issue --help`.
2. For a live request, set exactly one credential in the process environment. Use `LINEAR_API_KEY`
   for a personal key or `LINEAR_ACCESS_TOKEN` for OAuth. Never print, persist, or place either in a command transcript.
3. Begin with bounded discovery. Reads default to `--limit 10`; the maximum is 100.
4. Output is always JSON: compact with `--json`, indented without it. `--dry-run` makes no network request and previews the operation.

## Command Map

| Need | Command |
|---|---|
| Confirm current identity | `scripts/linear whoami --json` |
| Discover teams | `scripts/linear team list --limit 20 --json` |
| Narrow a known issue set | `scripts/linear issue list --team ENG --state "In Progress" --json` |
| Find an issue by words | `scripts/linear issue search "customer import" --json` |
| Read one known issue | `scripts/linear issue get ENG-42 --json` |
| Read an issue with its project, cycle, hierarchy, comments, and relations | `scripts/linear issue get ENG-42 --detail --json` |
| List or read projects | `scripts/linear project list --team ENG --json` or `scripts/linear project get "Roadmap" --json` |
| List or read cycles | `scripts/linear cycle list --team ENG --json` or `scripts/linear cycle get UUID --json` |
| Find documents by words | `scripts/linear document search roadmap --json` |
| Read a document by UUID, slug, or URL | `scripts/linear document get REF --json` |
| Use a documented unsupported GraphQL operation | `scripts/linear raw 'query { viewer { id } }' --json` |

## Choose the Smallest Read

| Situation | Use |
|---|---|
| You know an issue identifier or UUID | `issue get` |
| You have words but not an identifier | `issue search` or `document search` |
| You need a bounded set with filters | `issue list`, `document list`, `project list`, or `cycle list` |
| The task needs a documented operation outside this focused CLI | `raw` with an explicit GraphQL query |

`raw` is an escape hatch, not a replacement for normal commands. Keep its query narrow and use
the official GraphQL documentation to confirm field names and permissions.

## State Changes

Confirm the target, scope, and rollback path before acting. Read-only discovery may proceed without confirmation.

For `issue create`, `issue update`, `issue move`, `issue comment`, and raw GraphQL mutations:

1. Identify the issue/team/state using a read command.
2. State the exact intended change and recovery path to the user.
3. Run the same command with `--dry-run --json`; this has no credentials or network requirement.
4. After confirmation, rerun it with `--confirm --json`.
5. Report the returned identifier and outcome without exposing credentials.

The `--team` filters for issue, project, and cycle lists require an exact team key. `issue create`
resolves a team key or exact name before creation, resolves issue identifiers before comments or
updates, and resolves a destination workflow state only within that issue's team.
It does not guess IDs or workflow states. Load `references/domain-and-workflows.md` for safe
mutation recipes and Linear workflow semantics.

## Errors And Recovery

- Missing credentials: export one supported environment variable only for the command session, or use `--dry-run` to inspect the request.
- GraphQL error: the CLI writes Linear's first useful error message to stderr and exits nonzero, including when the HTTP status is 200. Check permissions, exact identifiers, and documented field availability.
- Team ambiguity: use `team list` to choose an exact key/name; do not retry by guessing an ID.
- State lookup failure: the error lists the available states for the issue's team. Use that exact name, or use documented `raw` GraphQL as the explicit escape hatch when the focused CLI cannot express the operation.
- Limit failure: choose a value from 1 through 100. The CLI deliberately does not paginate automatically.
- Rate limit or transport failure: wait and retry the same bounded read. Follow Linear's [rate limiting guidance](https://linear.app/developers/rate-limiting) rather than adding a retry loop.

## References

| When you need... | Load... |
|---|---|
| Linear's data model, workflow semantics, safe mutation recipes | `references/domain-and-workflows.md` |
| GraphQL endpoint, auth, filters, pagination, errors, rate limits | `references/graphql-contract.md` |
| CLI vs MCP vs raw GraphQL vs Agent Session decision | `references/integration-boundaries.md` |
| Source URLs, access dates, schema verification procedure | `references/sources.md` |

## Verification

Run the offline tests and repository validator after changes:

```bash
python3 -m unittest linear/tests/test_linear.py
ruby scripts/validate-skills.rb
```

## When Not To Use

Use Linear's native MCP or agent-session/webhook API when the task is to embed a live agent inside
Linear rather than operate Linear from a terminal.