mcpField
L
linear

linear

github.com/nousresearch生产力258.9k80 次安装今天更新
代码仓库

关于 linear

面向需要通过 Hermes 操作 Linear 的用户,提供基于 GraphQL API 的命令行和 curl 工作方法。附带无额外依赖的 Python 脚本,可查询和修改 issue、项目及文档。

主要功能

  1. 01查询与搜索 issue
  2. 02创建和更新 issue
  3. 03管理团队、项目与工作流状态
  4. 04检索 Linear 文档
  5. 05提供零依赖 Python 命令行脚本

适用场景

  1. 01查看分配给自己的 issue
  2. 02为团队筛选并更新 issue 状态
  3. 03创建项目或添加 issue 评论
  4. 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 流程,也无需额外依赖。

设置

  1. 从 Linear 设置 > 账户 > 安全与访问 > 个人 API 密钥 获取个人 API 密钥(URL:https://linear.app/settings/account/security)。注意:组织级别的 设置 > API 页面只显示 OAuth 应用和工作区成员密钥,不显示个人密钥。
  2. 在环境中设置 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)。

典型工作流

  1. 查询团队以获取团队 ID 和键
  2. 查询工作流状态以获取目标团队的状态 UUID
  3. 列出或搜索工作项以查找待处理事项
  4. 创建工作项,并填写团队 ID、标题、描述和优先级
  5. 更新状态,将 stateId 设置为目标工作流状态
  6. 添加评论以跟踪进度
  7. 标记为完成,将 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 响应,以提高可读性

评论

支持 Markdown