$npx -y skills add adityahimaone/hermes-agent-rtk-caveman --skill linearManage 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.
| 1 | # Linear — Issue & Project Management |
| 2 | |
| 3 | Manage Linear issues, projects, and teams directly via the GraphQL API using `curl`. No MCP server, no OAuth flow, no extra dependencies. |
| 4 | |
| 5 | ## Setup |
| 6 | |
| 7 | 1. Get a personal API key from **Linear Settings > API > Personal API keys** |
| 8 | 2. Set `LINEAR_API_KEY` in your environment (via `hermes setup` or your env config) |
| 9 | |
| 10 | ## API Basics |
| 11 | |
| 12 | - **Endpoint:** `https://api.linear.app/graphql` (POST) |
| 13 | - **Auth header:** `Authorization: $LINEAR_API_KEY` (no "Bearer" prefix for API keys) |
| 14 | - **All requests are POST** with `Content-Type: application/json` |
| 15 | - **Both UUIDs and short identifiers** (e.g., `ENG-123`) work for `issue(id:)` |
| 16 | |
| 17 | Base curl pattern: |
| 18 | ```bash |
| 19 | curl -s -X POST https://api.linear.app/graphql \ |
| 20 | -H "Authorization: $LINEAR_API_KEY" \ |
| 21 | -H "Content-Type: application/json" \ |
| 22 | -d '{"query": "{ viewer { id name } }"}' | python3 -m json.tool |
| 23 | ``` |
| 24 | |
| 25 | ## Workflow States |
| 26 | |
| 27 | Linear uses `WorkflowState` objects with a `type` field. **6 state types:** |
| 28 | |
| 29 | | Type | Description | |
| 30 | |------|-------------| |
| 31 | | `triage` | Incoming issues needing review | |
| 32 | | `backlog` | Acknowledged but not yet planned | |
| 33 | | `unstarted` | Planned/ready but not started | |
| 34 | | `started` | Actively being worked on | |
| 35 | | `completed` | Done | |
| 36 | | `canceled` | Won't do | |
| 37 | |
| 38 | 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. |
| 39 | |
| 40 | **Priority values:** 0 = None, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low |
| 41 | |
| 42 | ## Common Queries |
| 43 | |
| 44 | ### Get current user |
| 45 | ```bash |
| 46 | curl -s -X POST https://api.linear.app/graphql \ |
| 47 | -H "Authorization: $LINEAR_API_KEY" \ |
| 48 | -H "Content-Type: application/json" \ |
| 49 | -d '{"query": "{ viewer { id name email } }"}' | python3 -m json.tool |
| 50 | ``` |
| 51 | |
| 52 | ### List teams |
| 53 | ```bash |
| 54 | curl -s -X POST https://api.linear.app/graphql \ |
| 55 | -H "Authorization: $LINEAR_API_KEY" \ |
| 56 | -H "Content-Type: application/json" \ |
| 57 | -d '{"query": "{ teams { nodes { id name key } } }"}' | python3 -m json.tool |
| 58 | ``` |
| 59 | |
| 60 | ### List workflow states for a team |
| 61 | ```bash |
| 62 | curl -s -X POST https://api.linear.app/graphql \ |
| 63 | -H "Authorization: $LINEAR_API_KEY" \ |
| 64 | -H "Content-Type: application/json" \ |
| 65 | -d '{"query": "{ workflowStates(filter: { team: { key: { eq: \"ENG\" } } }) { nodes { id name type } } }"}' | python3 -m json.tool |
| 66 | ``` |
| 67 | |
| 68 | ### List issues (first 20) |
| 69 | ```bash |
| 70 | curl -s -X POST https://api.linear.app/graphql \ |
| 71 | -H "Authorization: $LINEAR_API_KEY" \ |
| 72 | -H "Content-Type: application/json" \ |
| 73 | -d '{"query": "{ issues(first: 20) { nodes { identifier title priority state { name type } assignee { name } team { key } url } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool |
| 74 | ``` |
| 75 | |
| 76 | ### List my assigned issues |
| 77 | ```bash |
| 78 | curl -s -X POST https://api.linear.app/graphql \ |
| 79 | -H "Authorization: $LINEAR_API_KEY" \ |
| 80 | -H "Content-Type: application/json" \ |
| 81 | -d '{"query": "{ viewer { assignedIssues(first: 25) { nodes { identifier title state { name type } priority url } } } }"}' | python3 -m json.tool |
| 82 | ``` |
| 83 | |
| 84 | ### Get a single issue (by identifier like ENG-123) |
| 85 | ```bash |
| 86 | curl -s -X POST https://api.linear.app/graphql \ |
| 87 | -H "Authorization: $LINEAR_API_KEY" \ |
| 88 | -H "Content-Type: application/json" \ |
| 89 | -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 |
| 90 | ``` |
| 91 | |
| 92 | ### Search issues by text |
| 93 | ```bash |
| 94 | curl -s -X POST https://api.linear.app/graphql \ |
| 95 | -H "Authorization: $LINEAR_API_KEY" \ |
| 96 | -H "Content-Type: application/json" \ |
| 97 | -d '{"query": "{ issueSearch(query: \"bug login\", first: 10) { nodes { identifier title state { name } assignee { name } url } } }"}' | python3 -m json.tool |
| 98 | ``` |
| 99 | |
| 100 | ### Filter issues by state type |
| 101 | ```bash |
| 102 | curl -s -X POST https://api.linear.app/graphql \ |
| 103 | -H "Authorization: $LINEAR_API_KEY" \ |
| 104 | -H "Content-Type: application/json" \ |
| 105 | -d '{"query": "{ issues(filter: { state: { type: { in: [\"started\"] } } }, first: 20) { nodes { identifier title state { name } assignee { name } } } }"}' | python3 -m json.tool |
| 106 | ``` |
| 107 | |
| 108 | ### Filter by team and assignee |
| 109 | ```bash |
| 110 | curl -s -X POST https://api.linear.app/graphql \ |
| 111 | -H "Authorization: $LINEAR_API_KEY" \ |
| 112 | -H "Content-Type: application/json" \ |
| 113 | -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 |
| 114 | ``` |
| 115 | |
| 116 | ### List projects |
| 117 | ```bash |
| 118 | curl - |