关于 linear
面向需要通过 Hermes 操作 Linear 的用户,提供基于 GraphQL API 的命令行和 curl 工作方法。附带无额外依赖的 Python 脚本,可查询和修改 issue、项目及文档。
主要功能
- 01查询与搜索 issue
- 02创建和更新 issue
- 03管理团队、项目与工作流状态
- 04检索 Linear 文档
- 05提供零依赖 Python 命令行脚本
适用场景
- 01查看分配给自己的 issue
- 02为团队筛选并更新 issue 状态
- 03创建项目或添加 issue 评论
- 04按标题或 slugId 查找文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nousresearch/ hermes-agent --skill linear安装后在 Claude Code 中输入/linear确认已加载。
附带文件scripts/linear_api.py
详细介绍
Linear — 问题与项目管理
通过 curl 使用 GraphQL API,直接管理 Linear 问题、项目和团队。无需 MCP 服务,无需 OAuth 流程,也无需额外依赖。
设置
- 从 Linear 设置 > 账户 > 安全与访问 > 个人 API 密钥 获取个人 API 密钥(URL:https://linear.app/settings/account/security)。注意:组织级别的 设置 > API 页面只显示 OAuth 应用和工作区成员密钥,不显示个人密钥。
- 在环境中设置
LINEAR_API_KEY(通过hermes setup或环境配置)
API 基础知识
- 端点:
https://api.linear.app/graphql(POST) - 身份验证标头:
Authorization: $LINEAR_API_KEY(API 密钥不需要 "Bearer" 前缀) - 所有请求均使用 POST,并带有
Content-Type: application/json issue(id:)同时支持 UUID 和短标识符(例如ENG-123)
基础 curl 模式:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ viewer { id name } }"}' | python3 -m json.tool
Python 辅助脚本(便捷替代方案)
对于不需要手写 GraphQL 的快捷单行命令,此技能提供了一个使用 Python 标准库的 CLI,路径为 scripts/linear_api.py。零依赖。身份验证方式相同(读取 LINEAR_API_KEY)。
SCRIPT=$(dirname "$(find ~/.hermes -path '*skills/productivity/linear/scripts/linear_api.py' 2>/dev/null | head -1)")/linear_api.py
python3 "$SCRIPT" whoami
python3 "$SCRIPT" list-teams
python3 "$SCRIPT" get-issue ENG-42
python3 "$SCRIPT" get-document 38359beef67c # fetch a doc by slugId from the URL
python3 "$SCRIPT" raw 'query { viewer { name } }'
所有子命令:whoami、list-teams、list-projects、list-states、list-issues、get-issue、search-issues、create-issue、update-issue、update-status、add-comment、list-documents、get-document、search-documents、raw。运行时添加 --help 可查看标志。
适合使用脚本的情况:想快速获取答案,无需编写 GraphQL。适合使用 curl 的情况:需要执行脚本未封装的查询,或想直接组合筛选条件。
工作流状态
Linear 使用带有 type 字段的 WorkflowState 对象。共有 6 种状态类型:
| 类型 | 描述 |
|---|---|
triage | 等待审核的新问题 |
backlog | 已确认但尚未规划 |
unstarted | 已规划/准备就绪,但尚未开始 |
started | 正在积极处理 |
completed | 已完成 |
canceled | 不会处理 |
每个团队都有自己的命名状态(例如,“进行中”属于 started 类型)。要更改问题的状态,需要目标状态的 stateId(UUID)——请先查询工作流状态。
**优先级值:**0 = 无,1 = 紧急,2 = 高,3 = 中,4 = 低
常用查询
获取当前用户
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ viewer { id name email } }"}' | python3 -m json.tool
列出团队
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ teams { nodes { id name key } } }"}' | python3 -m json.tool
列出团队的工作流状态
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ workflowStates(filter: { team: { key: { eq: \"ENG\" } } }) { nodes { id name type } } }"}' | python3 -m json.tool
列出问题(前 20 个)
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issues(first: 20) { nodes { identifier title priority state { name type } assignee { name } team { key } url } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool
列出分配给我的问题
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ viewer { assignedIssues(first: 25) { nodes { identifier title state { name type } priority url } } } }"}' | python3 -m json.tool
获取单个问题(通过 ENG-123 之类的标识符)
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-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
按文本搜索问题
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issueSearch(query: \"bug login\", first: 10) { nodes { identifier title state { name } assignee { name } url } } }"}' | python3 -m json.tool
按状态类型筛选问题
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issues(filter: { state: { type: { in: [\"started\"] } } }, first: 20) { nodes { identifier title state { name } assignee { name } } } }"}' | python3 -m json.tool
按团队和受分配者筛选
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-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
列出项目
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ projects(first: 20) { nodes { id name description progress lead { name } teams { nodes { key } } url } } }"}' | python3 -m json.tool
列出团队成员
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ users { nodes { id name email active } } }"}' | python3 -m json.tool
列出标签
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issueLabels { nodes { id name color } } }"}' | python3 -m json.tool
常用变更操作
创建问题
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id identifier title url } } }",
"variables": {
"input": {
"teamId": "TEAM_UUID",
"title": "Fix login bug",
"description": "Users cannot login with SSO",
"priority": 2
}
}
}' | python3 -m json.tool
更新问题状态
先从上面的工作流状态查询中获取目标状态 UUID,然后:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { stateId: \"STATE_UUID\" }) { success issue { identifier state { name type } } } }"}' | python3 -m json.tool
分配问题
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { assigneeId: \"USER_UUID\" }) { success issue { identifier assignee { name } } } }"}' | python3 -m json.tool
设置优先级
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { priority: 1 }) { success issue { identifier priority } } }"}' | python3 -m json.tool
添加评论
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { commentCreate(input: { issueId: \"ISSUE_UUID\", body: \"Investigated. Root cause is X.\" }) { success comment { id body } } }"}' | python3 -m json.tool
设置截止日期
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { dueDate: \"2026-04-01\" }) { success issue { identifier dueDate } } }"}' | python3 -m json.tool
为问题添加标签
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-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
将问题添加到项目
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "mutation { issueUpdate(id: \"ENG-123\", input: { projectId: \"PROJECT_UUID\" }) { success issue { identifier project { name } } } }"}' | python3 -m json.tool
创建项目
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($input: ProjectCreateInput!) { projectCreate(input: $input) { success project { id name url } } }",
"variables": {
"input": {
"name": "Q2 Auth Overhaul",
"description": "Replace legacy auth with OAuth2 and PKCE",
"teamIds": ["TEAM_UUID"]
}
}
}' | python3 -m json.tool
文档
Linear 文档是与问题一同存储的文本资料(RFC、规范、笔记)。它们有自己的 documents 根查询和用于获取单个文档的 document(id:) 查询。
文档 URL 和 slugId
文档 URL 如下:
https://linear.app/<workspace>/document/<slug>-<hexSlugId>
末尾的十六进制片段就是 slugId。示例:https://linear.app/nousresearch/document/rfc-hermes-permission-gateway-discord-38359beef67c → slugId 为 38359beef67c。
**重要的架构细节:**Markdown 正文位于 content 字段中。ProseMirror JSON 位于 contentState(不是 contentData——该字段不存在,API 会返回 400)。
通过 slugId 获取文档
document(id:) 只接受 UUID。要通过 URL 中的十六进制 slug 获取文档,请筛选集合:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "query($s: String!) { documents(filter: { slugId: { eq: $s } }, first: 1) { nodes { id title content contentState slugId url creator { name } project { name } updatedAt } } }", "variables": {"s": "38359beef67c"}}' \
| python3 -m json.tool
也可以通过 Python 辅助脚本:
python3 scripts/linear_api.py get-document 38359beef67c
通过 UUID 获取文档
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ document(id: \"11700cff-b514-4db3-afcc-3ed1afacba1c\") { title content url } }"}' \
| python3 -m json.tool
列出最近的文档
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ documents(first: 25, orderBy: updatedAt) { nodes { id title slugId url updatedAt project { name } } } }"}' \
| python3 -m json.tool
按标题搜索文档
Linear 的架构中没有 searchDocuments 根字段。请改用标题子字符串筛选器:
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ documents(filter: { title: { containsIgnoreCase: \"RFC\" } }, first: 25) { nodes { title slugId url } } }"}' \
| python3 -m json.tool
分页
Linear 使用 Relay 风格的游标分页:
# First page
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issues(first: 20) { nodes { identifier title } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool
# Next page — use endCursor from previous response
curl -s -X POST https://api.linear.app/graphql \
-H "Authorization: $LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ issues(first: 20, after: \"CURSOR_FROM_PREVIOUS\") { nodes { identifier title } pageInfo { hasNextPage endCursor } } }"}' | python3 -m json.tool
默认页面大小:50。最大值:250。始终使用 first: N 限制结果数量。
筛选参考
比较运算符:eq、neq、in、nin、lt、lte、gt、gte、contains、startsWith、containsIgnoreCase
使用 or: [...] 组合筛选器以实现 OR 逻辑(筛选对象内默认使用 AND)。
典型工作流
- 查询团队以获取团队 ID 和键
- 查询工作流状态以获取目标团队的状态 UUID
- 列出或搜索工作项以查找待处理事项
- 创建工作项,并填写团队 ID、标题、描述和优先级
- 更新状态,将
stateId设置为目标工作流状态 - 添加评论以跟踪进度
- 标记为完成,将
stateId设置为该团队类型为“已完成”的状态
速率限制
- 每个 API 密钥每小时 5,000 个请求
- 每小时 3,000,000 个复杂度点
- 使用
first: N限制结果数量并降低复杂度消耗 - 监控
X-RateLimit-Requests-Remaining响应标头
重要说明
- 始终使用
terminal工具搭配curl调用 API——不要使用web_extract或browser - 始终检查 GraphQL 响应中的
errors数组——即使 HTTP 状态码为 200,响应仍可能包含错误 - 创建工作项时,如果省略
stateId,Linear 会默认使用第一个待办状态 description字段支持 Markdown- 使用
python3 -m json.tool或jq格式化 JSON 响应,以提高可读性