{“content”:”---\nname: linear\ndescription: 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.\nversion: 1.0.0\nauthor: Hermes Agent\nlicense: MIT\nprerequisites:\n env_vars: [LINEAR_API_KEY]\n commands: [curl]\nmetadata:\n hermes:\n tags: [Linear, Project Management, Issues, GraphQL, API, Productivity]\n---\n\n# Linear — Issue & Project Management\n\nManage Linear issues, projects, and teams directly via the GraphQL API using curl. No MCP server, no OAuth flow, no extra dependencies.\n\n## Setup\n\n1. Get a personal API key from Linear Settings > API > Personal API keys\n2. Set LINEAR_API_KEY in your environment (via hermes setup or your env config)\n\n## API Basics\n\n- Endpoint: https://api.linear.app/graphql (POST)\n- Auth header: Authorization: $LINEAR_API_KEY (no “Bearer” prefix for API keys)\n- All requests are POST with Content-Type: application/json\n- Both UUIDs and short identifiers (e.g., ENG-123) work for issue(id:)\n\nBase curl pattern:\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ viewer { id name } }\"}' | python3 -m json.tool\n\n\n## Workflow States\n\nLinear uses WorkflowState objects with a type field. 6 state types:\n\n| Type | Description |\n|------|-------------|\n| triage | Incoming issues needing review |\n| backlog | Acknowledged but not yet planned |\n| unstarted | Planned/ready but not started |\n| started | Actively being worked on |\n| completed | Done |\n| canceled | Won’t do |\n\nEach 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.\n\nPriority values: 0 = None, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low\n\n## Common Queries\n\n### Get current user\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ viewer { id name email } }\"}' | python3 -m json.tool\n\n\n### List teams\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ teams { nodes { id name key } } }\"}' | python3 -m json.tool\n\n\n### List workflow states for a team\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ workflowStates(filter: { team: { key: { eq: \\\"ENG\\\" } } }) { nodes { id name type } } }\"}' | python3 -m json.tool\n\n\n### List issues (first 20)\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issues(first: 20) { nodes { identifier title priority state { name type } assignee { name } team { key } url } pageInfo { hasNextPage endCursor } } }\"}' | python3 -m json.tool\n\n\n### List my assigned issues\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ viewer { assignedIssues(first: 25) { nodes { identifier title state { name type } priority url } } } }\"}' | python3 -m json.tool\n\n\n### Get a single issue (by identifier like ENG-123)\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -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\n\n\n### Search issues by text\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issueSearch(query: \\\"bug login\\\", first: 10) { nodes { identifier title state { name } assignee { name } url } } }\"}' | python3 -m json.tool\n\n\n### Filter issues by state type\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issues(filter: { state: { type: { in: [\\\"started\\\"] } } }, first: 20) { nodes { identifier title state { name } assignee { name } } } }\"}' | python3 -m json.tool\n\n\n### Filter by team and assignee\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issues(filter: { team: { key: { eq: \\\"ENG\\\" } }, assignee: { email: { eq: \\\"[email protected]\\\" } } }, first: 20) { nodes { identifier title state { name } priority } } }\"}' | python3 -m json.tool\n\n\n### List projects\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ projects(first: 20) { nodes { id name description progress lead { name } teams { nodes { key } } url } } }\"}' | python3 -m json.tool\n\n\n### List team members\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ users { nodes { id name email active } } }\"}' | python3 -m json.tool\n\n\n### List labels\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issueLabels { nodes { id name color } } }\"}' | python3 -m json.tool\n\n\n## Common Mutations\n\n### Create an issue\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }\",\n \"variables\": {\n \"input\": {\n \"teamId\": \"TEAM_UUID\",\n \"title\": \"Fix login bug\",\n \"description\": \"Users cannot login with SSO\",\n \"priority\": 2\n }\n }\n }' | python3 -m json.tool\n\n\n### Update issue status\nFirst get the target state UUID from the workflow states query above, then:\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { issueUpdate(id: \\\"ENG-123\\\", input: { stateId: \\\"STATE_UUID\\\" }) { success issue { identifier state { name type } } } }\"}' | python3 -m json.tool\n\n\n### Assign an issue\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { issueUpdate(id: \\\"ENG-123\\\", input: { assigneeId: \\\"USER_UUID\\\" }) { success issue { identifier assignee { name } } } }\"}' | python3 -m json.tool\n\n\n### Set priority\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { issueUpdate(id: \\\"ENG-123\\\", input: { priority: 1 }) { success issue { identifier priority } } }\"}' | python3 -m json.tool\n\n\n### Add a comment\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { commentCreate(input: { issueId: \\\"ISSUE_UUID\\\", body: \\\"Investigated. Root cause is X.\\\" }) { success comment { id body } } }\"}' | python3 -m json.tool\n\n\n### Set due date\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { issueUpdate(id: \\\"ENG-123\\\", input: { dueDate: \\\"2026-04-01\\\" }) { success issue { identifier dueDate } } }\"}' | python3 -m json.tool\n\n\n### Add labels to an issue\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -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\n\n\n### Add issue to a project\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"mutation { issueUpdate(id: \\\"ENG-123\\\", input: { projectId: \\\"PROJECT_UUID\\\" }) { success issue { identifier project { name } } } }\"}' | python3 -m json.tool\n\n\n### Create a project\nbash\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"query\": \"mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id name url } } }\",\n \"variables\": {\n \"input\": {\n \"name\": \"Q2 Auth Overhaul\",\n \"description\": \"Replace legacy auth with OAuth2 and PKCE\",\n \"teamIds\": [\"TEAM_UUID\"]\n }\n }\n }' | python3 -m json.tool\n\n\n## Pagination\n\nLinear uses Relay-style cursor pagination:\n\nbash\n# First page\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issues(first: 20) { nodes { identifier title } pageInfo { hasNextPage endCursor } } }\"}' | python3 -m json.tool\n\n# Next page — use endCursor from previous response\ncurl -s -X POST https://api.linear.app/graphql \\\n -H \"Authorization: $LINEAR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"query\": \"{ issues(first: 20, after: \\\"CURSOR_FROM_PREVIOUS\\\") { nodes { identifier title } pageInfo { hasNextPage endCursor } } }\"}' | python3 -m json.tool\n\n\nDefault page size: 50. Max: 250. Always use first: N to limit results.\n\n## Filtering Reference\n\nComparators: eq, neq, in, nin, lt, lte, gt, gte, contains, startsWith, containsIgnoreCase\n\nCombine filters with or: [...] for OR logic (default is AND within a filter object).\n\n## Typical Workflow\n\n1. Query teams to get team IDs and keys\n2. Query workflow states for target team to get state UUIDs\n3. List or search issues to find what needs work\n4. Create issues with team ID, title, description, priority\n5. Update status by setting stateId to the target workflow state\n6. Add comments to track progress\n7. Mark complete by setting stateId to the team’s “completed” type state\n\n## Rate Limits\n\n- 5,000 requests/hour per API key\n- 3,000,000 complexity points/hour\n- Use first: N to limit results and reduce complexity cost\n- Monitor X-RateLimit-Requests-Remaining response header\n\n## Important Notes\n\n- Always use terminal tool with curl for API calls — do NOT use web_extract or browser\n- Always check the errors array in GraphQL responses — HTTP 200 can still contain errors\n- If stateId is omitted when creating issues, Linear defaults to the first backlog state\n- The description field supports Markdown\n- Use python3 -m json.tool or jq to format JSON responses for readability\n”}