Skip to content

Рабочий процесс OPSX

Приветствуется обратная связь в Discord.

Что это такое?

OPSX теперь является стандартным рабочим процессом для OpenSpec.

Это гибкий итеративный процесс для внесения изменений в OpenSpec. Больше никаких жестких этапов — только действия, которые вы можете выполнять в любое время.

Почему это существует

Рабочий процесс унаследованного OpenSpec работает, но он жёстко ограничен:

  • Инструкции зашиты в код — спрятаны в TypeScript, вы не можете их изменить
  • Всё или ничего — одна большая команда создаёт всё сразу, невозможно тестировать отдельные части
  • Фиксированная структура — один и тот же рабочий процесс для всех, без возможности настройки
  • Чёрный ящик — когда результат ИИ неудовлетворительный, вы не можете подправить промпты

OPSX открывает его. Теперь любой может:

  1. Экспериментировать с инструкциями — редактировать шаблон, проверять, станет ли ИИ работать лучше
  2. Тестировать поэтапно — проверять инструкции для каждого артефакта независимо
  3. Настраивать рабочие процессы — определять свои артефакты и зависимости
  4. Быстро итерировать — менять шаблон, тестировать сразу, без пересборки
Унаследованный рабочий процесс:          OPSX:
┌────────────────────────┐           ┌────────────────────────┐
│  Зашито в пакете       │           │  schema.yaml           │◄── Вы редактируете это
│  (нельзя изменить)     │           │  templates/*.md        │◄── Или это
│        ↓               │           │        ↓               │
│  Ожидание нового       │           │  Мгновенный эффект     │
│  релиза                │           │        ↓               │
│        ↓               │           │  Тестируете сами       │
│  Надежда на улучшение  │           │                       │
└────────────────────────┘           └────────────────────────┘

Это для всех:

  • Команды — создавайте рабочие процессы, соответствующие вашему реальному способу работы
  • Продвинутые пользователи — настраивайте промпты для получения лучших результатов ИИ для вашей кодовой базы
  • Контрибьюторы OpenSpec — экспериментируйте с новыми подходами без необходимости релизов

Мы все ещё учимся, что работает лучше всего. OPSX позволяет нам учиться вместе.

Пользовательский опыт

Проблема линейных рабочих процессов: Вы «в фазе планирования», затем «в фазе реализации», затем «готово». Но реальная работа так не устроена. Вы реализуете что-то, понимаете, что дизайн был неверным, нужно обновить спецификации, продолжить реализацию. Линейные фазы противоречат тому, как работа на самом деле происходит.

Подход OPSX:

  • Действия, а не фазы — создание, реализация, обновление, архивация — выполняйте любое из них в любое время
  • Зависимости — это возможности — они показывают, что возможно, а не что является обязательным следующим шагом
  proposal ──→ specs ──→ design ──→ tasks ──→ implement

Установка

bash
# Убедитесь, что у вас установлен openspec — навыки генерируются автоматически
openspec init

Это создаёт навыки в .claude/skills/ (или эквивалентной директории), которые ИИ-ассистенты для кодирования автоматически обнаруживают.

По умолчанию OpenSpec использует профиль рабочего процесса core (propose, explore, apply, archive). Если вы хотите расширенные команды рабочего процесса (new, continue, ff, verify, sync, bulk-archive, onboard), настройте их с помощью openspec config profile и примените через openspec update.

Во время установки вам будет предложено создать конфигурацию проекта (openspec/config.yaml). Это необязательно, но рекомендуется.

Конфигурация проекта

Конфигурация проекта позволяет установить значения по умолчанию и внедрить контекст проекта во все артефакты.

Создание конфигурации

Конфигурация создаётся во время openspec init или вручную:

yaml
# openspec/config.yaml
schema: spec-driven

context: |
  Технологический стек: TypeScript, React, Node.js
  Соглашения API: RESTful, JSON-ответы
  Тестирование: Vitest для модульных тестов, Playwright для e2e
  Стиль: ESLint с Prettier, строгий TypeScript

rules:
  proposal:
    - Включить план отката
    - Определить затронутые команды
  specs:
    - Использовать формат Given/When/Then для сценариев
  design:
    - Включить диаграммы последовательности для сложных процессов

Поля конфигурации

ПолеТипОписание
schemaстрокаСхема по умолчанию для новых изменений (например, spec-driven)
contextстрокаКонтекст проекта, внедряемый во все инструкции артефактов
rulesобъектПравила для каждого артефакта, ключи — идентификаторы артефактов

Как это работает

Приоритет схемы (от высшего к низшему):

  1. Флаг CLI (--schema <name>)
  2. Метаданные изменения (.openspec.yaml в директории изменения)
  3. Конфигурация проекта (openspec/config.yaml)
  4. Значение по умолчанию (spec-driven)

Внедрение контекста:

  • Контекст добавляется в начало инструкций каждого артефакта
  • Оборачивается в теги <context>...</context>
  • Помогает ИИ понять соглашения вашего проекта

Внедрение правил:

  • Правила внедряются только для соответствующих артефактов
  • Оборачиваются в теги <rules>...</rules>
  • Появляются после контекста, перед шаблоном

Идентификаторы артефактов по схеме

spec-driven (по умолчанию):

  • proposal — Предложение по изменению
  • specs — Спецификации
  • design — Технический дизайн
  • tasks — Задачи реализации

Валидация конфигурации

  • Неизвестные идентификаторы артефактов в rules генерируют предупреждения
  • Имена схем проверяются по доступным схемам
  • Контекст ограничен размером 50 КБ
  • Невалидный YAML сообщается с указанием номеров строк

Устранение неполадок

"Unknown artifact ID in rules: X"

  • Проверьте, что идентификаторы артефактов соответствуют вашей схеме (см. список выше)
  • Запустите openspec schemas --json, чтобы увидеть идентификаторы артефактов для каждой схемы

Конфигурация не применяется:

  • Убедитесь, что файл находится в openspec/config.yaml (не .yml)
  • Проверьте синтаксис YAML с помощью валидатора
  • Изменения конфигурации вступают в силу немедленно (перезапуск не требуется)

Контекст слишком большой:

  • Контекст ограничен 50 КБ
  • Сократите его или вместо этого дайте ссылку на внешнюю документацию

Команды

КомандаЧто делает
/opsx:proposeСоздаёт изменение и генерирует артефакты планирования за один шаг (путь по умолчанию)
/opsx:exploreОбдумывает идеи, исследует проблемы, уточняет требования
/opsx:newНачинает новый каркас изменения (расширенный рабочий процесс)
/opsx:continueСоздаёт следующий артефакт (расширенный рабочий процесс)
/opsx:ffБыстро создаёт артефакты планирования (расширенный рабочий процесс)
/opsx:applyРеализует задачи, обновляя артефакты по мере необходимости
/opsx:verifyПроверяет реализацию на соответствие артефактам (расширенный рабочий процесс)
/opsx:syncСинхронизирует дельта-спецификации с основными (расширенный рабочий процесс, опционально)
/opsx:archiveАрхивирует при завершении
/opsx:bulk-archiveАрхивирует несколько завершённых изменений (расширенный рабочий процесс)
/opsx:onboardПошаговое руководство по полному изменению от начала до конца (расширенный рабочий процесс)

Использование

Исследование идеи

/opsx:explore

Обдумывайте идеи, исследуйте проблемы, сравнивайте варианты. Структура не требуется — просто помощник для размышлений. Когда идеи кристаллизируются, переходите к /opsx:propose (по умолчанию) или /opsx:new//opsx:ff (расширенный процесс).

Начало нового изменения

/opsx:propose

Создаёт изменение и генерирует артефакты планирования, необходимые перед реализацией.

Если вы включили расширенные рабочие процессы, вместо этого можно использовать:

text
/opsx:new        # только каркас
/opsx:continue   # создание одного артефакта за раз
/opsx:ff         # создание всех артефактов планирования сразу

Создание артефактов

/opsx:continue

Показывает, что можно создать на основе зависимостей, затем создаёт один артефакт. Используйте многократно для постепенного формирования вашего изменения.

/opsx:ff add-dark-mode

Создаёт все артефакты планирования сразу. Используйте, когда у вас есть чёткое представление о том, что вы создаёте.

Реализация (гибкая часть)

/opsx:apply

Работает над задачами, отмечая их выполнение по мере продвижения. Если вы работаете над несколькими изменениями одновременно, можно запустить /opsx:apply <name>; в противном случае он должен определить контекст из диалога и предложить выбор, если не может определить автоматически.

Завершение

/opsx:archive   # Перемещение в архив при завершении (предлагает синхронизировать спецификации при необходимости)

Когда обновлять, а когда начинать заново

Вы всегда можете редактировать ваше предложение или специкации перед реализацией. Но когда уточнение становится «это уже другая работа»?

Что фиксирует предложение

Предложение определяет три вещи:

  1. Намерение — Какую проблему вы решаете?
  2. Объём — Что входит, а что нет?
  3. Подход — Как вы будете это решать?

Вопрос в том: что изменилось и насколько?

Обновляйте существующее изменение, когда:

То же намерение, уточнённая реализация

  • Вы обнаруживаете граничные случаи, которые не учитывали
  • Подход нуждается в корректировке, но цель не изменилась
  • Реализация показывает, что дизайн был немного неверным

Объём сужается

  • Вы понимаете, что полный объём слишком велик, хотите выпустить MVP сначала
  • «Добавить тёмную тему» → «Добавить переключатель тёмной темы (системные предпочтения в v2)»

Корректировки на основе обучения

  • Кодовая база устроена не так, как вы думали
  • Зависимость работает не так, как ожидалось
  • «Использовать CSS-переменные» → «Использовать вместо этого префикс dark: от Tailwind»

Начинайте новое изменение, когда:

Намерение принципиально изменилось

  • Сама проблема теперь другая
  • «Добавить тёмную тему» → «Добавить комплексную систему тем с пользовательскими цветами, шрифтами, отступами»

Объём вырос

  • Изменение выросло настолько, что это по сути другая работа
  • Оригинальное предложение было бы неузнаваемо после обновлений
  • «Исправить баг входа» → «Переписать систему аутентификации»

Оригинальное можно завершить

  • Оригинальное изменение можно пометить как «выполненное»
  • Новая работа самостоятельна, не является уточнением
  • Завершить «Добавить тёмную тему MVP» → Архивировать → Новое изменение «Улучшить тёмную тему»

Эвристики

                        ┌─────────────────────────────────────┐
                        │     Это та же самая работа?         │
                        └──────────────┬──────────────────────┘

                    ┌──────────────────┼──────────────────┐
                    │                  │                  │
                    ▼                  ▼                  ▼
             То же намерение?   >50% пересечения?   Можно ли завершить
             Та же проблема?    Тот же объём?        оригинал без этих
                    │                  │              изменений?
                    │                  │                  │
          ┌────────┴────────┐  ┌──────┴──────┐   ┌───────┴───────┐
          │                 │  │             │   │               │
         ДА               НЕТ ДА           НЕТ  НЕТ             ДА
          │                 │  │             │   │               │
          ▼                 ▼  ▼             ▼   ▼               ▼
       ОБНОВИТЬ         НОВОЕ ОБНОВИТЬ    НОВОЕ ОБНОВИТЬ       НОВОЕ
КритерийОбновитьНовое изменение
Идентичность«То же самое, уточнённое»«Другая работа»
Пересечение объёма>50% пересечения<50% пересечения
ЗавершённостьНельзя завершить без измененийМожно завершить оригинал, новая работа самостоятельна
ИсторияЦепочка обновлений рассказывает связную историюПатчи скорее запутают, чем прояснят

Принцип

Обновление сохраняет контекст. Новое изменение обеспечивает ясность.

Выбирайте обновление, когда история ваших размышлений ценна. Выбирайте новое, когда начать заново будет яснее, чем исправлять.

Думайте об этом как о ветках git:

  • Продолжайте коммитить, пока работаете над одной функцией
  • Начинайте новую ветку, когда это по-настоящему новая работа
  • Иногда мержьте частичную функцию и начинайте заново для второй фазы

Что изменилось?

Устаревший (/openspec:proposal)OPSX (/opsx:*)
СтруктураОдин большой документ предложенияОтдельные артефакты с зависимостями
Рабочий процессЛинейные фазы: план → реализация → архивГибкие действия — делайте что угодно в любое время
ИтерацияСложно вернуться назадОбновляйте артефакты по мере обучения
НастраиваемостьФиксированная структураУправляемая схемами (определяйте свои артефакты)

Ключевой вывод: работа не является линейной. OPSX прекращает делать вид, что это так.

Глубокое погружение в архитектуру

Этот раздел объясняет, как работает OPSX «под капотом», и сравнивает его с унаследованным рабочим процессом. Примеры в этом разделе используют расширенный набор команд (new, continue и т.д.); пользователи по умолчанию (core) могут применить тот же процесс через propose → apply → archive.

Философия: Фазы vs Действия

┌─────────────────────────────────────────────────────────────────────────────┐
│                         УНАСЛЕДОВАННЫЙ РАБОЧИЙ ПРОЦЕСС                      │
│                    (Привязан к фазам, Всё или ничего)                       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌──────────────┐      ┌──────────────┐      ┌──────────────┐             │
│   │    ФАЗА      │      │    ФАЗА      │      │    ФАЗА      │             │
│   │  ПЛАНИРОВАНИЯ│ ───► │ РЕАЛИЗАЦИИ   │ ───► │  АРХИВАЦИИ   │             │
│   └──────────────┘      └──────────────┘      └──────────────┘             │
│         │                     │                     │                       │
│         ▼                     ▼                     ▼                       │
│   /openspec:proposal   /openspec:apply      /openspec:archive              │
│                                                                             │
│   • Создаёт ВСЕ артефакты сразу                                           │
│   • Невозможно вернуться для обновления спецификаций во время реализации   │
│   • Ворота фаз принудительно задают линейное движение                      │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────────────────┐
│                         РАБОЧИЙ ПРОЦЕСС OPSX                                │
│                      (Гибкие действия, Итеративный)                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│              ┌────────────────────────────────────────────┐                 │
│              │        ДЕЙСТВИЯ (не фазы)                  │                 │
│              │                                            │                 │
│              │   new ◄──► continue ◄──► apply ◄──► archive │                 │
│              │    │          │           │           │    │                 │
│              │    └──────────┴───────────┴───────────┘    │                 │
│              │              в любом порядке                │                 │
│              └────────────────────────────────────────────┘                 │
│                                                                             │
│   • Создавайте артефакты по одному ИЛИ делайте быстрое продвижение         │
│   • Обновляйте спецификации/дизайн/задачи во время реализации              │
│   • Зависимости определяют прогресс, фазы не существуют                    │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Компонентная архитектура

Унаследованный рабочий процесс использует жёстко закодированные шаблоны на TypeScript:

┌─────────────────────────────────────────────────────────────────────────────┐
│                 КОМПОНЕНТЫ УНАСЛЕДОВАННОГО РАБОЧЕГО ПРОЦЕССА                │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   Жёстко закодированные шаблоны (строки TypeScript)                         │
│                    │                                                        │
│                    ▼                                                        │
│   Специфичные для инструмента конфигураторы/адаптеры                       │
│                    │                                                        │
│                    ▼                                                        │
│   Сгенерированные файлы команд (.claude/commands/openspec/*.md)            │
│                                                                             │
│   • Фиксированная структура, нет осознания артефактов                      │
│   • Изменения требуют модификации кода + пересборки                         │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

OPSX использует внешние схемы и движок графа зависимостей:

┌─────────────────────────────────────────────────────────────────────────────┐
│                         КОМПОНЕНТЫ OPSX                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   Определения схем (YAML)                                                  │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  name: spec-driven                                                  │   │
│   │  artifacts:                                                         │   │
│   │    - id: proposal                                                   │   │
│   │      generates: proposal.md                                         │   │
│   │      requires: []              ◄── Зависимости                      │   │
│   │    - id: specs                                                      │   │
│   │      generates: specs/**/*.md  ◄── Шаблоны glob                     │   │
│   │      requires: [proposal]      ◄── Разблокируется после proposal   │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                    │                                                        │
│                    ▼                                                        │
│   Движок графа артефактов                                                   │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │  • Топологическая сортировка (порядок зависимостей)                 │   │
│   │  • Определение состояния (существование в файловой системе)         │   │
│   │  • Генерация подробных инструкций (шаблоны + контекст)              │   │
│   └─────────────────────────────────────────────────────────────────────┘   │
│                    │                                                        │
│                    ▼                                                        │
│   Файлы навыков (.claude/skills/openspec-*/SKILL.md)                        │
│                                                                             │
│   • Совместимость с разными редакторами (Claude Code, Cursor, Windsurf)    │
│   • Навыки запрашивают CLI для получения структурированных данных           │
│   • Полностью настраиваемы через файлы схем                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Модель графа зависимостей

