skills/linear/SKILL.md
Interact with Linear project management - query issues, update status, create tickets, and manage workflows using the Linear GraphQL API. Use when working with Linear tickets, sprints, or project tracking.
npx skillsauth add openhands/skills linearInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Windows PowerShell equivalents for the repeated Linear GraphQL curl and environment-variable snippets are in references/windows.md.
[ -n "$LINEAR_API_KEY" ] && echo "LINEAR_API_KEY is set" || echo "LINEAR_API_KEY is NOT set"
If LINEAR_API_KEY is missing, ask the user to provide it before proceeding. </IMPORTANT>
Linear uses two types of identifiers for issues:
ALL-1234): Displayed to users, used in search queries. This is the team key + number.a1b2c3d4-e5f6-7890-abcd-ef1234567890): Required for all mutations (update, comment, etc.). Returned as id in query results.Important workflow: When working with issues, you must:
id (UUID) from the query resultAll Linear API requests use GraphQL with the API key in the Authorization header:
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{"query": "YOUR_GRAPHQL_QUERY"}'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { viewer { assignedIssues(first: 50, filter: { state: { type: { nin: [\"completed\", \"canceled\"] } } }) { nodes { id identifier title priority priorityLabel state { name type } description createdAt updatedAt } } } }"
}' | jq '.data.viewer.assignedIssues.nodes'
Priority values: 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { viewer { assignedIssues(first: 50, filter: { priority: { lte: 2 }, state: { type: { nin: [\"completed\", \"canceled\"] } } }) { nodes { id identifier title priority priorityLabel state { name } } } } }"
}' | jq '.data.viewer.assignedIssues.nodes'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { issue(id: \"ISSUE_UUID\") { id identifier title description state { name } priority assignee { name email } labels { nodes { name } } comments { nodes { body createdAt user { name } } } } }"
}' | jq '.data.issue'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { issueSearch(query: \"ALL-1234\", first: 5) { nodes { id identifier title state { name } } } }"
}' | jq '.data.issueSearch.nodes'
First, get available workflow states:
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { workflowStates { nodes { id name type } } }"
}' | jq '.data.workflowStates.nodes'
Then update the issue:
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation { issueUpdate(id: \"ISSUE_UUID\", input: { stateId: \"STATE_UUID\" }) { success issue { identifier state { name } } } }"
}' | jq '.data.issueUpdate'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation { commentCreate(input: { issueId: \"ISSUE_UUID\", body: \"Your comment here\" }) { success comment { id body } } }"
}' | jq '.data.commentCreate'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation { issueCreate(input: { teamId: \"TEAM_UUID\", title: \"Issue Title\", description: \"Issue description\", priority: 2 }) { success issue { identifier title url } } }"
}' | jq '.data.issueCreate'
This example shows the complete flow to change an issue's state using its human-readable identifier:
# Search for issue ALL-1234 and extract its UUID
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { issueSearch(query: \"ALL-1234\", first: 1) { nodes { id identifier title state { name } } } }"
}' | jq '.data.issueSearch.nodes[0]'
# Save the "id" value (UUID) from the response
# List all workflow states to find the "In Progress" state UUID
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { workflowStates { nodes { id name type } } }"
}' | jq '.data.workflowStates.nodes[] | select(.name == "In Progress")'
# Save the "id" value of the desired state
# Use the issue UUID and state UUID from previous steps
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "mutation { issueUpdate(id: \"ISSUE_UUID_FROM_STEP_1\", input: { stateId: \"STATE_UUID_FROM_STEP_2\" }) { success issue { identifier state { name } } } }"
}' | jq '.data.issueUpdate'
curl -s -X POST https://api.linear.app/graphql \
-H "Content-Type: application/json" \
-H "Authorization: $LINEAR_API_KEY" \
-d '{
"query": "query { teams { nodes { id name key } } }"
}' | jq '.data.teams.nodes'
| Priority | Label | Recommended Action | |----------|-------|-------------------| | 1 | Urgent | Work on immediately | | 2 | High | Work on first | | 3 | Medium | Normal priority | | 4 | Low | When time permits | | 0 | None | Backlog |
backlog - Not yet startedunstarted - Todostarted - In Progresscompleted - Donecanceled - Won't dotools
Iterate on a GitHub pull request — drive it through CI, code review, and QA until it is merge-ready. Poll verification layers with `gh` CLI, diagnose and fix CI failures, address review feedback, retry flaky checks, push fixes, and repeat. The agent is the orchestration loop.
development
Guides technical explanations toward flowing, direct, conversational prose. This skill should be used for engineering chat, design discussion, architecture analysis, code-review explanations, and technical recommendations that should be concise without becoming fragmented or vague.
tools
This skill should be used when the user asks to "set up a Jira automation to create pull requests", "poll Jira for create-pr issues", "automatically create GitHub PRs from Jira tickets", "deploy a Jira issue-to-PR automation", "create a Jira to GitHub PR workflow", or mentions automating GitHub PR creation from a Jira label. Deploys a cron-based OpenHands automation that watches a Jira Cloud project for issues labeled with a configurable label (default: "create-pr") and spawns an agent conversation to create a GitHub pull request for each new issue found. The target GitHub repository is read from the body of the Jira ticket - no repo parameter is required at deploy time.
tools
This skill should be used when the user asks to "create an automation", "schedule a task", "set up a cron job", "webhook integration", "event-triggered automation", or mentions automations, scheduled tasks, cron scheduling, or webhook events in OpenHands Cloud.