skills/linear/SKILL.md
Linear issue tracker API integration. Covers first-use identity bootstrap (viewer + teams cached), raw GraphQL for list/search/create/update, and the rules for handling "my issues" / "assigned to me" requests.
npx skillsauth add nearai/ironclaw 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.
You have access to the Linear GraphQL API via the http tool. Credentials are automatically injected — never construct Authorization headers manually. When the URL host is api.linear.app, the system injects Authorization: {linear_api_key} transparently (no Bearer prefix — Linear API keys are sent raw).
Linear's API key does not tell you who the user IS inside Linear. Before running any "my issues" / "assigned to me" / "my tickets" request, make sure the user's Linear identity is cached. This avoids re-fetching viewer on every request and makes filter-by-assignee queries deterministic.
Path: context/intel/linear-identity.md
Shape:
---
type: linear-identity
bootstrapped_at: 2026-04-21
refreshed_at: 2026-04-21
stale_after: 2026-05-21
---
# Linear identity
user_id: 8a7f...-uuid
display_name: Tobias Holenstein
email: tobias@...
timezone: Europe/Zurich
## Teams
- id: team-uuid-a, key: ENG, name: Engineering
- id: team-uuid-b, key: PROD, name: Product
## Default team
ENG
memory_read("context/intel/linear-identity.md"). If the file exists and stale_after is in the future, use it and stop.query { viewer { id name displayName email } teams(first: 50) { nodes { id key name } } }
memory_write with stale_after = today + 30 days.Default team. If more than one, ask the user once: "I see teams ENG, PROD, OPS. Which one do you default to for new issues?" and store the answer.AuthenticationError GraphQL error, invalidate the cache and re-prompt the user to check their API key — do not silently retry.assignee: { id: { eq: "<cached user_id>" } }, not by assignee: { isMe: true } (the isMe filter is not universally available and viewer round-trips are wasteful).Default team id without asking.Linear uses a single GraphQL endpoint: https://api.linear.app/graphql
All requests are POST with a JSON body containing query and optional variables.
http(method="POST", url="https://api.linear.app/graphql", body={"query": "{ issues(first: 20, orderBy: updatedAt) { nodes { id identifier title state { name } assignee { name } priority priorityLabel createdAt } } }"})
http(method="POST", url="https://api.linear.app/graphql", body={"query": "query($uid: ID!) { issues(filter: { assignee: { id: { eq: $uid } }, state: { type: { nin: [completed, canceled] } } }, first: 50, orderBy: updatedAt) { nodes { id identifier title state { name type } priority priorityLabel url updatedAt } } }", "variables": {"uid": "<cached user_id>"}})
Never pass viewer.id inline from a fresh round-trip when the cache is valid — consult context/intel/linear-identity.md.
http(method="POST", url="https://api.linear.app/graphql", body={"query": "query($id: String!) { issue(id: $id) { id identifier title description state { name } assignee { name } labels { nodes { name } } comments { nodes { body user { name } createdAt } } } }", "variables": {"id": "ISSUE_ID"}})
http(method="POST", url="https://api.linear.app/graphql", body={"query": "query($term: String!) { issueSearch(query: $term, first: 10) { nodes { id identifier title state { name } priorityLabel } } }", "variables": {"term": "SEARCH_TERM"}})
http(method="POST", url="https://api.linear.app/graphql", body={"query": "mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }", "variables": {"input": {"title": "...", "description": "...", "teamId": "TEAM_ID", "priority": 2}}})
http(method="POST", url="https://api.linear.app/graphql", body={"query": "{ teams { nodes { id name key } } }"})
http(method="POST", url="https://api.linear.app/graphql", body={"query": "mutation($id: String!, $stateId: String!) { issueUpdate(id: $id, input: { stateId: $stateId }) { success issue { id identifier title state { name } } } }", "variables": {"id": "ISSUE_UUID", "stateId": "STATE_UUID"}})
{"data": {...}} on success, {"errors": [...]} on failure.ENG-123 (team key + number).errors in the response before processing data.message and optional extensions with error codes.Authorization header — it is injected automatically.POST method — Linear's API is GraphQL only.id field is a UUID, the identifier field is human-readable (e.g., ENG-42).issueSearch for text search, not issues with a filter (text search is separate).teamId. List teams first if unknown.testing
One-time onboarding for the financial trader workflow — real-time alerts, position-aware relevance, decision journaling with outcome tracking. After successful setup this skill is excluded from selection until the marker file is deleted.
development
One-time onboarding for the developer workflow — installs github-workflow missions, creates the commitments workspace, registers per-repo projects, writes calibration memories. After successful setup this skill is excluded from selection until the marker file is deleted.
devops
One-time onboarding for the content creator workflow — content pipeline stages, trend expiration, cross-platform cascades, heavy idea parking. After successful setup this skill is excluded from selection until the marker file is deleted.
testing
One-time onboarding for the executive/manager commitment workflow — delegation-heavy, meeting prep, decision capture, morning and evening digests. Creates a `commitments` project and installs two dashboard widgets. After successful setup this skill is excluded from selection until the marker file is deleted.