Артефакты образуют ориентированный ациклический граф (DAG). Зависимости являются разблокировщиками, а не воротами:

                              proposal
                            (корневой узел)

                    ┌─────────────┴─────────────┐
                    │                           │
                    ▼                           ▼
                 specs                       design
              (требует:                  (требует:
               proposal)                   proposal)
                    │                           │
                    └─────────────┬─────────────┘


                               tasks
                           (требует:
                           specs, design)


                          ┌──────────────┐
                          │    ФАЗА      │
                          │   ПРИМЕНЕНИЯ │
                          │  (требует:   │
                          │    tasks)    │
                          └──────────────┘

Переходы состояний:

   ЗАБЛОКИРОВАНО ────────────────► ГОТОВО ────────────────► ВЫПОЛНЕНО
      │                              │                       │
   Отсутствуют                   Все зависимости         Файл существует
   зависимости                    ВЫПОЛНЕНЫ              в файловой системе

Поток информации

Унаследованный рабочий процесс — агент получает статические инструкции:

  Пользователь: "/openspec:proposal"


  ┌─────────────────────────────────────────┐
  │  Статические инструкции:                │
  │  • Создать proposal.md                  │
  │  • Создать tasks.md                     │
  │  • Создать design.md                    │
  │  • Создать specs/<capability>/spec.md   │
  │                                         │
  │  Нет информации о том, что уже          │
  │  существует или о зависимостях          │
  │  между артефактами                      │
  └─────────────────────────────────────────┘


  Агент создаёт ВСЕ артефакты за один раз

