linear について
Hermes から Linear を操作するユーザー向けのスキルです。GraphQL API の curl 例と、依存関係のない Python CLI で、issue、プロジェクト、ドキュメントを検索・変更できます。
主な機能
- 01issue の検索と照会
- 02issue の作成と更新
- 03チーム、プロジェクト、ワークフロー状態の管理
- 04Linear ドキュメントの取得
- 05依存関係のない Python CLI
活用シーン
- 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 Settings > Account > Security & access > Personal API keys から個人用 API キーを取得します(URL:https://linear.app/settings/account/security)。注:組織レベルの Settings > 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 | 対応しない |
各チームには、それぞれ名前付きの状態があります(例:「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
1 件のイシューを取得(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>
末尾の 16 進数の部分が 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 の 16 進数のスラッグで取得するには、コレクションをフィルタリングします。
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 キーごとに 1 時間あたり 5,000 リクエスト
- 1 時間あたり 3,000,000 複雑度ポイント
- 結果を制限して複雑度コストを削減するには、
first: Nを使用してください - レスポンスヘッダー
X-RateLimit-Requests-Remainingを監視してください
重要な注意事項
- API 呼び出しには、必ず
curlを使うterminalツールを使用してください。web_extractやbrowserは使用しないでください - GraphQL のレスポンスでは、必ず
errors配列を確認してください。HTTP 200 でもエラーが含まれている場合があります - 課題の作成時に
stateIdを省略すると、Linear は最初のバックログ状態をデフォルトとして設定します descriptionフィールドは Markdown に対応しています- 読みやすく JSON レスポンスを整形するには、
python3 -m json.toolまたはjqを使用してください