linear
Manage Linear issues, projects, and teams via the GraphQL API. Create, update, search, and organize issues. Uses API key auth (no OAuth needed). All operations via curl — no dependencies.
Manage Linear issues, projects, and teams via the GraphQL API. Create, update, search, and organize issues. Uses API key auth (no OAuth needed). All operations via curl — no dependencies.
Real data. Real impact.
Emerging
Developers
Per week
Excellent
Skills give you superpowers. Install in 30 seconds.
Manage Linear issues, projects, and teams directly via the GraphQL API using
curl. No MCP server, no OAuth flow, no extra dependencies.
LINEAR_API_KEY in your environment (via hermes setup or your env config)https://api.linear.app/graphql (POST)Authorization: $LINEAR_API_KEY (no "Bearer" prefix for API keys)Content-Type: application/jsonENG-123) work for issue(id:)Base curl pattern:
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ viewer { id name } }"}' | python3 -m json.tool
Linear uses
WorkflowState objects with a type field. 6 state types:
| Type | Description |
|---|---|
| Incoming issues needing review |
| Acknowledged but not yet planned |
| Planned/ready but not started |
| Actively being worked on |
| Done |
| Won't do |
Each team has its own named states (e.g., "In Progress" is type
started). To change an issue's status, you need the stateId (UUID) of the target state — query workflow states first.
Priority values: 0 = None, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ viewer { id name email } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ teams { nodes { id name key } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ workflowStates(filter: { team: { key: { eq: \"ENG\" } } }) { nodes { id name type } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issues(first: 20) { nodes { identifier title priority state { name type } assignee { name } team { key } url } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ viewer { assignedIssues(first: 25) { nodes { identifier title state { name type } priority url } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issue(id: \"ENG-123\") { id identifier title description priority state { id name type } assignee { id name } team { key } project { name } labels { nodes { name } } comments { nodes { body user { name } createdAt } } url } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issueSearch(query: \"bug login\", first: 10) { nodes { identifier title state { name } assignee { name } url } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issues(filter: { state: { type: { in: [\"started\"] } } }, first: 20) { nodes { identifier title state { name } assignee { name } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issues(filter: { team: { key: { eq: \"ENG\" } }, assignee: { email: { eq: \"user@example.com\" } } }, first: 20) { nodes { identifier title state { name } priority } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ projects(first: 20) { nodes { id name description progress lead { name } teams { nodes { key } } url } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ users { nodes { id name email active } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issueLabels { nodes { id name color } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }", "variables": { "input": { "teamId": "TEAM_UUID", "title": "Fix login bug", "description": "Users cannot login with SSO", "priority": 2 } } }' | python3 -m json.tool
First get the target state UUID from the workflow states query above, then:
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { stateId: \"STATE_UUID\" }) { success issue { identifier state { name type } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { assigneeId: \"USER_UUID\" }) { success issue { identifier assignee { name } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { priority: 1 }) { success issue { identifier priority } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { commentCreate(input: { issueId: \"ISSUE_UUID\", body: \"Investigated. Root cause is X.\" }) { success comment { id body } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { dueDate: \"2026-04-01\" }) { success issue { identifier dueDate } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { labelIds: [\"LABEL_UUID_1\", \"LABEL_UUID_2\"] }) { success issue { identifier labels { nodes { name } } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { projectId: \"PROJECT_UUID\" }) { success issue { identifier project { name } } } }"}' | python3 -m json.tool
curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id name url } } }", "variables": { "input": { "name": "Q2 Auth Overhaul", "description": "Replace legacy auth with OAuth2 and PKCE", "teamIds": ["TEAM_UUID"] } } }' | python3 -m json.tool
Linear uses Relay-style cursor pagination:
# First page curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issues(first: 20) { nodes { identifier title } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool # Next page — use endCursor from previous response curl -s -X POST https://api.linear.app/graphql \ -H "Authorization: $LINEAR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "{ issues(first: 20, after: \"CURSOR_FROM_PREVIOUS\") { nodes { identifier title } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool
Default page size: 50. Max: 250. Always use
first: N to limit results.
Comparators:
eq, neq, in, nin, lt, lte, gt, gte, contains, startsWith, containsIgnoreCase
Combine filters with
or: [...] for OR logic (default is AND within a filter object).
stateId to the target workflow statestateId to the team's "completed" type statefirst: N to limit results and reduce complexity costX-RateLimit-Requests-Remaining response headerterminal tool with curl for API calls — do NOT use web_extract or browsererrors array in GraphQL responses — HTTP 200 can still contain errorsstateId is omitted when creating issues, Linear defaults to the first backlog statedescription field supports Markdownpython3 -m json.tool or jq to format JSON responses for readabilityMIT
mkdir -p ~/.hermes/skills/productivity/linear && curl -o ~/.hermes/skills/productivity/linear/SKILL.md https://raw.githubusercontent.com/NousResearch/hermes-agent/main/skills/productivity/linear/SKILL.md1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.