欢迎回来

登录 EAKE AI,继续您的智能之旅

忘记密码?
还没有账号?立即注册

Linear 项目管理

2026-05-20 · Skills中心

# Linear — 问题与项目管理

通过 GraphQL API 直接使用 curl 管理 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
  • UUID 和短标识符(如 ENG-123)都可用于 issue(id:)

基础 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,本技能附带一个位于 scripts/linear_api.py 的标准库 Python CLI。零依赖。认证方式相同(读取 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 } }'

所有子命令:whoamilist-teamslist-projectslist-stateslist-issuesget-issuesearch-issuescreate-issueupdate-issueupdate-statusadd-commentlist-documentsget-documentsearch-documentsraw。运行 --help 查看参数。

什么时候用脚本:你想要快速答案而不想手写 GraphQL。什么时候用 curl:你需要脚本未封装的查询,或想内联组合过滤器。

工作流状态

Linear 使用带 type 字段的 WorkflowState 对象。6 种状态类型:

| 类型 | 说明 |

|------|-------------|

| triage | 需要评审的入站问题 |

| backlog | 已确认但尚未规划 |

| unstarted | 已规划/就绪但未开始 |

| started | 正在积极处理 |

| completed | 已完成 |

| canceled | 不做了 |

每个团队都有自己的命名状态(例如「In Progress」的类型是 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: "user@example.com" } } }, 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

常用变更(Mutations)

创建问题


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

文档(Documents)

Linear 文档是与问题存放在一起的散文式文档(RFC、规格、笔记)。它们有自己的 documents 根查询和 document(id:) 单条获取。

文档 URL 与 `slugId`

文档 URL 形如:


https://linear.app//document/-

末尾的十六进制段就是 slugId。示例:https://linear.app/nousresearch/document/rfc-hermes-permission-gateway-discord-38359beef67cslugId38359beef67c

重要的 schema 细节: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 的 schema 没有 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 限制结果数。

过滤参考

比较器:eqneqinninltltegtgtecontainsstartsWithcontainsIgnoreCase

or: [...] 组合过滤器实现 OR 逻辑(过滤器对象内部默认是 AND)。

典型工作流

  1. 查询团队,获取团队 ID 和 key
  2. 查询工作流状态,获取目标团队的状态 UUID
  3. 列出或搜索问题,找到需要处理的内容
  4. 创建问题,带上团队 ID、标题、描述、优先级
  5. 更新状态,把 `stateId` 设为目标工作流状态
  6. 添加评论,跟踪进度
  7. 标记完成,把 `stateId` 设为团队类型为「completed」的状态

速率限制

  • 每个 API 密钥每小时 5,000 次请求
  • 每小时 3,000,000 复杂度点
  • 使用 first: N 限制结果数,降低复杂度成本
  • 监控 X-RateLimit-Requests-Remaining 响应头

重要提示

  • API 调用始终使用 terminal 工具 + curl——不要用 web_extractbrowser
  • 始终检查 GraphQL 响应中的 errors 数组——HTTP 200 也可能包含错误
  • 创建问题时如果省略 stateId,Linear 默认为第一个 backlog 状态
  • description 字段支持 Markdown
  • python3 -m json.tooljq 格式化 JSON 响应以便阅读

评论区

发表评论