shared/skills/linear/SKILL.md
Read, create, and update Linear issues/projects/cycles using the Linear GraphQL API with a personal API key (no MCP required). Use when the user wants to look up, file, or edit Linear tickets.
npx skillsauth add nsimonfr/nic-os 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.
Two Linear workspaces are available:
| Env var | Workspace | Team | Key |
|---|---|---|---|
| $LINEAR_KEY | nsimon (personal) | nSimon (NSI) | default |
| $LINEAR_KEY_TRUSK | trusk (work) | — | use for trusk-specific queries |
Default to $LINEAR_KEY (nsimon workspace) for all queries unless the user explicitly asks about Trusk.
Keys are format lin_api_…. All API calls go to https://api.linear.app/graphql with header Authorization: $LINEAR_KEY (no Bearer prefix — Linear personal keys are sent raw). If LINEAR_KEY is unset, stop and tell the user.
# Sanity check — should print your name
curl -sS -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ viewer { id name email } }"}' | jq .
For the nsimon workspace, the default team is nSimon:
f70e4ca5-9442-4489-82f8-9a988269961bNSIWhen creating issues or searching, use this team ID unless told otherwise.
All examples use the default nsimon workspace ($LINEAR_KEY). For trusk, swap $LINEAR_KEY → $LINEAR_KEY_TRUSK.
linear_q() {
curl -sS -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -nc --arg q "$1" --argjson v "${2:-{}}" '{query:$q, variables:$v}')"
}
# nsimon team ID (default)
NSIMON_TEAM="f70e4ca5-9442-4489-82f8-9a988269961b"
# Teams (id, key, name)
linear_q 'query { teams(first:50) { nodes { id key name } } }' | jq '.data.teams.nodes'
# My open issues (nsimon)
linear_q 'query { viewer { assignedIssues(filter:{state:{type:{nin:["completed","canceled"]}}}, first:50) { nodes { identifier title state { name } url } } } }' | jq '.data.viewer.assignedIssues.nodes'
# Issue by identifier (e.g. NSI-42)
linear_q 'query($id:String!){ issue(id:$id){ id identifier title description state{name} priority assignee{name} labels{nodes{name}} url } }' '{"id":"NSI-42"}' | jq '.data.issue'
# Search issues in the nSimon team
linear_q 'query($q:String!,$tid:String!){ issues(filter:{team:{id:{eq:$tid}}, title:{containsIgnoreCase:$q}}, first:25){ nodes{ identifier title state{name} url } } }' '{"q":"flaky","tid":"'$NSIMON_TEAM'"}' | jq
# Workflow states for the nSimon team
linear_q 'query($tid:String!){ team(id:$tid){ states{ nodes{ id name type } } } }' '{"tid":"'$NSIMON_TEAM'"}' | jq
# List all open issues in nSimon team
linear_q 'query($tid:String!){ issues(filter:{team:{id:{eq:$tid}}, state:{type:{nin:["completed","canceled"]}}}, first:25){ nodes{ identifier title state{name} url } } }' '{"tid":"'$NSIMON_TEAM'"}' | jq
# Create an issue in nSimon (default team)
linear_q 'mutation($i:IssueCreateInput!){ issueCreate(input:$i){ success issue{ identifier url } } }' \
'{"i":{"teamId":"'$NSIMON_TEAM'","title":"Fix flaky test","description":"Repro steps…","priority":2}}' | jq
# Add a comment
linear_q 'mutation($i:CommentCreateInput!){ commentCreate(input:$i){ success comment{ id url } } }' \
'{"i":{"issueId":"<issue-uuid>","body":"Update: deployed v1.2.3"}}' | jq
# Update title / state / assignee
linear_q 'mutation($id:String!,$i:IssueUpdateInput!){ issueUpdate(id:$id, input:$i){ success } }' \
'{"id":"<issue-uuid>","i":{"stateId":"<state-uuid>","assigneeId":"<user-uuid>"}}' | jq
# --- Trusk workspace queries ---
# For trusk-specific work, set LINEAR_KEY=$LINEAR_KEY_TRUSK before queries
Notes:
issueUpdate and commentCreate need the issue's UUID, not its identifier (NSI-42). Resolve issue(id:"NSI-42"){ id } first when needed.priority: 0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low.state types: triage, backlog, unstarted, started, completed, canceled.viewer.assignedIssues filtered by priority:{lte:2}, then issueUpdate to bump state to "In Progress".cycle for the nSimon team, list backlog issues, batch-create assignments.commentCreate with the latest status.team.labels.nodes, then issueUpdate with labelIds:[…].$LINEAR_KEY_TRUSK and use the trusk team IDs (e.g. IN, EXTERN).401: LINEAR_KEY empty/invalid — verify with the viewer query at the top.400 / GraphQL errors: read the errors[].message in the response — usually a missing required field or wrong UUID vs identifier.databases
Query today's Immich "on this day" memories and print a summary picoclaw can relay. Use when the user asks about Immich memories, on-this-day, or a recap of past photos from today's date.
documentation
Promote items from Wiki/Inbox into curated Wiki/Pages, merging or creating as Wiki/Schema dictates
development
Audit the LLM Wiki for orphans, broken links, duplicates, and stale facts; write a report page
documentation
Drop a URL or pasted note into the LLM Wiki Inbox in AFFiNE