OPSX — агент запрашивает подробный контекст:

  Пользователь: "/opsx:continue"


  ┌──────────────────────────────────────────────────────────────────────────┐
  │  Шаг 1: Запрос текущего состояния                                        │
  │  ┌────────────────────────────────────────────────────────────────────┐  │
  │  │  $ openspec status --change "add-auth" --json                      │  │
  │  │                                                                    │  │
  │  │  {                                                                 │  │
  │  │    "artifacts": [                                                  │  │
  │  │      {"id": "proposal", "status": "done"},                         │  │
  │  │      {"id": "specs", "status": "ready"},      ◄── Первый готовый   │  │
  │  │      {"id": "design", "status": "ready"},                          │  │
  │  │      {"id": "tasks", "status": "blocked", "missingDeps": ["specs"]}│  │
  │  │    ]                                                               │  │
  │  │  }                                                                 │  │
  │  └────────────────────────────────────────────────────────────────────┘  │
  │                                                                          │
  │  Шаг 2: Получение подробных инструкций для готового артефакта            │
  │  ┌────────────────────────────────────────────────────────────────────┐  │
  │  │  $ openspec instructions specs --change "add-auth" --json          │  │
  │  │                                                                    │  │
  │  │  {                                                                 │  │
  │  │    "template": "# Спецификация\n\n## ДОБАВЛЕННЫЕ требования...",   │  │
  │  │    "dependencies": [{"id": "proposal", "path": "...", "done": true}│  │
  │  │    "unlocks": ["tasks"]                                            │  │
  │  │  }                                                                 │  │
  │  └────────────────────────────────────────────────────────────────────┘  │
  │                                                                          │
  │  Шаг 3: Чтение зависимостей → Создание ОДНОГО артефакта → Показ того,   │
  │  что разблокировано                                                      │
  └──────────────────────────────────────────────────────────────────────────┘

Модель итераций

Унаследованный рабочий процесс — неудобно для итераций:

  ┌─────────┐     ┌─────────┐     ┌─────────┐
  │/proposal│ ──► │ /apply  │ ──► │/archive │
  └─────────┘     └─────────┘     └─────────┘
       │               │
       │               ├── "Подождите, дизайн неправильный"
       │               │
       │               ├── Варианты:
       │               │   • Вручную редактировать файлы (нарушает контекст)
       │               │   • Отменить и начать заново
       │               │   • Продолжить и исправить позже
       │               │
       │               └── Нет официального механизма "вернуться назад"

       └── Создаёт ВСЕ артефакты сразу

OPSX — естественные итерации:

  /opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive
      │                │                  │
      │                │                  ├── "Дизайн неправильный"
      │                │                  │
      │                │                  ▼
      │                │            Просто отредактируйте design.md
      │                │            и продолжайте!
      │                │                  │
      │                │                  ▼
      │                │         /opsx:apply продолжает
      │                │         с того места, где вы остановились
      │                │
      │                └── Создаёт ОДИН артефакт, показывает, что разблокировано

      └── Создаёт каркас изменения, ожидает указаний

Пользовательские схемы

Создавайте пользовательские рабочие процессы с помощью команд управления схемами:

bash
# Создать новую схему с нуля (интерактивно)
openspec schema init my-workflow

# Или создать форк существующей схемы как основу
openspec schema fork spec-driven my-workflow

# Проверить структуру вашей схемы
openspec schema validate my-workflow

# Посмотреть, откуда разрешается схема (полезно для отладки)
openspec schema which my-workflow

Схемы хранятся в openspec/schemas/ (локально для проекта, контролируется версиями) или ~/.local/share/openspec/schemas/ (глобально для пользователя).

Структура схемы:

openspec/schemas/research-first/
├── schema.yaml
└── templates/
    ├── research.md
    ├── proposal.md
    └── tasks.md

Пример schema.yaml:

yaml
name: research-first
artifacts:
  - id: research        # Добавлено перед proposal
    generates: research.md
    requires: []

  - id: proposal
    generates: proposal.md
    requires: [research]  # Теперь зависит от research

  - id: tasks
    generates: tasks.md
    requires: [proposal]

Граф зависимостей:

   research ──► proposal ──► tasks

Резюме

АспектУнаследованныйOPSX
ШаблоныЖёстко закодированные TypeScriptВнешние YAML + Markdown
ЗависимостиНет (все сразу)DAG с топологической сортировкой
СостояниеМентальная модель, основанная на фазахСуществование в файловой системе
НастраиваемостьРедактирование исходников, пересборкаСоздание schema.yaml
ИтерацииПривязаны к фазамГибкие, редактируйте что угодно
Поддержка редакторовСпецифичные для инструмента конфигураторы/адаптерыЕдиная директория навыков

Схемы

Схемы определяют, какие артефакты существуют и их зависимости. В настоящее время доступны:

  • spec-driven (по умолчанию): proposal → specs → design → tasks
bash
# Вывести список доступных схем
openspec schemas

# Показать все схемы с их источниками разрешения
openspec schema which --all

# Создать новую схему интерактивно
openspec schema init my-workflow

# Разветвить существующую схему для настройки
openspec schema fork spec-driven my-workflow

# Проверить структуру схемы перед использованием
openspec schema validate my-workflow

Советы

  • Используйте /opsx:explore, чтобы обдумать идею перед тем, как приступить к изменению.
  • /opsx:ff — когда вы точно знаете, что хотите сделать, /opsx:continue — при исследовании.
  • Во время /opsx:apply, если что-то не так — исправьте артефакт, а затем продолжите.
  • Прогресс задач отслеживается с помощью флажков в tasks.md.
  • В любой момент можно проверить статус: openspec status --change "name".

Обратная связь

Это черновая версия. Это сделано намеренно — мы учимся тому, что работает.

Нашли ошибку? Есть идеи? Присоединяйтесь к нам в Discord или создайте issue на GitHub.