{/ Эта страница автоматически передается из навыков SKILL.md с помощью сайта/scripts/generate-skill-docs.py. Редактируйте исходный SKILL.md, а не эту страницу. /}

Линейный

Линейный: управление задачами, проектами, командами через GraphQL + Curl.

Метаданные навыки

Источник Встроенный (установлен по умолчанию)
Путь навыки/производительность/линейность
Версия 1.0.0
Автор Агент Гермес
Лицензия Массачусетский технологический институт
Платформы Linux, MacOS, Windows
Теги Линейное, Управление проектами, Проблемы, GraphQL, API, Производительность

Справочник: полный SKILL.md:::информация

Ниже приведено полное описание навыков, которые Hermes загружает при его активации. Это то, что агент видит в качестве инструкций, когда навыки активны.

Линейное — Управление задачами и проектами

Управляйте задачами, проектами и командами Linear напрямую через GraphQL API с помощью Curl. Никакого MCP-сервера, OAuth-потока или дополнительных зависимостей.

Настройка

  1. Получите персональный API-ключ в Линейные настройки > Учетная запись > Безопасность и доступ > Персональные ключи API (URL-адрес: https://linear.app/settings/account/security). Примечание: страница Настройки > API на уровне организации показывает только OAuth-приложения и ключи участников рабочего пространства, а не персональные ключи.
  2. Установите LINEAR_API_KEY в вашем решении (через hermes setup или конфигурацию окружения).

Основы API

Базовый шаблон завитка:

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, в этом навыке используется CLI на Python из библиотеки: 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      # получить документ по slugId из 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, сырой. Запустите --help для получения флагов.

Используйте скрипт, когда: нужен быстрый ответ без написания GraphQL. Используйте Curl, когда: нужен запрос, который скрипт не оборачивает, или вы хотите создать фильтры в строке.

Состояния рабочего процесса

Линейное использование объектов WorkflowState с полем type. 6 типов обработки:

Тип Описание
сортировка Входящие задачи, требующие рассмотрения
отставание Приняты, но ещё не запланированы
незапущенный Запланированы/готовы, но не начаты
начал Активно разрабатываются
завершен Завершены
отменено Не будет выполняться

У каждой команды есть свои именованные состояния (например, «Выполняется» — это тип «начато»). Чтобы изменить статус задачи, нужен 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

Часто используются мутации

Создать задачу

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": "Исправить баг входа",
        "description": "Пользователи не могут войти через 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: \"Исследовано. Коренная причина — 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": "Заменить устаревшую аутентификацию на OAuth2 и PKCE",
        "teamIds": ["TEAM_UUID"]
      }
    }
  }' | python3 -m json.tool

Документы

Документы Линейный — это прозаические документы (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-38359beef67cslugId равен 38359beef67c.

Важная деталь схемы: Тело Markdown находится в поле content. ProseMirror JSON находится в contentState (не contentData — такого поля не существует, и API получает 400).

Получить документ по slugId

document(id:) принимает только UUID. Чтобы получить документ по шестнадцатеричному фрагменту URL-адреса, отфильтруйте коллекцию:

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

Пагинация

Линейное использование контекстной пагинации в стиле Relay:

# Первая страница
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

Размер страницы по умолчанию: 50. Максимум: 250. Всегда воспользуйтесь first: N для ограничений результатов.

Справочник по фильтрам

Компараторы: eq, neq, in, nin, lt, lte, gt, gte, contains, startsWith, containsIgnoreCase

Комбинируйте фильтры с or: [...] для логики ИЛИ (по умолчанию внутри объекта используется фильтр И).

Типичный рабочий процесс

  1. Запросить команду, чтобы получить ID и ключи команды.
  2. Запросить процесс рабочего состояния для включения команды, чтобы получить UUID переключения.
  3. Список или поиск задач, чтобы найти то, что нужно сделать.
  4. Создать задачу с идентификатором команды, названием, описанием, приоритетом.
  5. Обновить статус, установив stateId в целевое состояние рабочего процесса.
  6. Добавить изменения для идентификации прогресса.
  7. Отметить как завершённое, установив stateId в состояние типа "завершено" команды.

Лимиты

Важные замечания