On this page Linear: управление задачами, проектами и командами через GraphQL + curl.
Метаданные навыка¶
| |
|---|---|
|Источник| Встроенный (установлен по умолчанию) |
|Путь| skills/productivity/linear |
|Версия| 1.0.0 |
|Автор| Hermes Agent |
|Лицензия| MIT |
|Теги| Linear, Project Management, Issues, GraphQL, API, Productivity |
Справочная информация: полный SKILL.md¶
info Далее приведено полное определение навыка, которое Hermes загружает при активации этого навыка. Агент видит эти инструкции, когда навык активен.
Linear — Управление задачами и проектами¶
Управляйте задачами, проектами и командами Linear напрямую через GraphQL API с помощью curl. Никакого MCP-сервера, OAuth-потока или дополнительных зависимостей.
Настройка¶
- Получите личный API-ключ в Linear Settings > Account > Security & access > Personal API keys (URL: https://linear.app/settings/account/security). Примечание: страница Settings > API на уровне организации показывает только OAuth-приложения и ключи участников рабочего пространства, а не личные ключи.
- Установите
LINEAR_API_KEYв вашем окружении (черезhermes setupили в конфигурации окружения).
Основы API¶
- Endpoint:
https://api.linear.app/graphql(POST) - Заголовок авторизации:
Authorization: $LINEAR_API_KEY(префикс \"Bearer\" для API-ключей не требуется) - Все запросы — POST с
Content-Type: application/json - UUID и короткие идентификаторы (например,
ENG-123) работают сissue(id:)
Базовый шаблон curl: [code] 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
[/code]
Python-скрипт-помощник (эргономичная альтернатива)¶
Для быстрых однострочных команд, не требующих написания GraphQL вручную, в состав навыка входит CLI на Python из стандартной библиотеки по пути scripts/linear_api.py. Без дополнительных зависимостей. Использует ту же авторизацию (читает LINEAR_API_KEY).
[code]
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 # получить документ по slugId из URL
python3 "$SCRIPT" raw 'query { viewer { name } }'
[/code]
Все подкоманды: 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 использует объекты WorkflowState с полем type. 6 типов состояний:
| Тип | Описание |
|---|---|
| triage | Входящие задачи, требующие рассмотрения |
| backlog | Подтверждённые, но ещё не запланированные |
| unstarted | Запланированные/готовые, но не начатые |
| started | Активно выполняемые |
| completed | Завершённые |
| canceled | Не будут выполняться |
У каждой команды есть собственные именованные состояния (например, «In Progress» имеет тип started). Чтобы изменить статус задачи, нужен stateId (UUID) целевого состояния — сначала запросите состояния рабочего процесса.
Значения приоритета: 0 = Нет, 1 = Срочно, 2 = Высокий, 3 = Средний, 4 = Низкий
Часто используемые запросы¶
Получить текущего пользователя¶
[code] 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
[/code]
Список команд¶
[code] 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
[/code]
Список состояний рабочего процесса для команды¶
[code] 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
[/code]
Список задач (первые 20)¶
[code] 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
[/code]
Список моих назначенных задач¶
[code] 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
[/code]
Получить одну задачу (по идентификатору, например ENG-123)¶
[code] 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
[/code]
Поиск задач по тексту¶
[code] 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
[/code]
Фильтрация задач по типу состояния¶
[code] 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
[/code]
Фильтрация по команде и исполнителю¶
[code] 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
[/code]
Список проектов¶
[code] 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
[/code]
Список участников команды¶
[code] 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
[/code]
Список меток¶
[code] 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
[/code]
Часто используемые мутации¶
Создать задачу¶
[code] 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
[/code]
Обновить статус задачи¶
Сначала получите UUID целевого состояния из запроса состояний рабочего процесса выше, затем: [code] 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
[/code]
Назначить задачу¶
[code] 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
[/code]
Установить приоритет¶
[code] 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
[/code]
Добавить комментарий¶
[code] 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
[/code]
Установить срок выполнения¶
[code] 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
[/code]
Добавить метки к задаче¶
[code] 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
[/code]
Добавить задачу в проект¶
[code] 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
[/code]
Создать проект¶
[code] 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
[/code]
Документы¶
Документы Linear — это текстовые документы (RFC, спецификации, заметки), хранящиеся вместе с задачами. У них есть собственный корневой запрос documents и единичная выборка document(id:).
URL-адреса документов и slugId¶
URL-адреса документов выглядят так:
[code]
https://linear.app/
[/code]
Завершающий шестнадцатеричный сегмент — это slugId. Пример: https://linear.app/nousresearch/document/rfc-hermes-permission-gateway-discord-38359beef67c → slugId равен 38359beef67c.
Важная деталь схемы: тело в Markdown находится в поле content. JSON в формате ProseMirror находится в contentState (не contentData — это поле не существует, и API вернёт 400).
Получить документ по slugId¶
document(id:) принимает только UUID. Чтобы получить документ по шестнадцатеричному slug из URL, отфильтруйте коллекцию:
[code]
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
[/code] Или через Python-помощник: [code] python3 scripts/linear_api.py get-document 38359beef67c
[/code]
Получить документ по UUID¶
[code] 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
[/code]
Список недавних документов¶
[code] 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
[/code]
Поиск документов по названию¶
В схеме Linear нет корневого запроса searchDocuments. Вместо этого используйте фильтр по подстроке названия:
[code]
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
[/code]
Пагинация¶
Linear использует курсорную пагинацию в стиле Relay: [code] # Первая страница 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
# Следующая страница — используйте endCursor из предыдущего ответа
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
[/code]
Размер страницы по умолчанию: 50. Максимум: 250. Всегда используйте first: N для ограничения результатов.
Справочник по фильтрации¶
Компараторы: eq, neq, in, nin, lt, lte, gt, gte, contains, startsWith, containsIgnoreCase
Комбинируйте фильтры с or: [...] для логики ИЛИ (по умолчанию внутри объекта фильтра применяется И).
Типичный рабочий процесс¶
- Запросить команды, чтобы получить ID команд и ключи
- Запросить состояния рабочего процесса для целевой команды, чтобы получить UUID состояний
- Вывести список или выполнить поиск задач, чтобы найти то, что требует работы
- Создать задачи с ID команды, заголовком, описанием, приоритетом
- Обновить статус, установив
stateIdв целевое состояние рабочего процесса - Добавить комментарии для отслеживания прогресса
- Отметить как выполненное, установив
stateIdв состояние типа «completed» команды
Лимиты запросов¶
- 5 000 запросов/час на один API-ключ
- 3 000 000 единиц сложности/час
- Используйте
first: Nдля ограничения результатов и снижения стоимости сложности - Следите за заголовком ответа
X-RateLimit-Requests-Remaining
Важные замечания¶
- Всегда используйте инструмент
terminalсcurlдля API-вызовов — НЕ используйтеweb_extractилиbrowser - Всегда проверяйте массив
errorsв ответах GraphQL — HTTP 200 может содержать ошибки - Если
stateIdопущен при создании задач, Linear по умолчанию использует первое состояние backlog - Поле
descriptionподдерживает Markdown -
Используйте
python3 -m json.toolилиjqдля форматирования JSON-ответов в удобочитаемый вид - Справочная информация: полный SKILL.md
- Настройка
- Основы API
- Python-скрипт-помощник (эргономичная альтернатива)
- Состояния рабочего процесса
- Часто используемые запросы
- Получить текущего пользователя
- Список команд
- Список состояний рабочего процесса для команды
- Список задач (первые 20)
- Список моих назначенных задач
- Получить одну задачу (по идентификатору, например ENG-123)
- Поиск задач по тексту
- Фильтрация задач по типу состояния
- Фильтрация по команде и исполнителю
- Список проектов
- Список участников команды
- Список меток
- Часто используемые мутации
- Документы
- Пагинация
- Справочник по фильтрации
- Типичный рабочий процесс
- Лимиты запросов
- Важные замечания