关于 linear-api
用于通过 Linear GraphQL API 查询和管理工作的技能,涵盖问题搜索、筛选、创建、更新和评论,并提供列表脚本及项目发现方法。
主要功能
- 01搜索和读取问题
- 02筛选并分页列出问题
- 03创建和更新问题
- 04添加问题评论
- 05发现团队和工作流
适用场景
- 01查找未解决或已分配的工作
- 02创建或更新 Linear 问题
- 03查看项目和团队信息
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ claude-tag-plugins --skill linear-api安装后在 Claude Code 中输入/linear-api确认已加载。
附带文件references/api.mdscripts/linear_issues.sh
详细介绍
Linear 只有一个 GraphQL 端点——没有 REST API。所有读取操作都是 query,所有写入操作都是 mutation,而且都发送到同一个 URL。不要寻找 /api/v1/issues 之类的路径;它们并不存在。
POST https://api.linear.app/graphql
两种 ID 系统并存:
- UUID(
id)——API 在所有查找和变更操作中使用的 ID。 - 标识符(
identifier,例如ENG-123)——UI 中显示的人类可读键。可以通过标识符获取 issue:issue(id: "ENG-123")(Linear 接受这两种 ID)。
请求设置
身份验证由运行时处理——凭据会注入发往此 API 的出站请求,因此无需进行任何设置。不要尝试创建、生成、刷新或验证令牌或密钥。凭据变量仅用于确保请求格式正确;如果某个变量未设置,可将其设为任意占位值。持续出现 401/403 错误表示此工作区未配置凭据——请报告这一情况,而不是排查身份验证问题。
Linear 要求将凭据直接作为值放入 Authorization 标头中,不带 Bearer 前缀——请严格按照以下示例发送标头。
export LINEAR_API_KEY="placeholder" # injected by the runtime; any value works
健全性检查——确认工作区已连通,并查看配置的身份对应的是谁:
curl -sS "https://api.linear.app/graphql" \
-H "Authorization: ${LINEAR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"query": "{ viewer { id name email } }"}' | jq .
每个会话只需定义一次辅助函数,避免重复编写样板代码。它接受一个查询字符串和一个可选的变量 JSON 对象:
linear_gql() {
local query="$1" vars="${2:-null}"
jq -n --arg q "$query" --argjson v "$vars" '{query:$q, variables:$v}' | \
curl -sS "https://api.linear.app/graphql" \
-H "Authorization: ${LINEAR_API_KEY}" \
-H "Content-Type: application/json" \
-d @-
}
务必先检查 .errors,再信任 .data——即使请求失败,GraphQL 仍会返回 HTTP 200:
linear_gql '{ viewer { id } }' | jq 'if .errors then .errors else .data end'
核心操作
1. 我是谁 / 分配给我的任务有哪些
linear_gql '{
viewer {
id name email
assignedIssues(first: 25, orderBy: updatedAt, filter: {state: {type: {nin: ["completed","canceled"]}}}) {
nodes { identifier title state { name type } priority team { key } updatedAt }
}
}
}' | jq '.errors // .data.viewer'
优先级:0 = 无优先级,1 = 紧急,2 = 高,3 = 中,4 = 低。
2. 搜索 issue
linear_gql 'query($q: String!) {
searchIssues(term: $q, first: 25) {
nodes { identifier title state { name } assignee { name } team { key } priority url }
}
}' '{"q": "login crash"}' | jq '.data.searchIssues.nodes'
3. 获取单个 issue(通过标识符或 UUID)
linear_gql 'query($id: String!) {
issue(id: $id) {
id identifier title description url priority estimate
state { name type }
assignee { name email }
creator { name }
team { id key name }
project { id name }
cycle { id number name }
labels { nodes { name color } }
comments(first: 50) { nodes { body user { name } createdAt } }
children { nodes { identifier title state { name } } }
parent { identifier title }
createdAt updatedAt dueDate
}
}' '{"id": "ENG-123"}' | jq '.data.issue'
4. 列出和筛选 issue(scripts/linear_issues.sh)
通过附带的脚本列出 issue(路径相对于此技能的目录):脚本会根据标志构建 IssueFilter,通过 pageInfo.endCursor 分页,检查每个响应中的 .errors,并输出 TSV 或 JSONL。
scripts/linear_issues.sh --team ENG --state-type started --assignee me --limit 100
- 所有筛选标志均为可选项,且会组合使用(AND):
--team KEY、--state NAME、--state-type TYPE(取值为backlog、unstarted、started、completed、canceled、triage、duplicate之一)、--assignee EMAIL(或me——先解析查看者 ID)、--label NAME。实例的具体信息来自上文的LINEAR_API_KEY。 --query TEXT会对标题和描述进行不区分大小写的子字符串匹配;与其他标志组合使用时,会包装为and: [ {…flags}, {or: [title, description]} ]。--limit N限制获取的 issue 总数(默认值为 50,0= 全部);--page-size N(最大值为 100) 设置每页大小;--json会为每个 issue 输出一个 JSON 对象,而非带有标题行的 TSV (字段为identifier、title、state、assignee、updatedAt、url)。行数会输出到 stderr。- 退出代码:
0表示成功;1表示请求失败、GraphQL.errors或参数错误——API 返回的消息和extensions.code会输出到 stderr。
如果脚本报错,请阅读脚本——它只是普通的 curl + jq——并参照 references/api.md 进行调试。
对于标志无法涵盖的筛选器结构——例如 lte/gte 之类的比较运算符、or 分组、嵌套的
some/every——请使用 linear_gql,自行传入 filter 对象:
linear_gql 'query($teamKey: String!) {
issues(first: 50, orderBy: updatedAt, filter: {
team: { key: { eq: $teamKey } }
priority: { lte: 2, gte: 1 }
state: { type: { nin: ["completed", "canceled"] } }
}) { nodes { identifier title priority state { name } assignee { name } } }
}' '{"teamKey": "ENG"}' | jq '.data.issues.nodes'
完整的筛选器语法:references/api.md 的 Filter operators 章节。
5. 创建 issue
需要团队的 UUID(不是团队键)。获取一次即可(示例 8),然后:
linear_gql 'mutation($input: IssueCreateInput!) {
issueCreate(input: $input) {
success
issue { id identifier url }
}
}' '{"input": {
"teamId": "TEAM_UUID",
"title": "Crash on empty input",
"description": "Steps to reproduce…\n\n1. …",
"priority": 2,
"assigneeId": "USER_UUID",
"labelIds": ["LABEL_UUID"]
}}' | jq '.data.issueCreate'
description 是 Markdown。
6. 更新 issue(更改状态、受派人、优先级等)
linear_gql 'mutation($id: String!, $input: IssueUpdateInput!) {
issueUpdate(id: $id, input: $input) {
success
issue { identifier state { name } assignee { name } }
}
}' '{"id": "ENG-123", "input": {"stateId": "STATE_UUID", "priority": 1}}' | jq '.data.issueUpdate'
要将 issue 移至“已完成”/“进行中”等状态,需要工作流的状态 UUID,该 UUID 因团队而异(示例 8 介绍了如何列出状态)。
7. 在 issue 上发表评论
linear_gql 'mutation($input: CommentCreateInput!) {
commentCreate(input: $input) { success comment { id url } }
}' '{"input": {"issueId": "ISSUE_UUID", "body": "Reproduced on main — looking into it."}}' \
| jq '.data.commentCreate'
body 是 Markdown。issueId 必须是 UUID,而不是标识符——请先使用示例 3 获取 UUID。
8. 发现团队、工作流状态、标签和成员
创建/更新 mutation 时需要这些 UUID。
linear_gql '{
teams {
nodes {
id key name
states { nodes { id name type position } }
labels { nodes { id name color } }
members { nodes { id name email } }
}
}
}' | jq '.data.teams.nodes'
状态 type ∈ backlog、unstarted、started、completed、canceled、triage、duplicate。
9. 项目和周期
linear_gql '{
projects(first: 25, orderBy: updatedAt, filter: {status: {type: {neq: "completed"}}}) {
nodes {
id name description progress targetDate url
status { name type }
lead { name }
teams { nodes { key } }
issues(first: 5) { nodes { identifier title state { name } } }
}
}
}' | jq '.data.projects.nodes'
# current cycle for a team
linear_gql 'query($teamId: String!) {
team(id: $teamId) {
activeCycle {
id number name startsAt endsAt progress
issues { nodes { identifier title state { name } assignee { name } } }
}
}
}' '{"teamId": "TEAM_UUID"}' | jq '.data.team.activeCycle'
连接没有 totalCount 字段——要统计问题数量,请对 nodes 分页并计数,或读取 team { issueCount } 之类的聚合字段。例外:搜索载荷(searchIssues、searchProjects、searchDocuments)确实会返回 totalCount。
10. 工作区近期活动
linear_gql '{
issues(first: 25, orderBy: updatedAt) {
nodes { identifier title state { name } assignee { name } team { key } updatedAt }
}
}' | jq '.data.issues.nodes'
分页
每个列表字段(issues、nodes、projects、comments 等)都是使用游标分页的连接。响应包含 pageInfo:
linear_gql 'query($cursor: String) {
issues(first: 50, after: $cursor, orderBy: createdAt) {
pageInfo { hasNextPage endCursor }
nodes { identifier title }
}
}' '{"cursor": null}' | jq '.data.issues'
循环执行:将 pageInfo.endCursor 作为 $cursor 传入,并在 hasNextPage 为 false 时停止。如果响应包含 .errors,或提取的游标为空或字面字符串 null,也应停止并打印响应内容——否则错误封装会导致无限循环。始终为循环设置最大页数限制。first 每页最多为 250 条(默认 50)。反向分页时使用 last / before。
速率限制
Linear 实施每用户请求限制和复杂度限制(大致与查询可能触及的节点数量成正比)。每个响应都包含:
X-RateLimit-Requests-Limit / -Remaining / -Reset
X-Complexity
X-RateLimit-Complexity-Limit / -Remaining / -Reset
API 密钥身份验证每小时可发起 5,000 次请求,获得 3,000,000 个复杂度点(OAuth 应用每位用户每小时可发起 5,000 次请求,获得 2,000,000 个点);单次查询不得超过 10,000 个点。超过限制时,Linear 会返回 HTTP 400(而不是 429),并附带 errors[].extensions.code: "RATELIMITED"。-Reset 标头中的值是 UTC 纪元毫秒——适用于 BSD/macOS 和 GNU date:
sleep $(( reset_ms / 1000 - $(date +%s) + 1 )) # reset_ms from X-RateLimit-Requests-Reset
要降低复杂度,请请求更少的字段、限制 first:,并避免对不需要的连接进行深层嵌套(例如,不要在列表中的每个问题上都选择 comments)。
错误处理
大多数应用程序错误发生时,GraphQL 返回的 HTTP 状态码仍为 200——务必检查响应正文的 errors[]。
- HTTP
400+code: "GRAPHQL_VALIDATION_FAILED"——架构验证失败(字段/类型未知)。errors[].message会指出错误字段——请修正查询,不要排查引号问题。 - HTTP
500+code: "GRAPHQL_VALIDATION_FAILED"——GraphQL 语法错误(括号不匹配等)。errors[].message会显示解析位置。 - HTTP
401——API 密钥无效或缺失。请检查LINEAR_API_KEY。个人密钥应放在Authorization:中,不要加Bearer前缀。 - HTTP
400+code: "RATELIMITED"——触及速率或复杂度限制。等待至X-RateLimit-…-Reset指定的时间(纪元毫秒)后重试;或简化查询(减少字段、缩小first:)。 errors[].extensions.code: "INVALID_INPUT"/"INPUT_ERROR"——验证失败。message会指出错误字段。常见原因:在需要 UUID 的地方传入了键(ENG),或查询超过 10,000 点的复杂度上限。errors[].extensions.code: "ENTITY_NOT_FOUND"——ID 不存在或不可见。请检查 ID。API 密钥的作用范围是整个工作区,但仍受团队/项目访问权限限制。errors[].message: "Cannot query field …"——拼写错误或架构不匹配。字段不存在。请检查拼写;使用内省(references/api.md)。
即使 HTTP 状态和 errors 都正常,mutation 仍会返回 success 布尔值——确认写入前请先检查该值。
深入了解
references/api.md 提供了更完整的目录:所有主要对象类型及其字段、筛选运算符语法、webhook 配置、文件附件、表情回应、通知、收藏项、工作区/组织查询以及架构内省。若需要使用上述内容未涵盖的对象或 mutation,或需要了解创建/更新操作的确切输入格式,请阅读该文档。