Зачем консольным утилитам свой аналог OpenAPI и как устроен проект Usage

25 авг 2026
935
51
3
2 недели

Каждый раз, когда я пишу небольшую консольную утилиту, история повторяется. Сначала ты набрасываешь аргументы и флаги в коде. Потом решаешь добавить автодополнение для bash и zsh, лезешь вспоминать синтаксис shell-скриптов или ищешь генераторы. Следом надо оформить документацию в Markdown, обновить man-страницы и не забыть поддержать переменные окружения. Если проект переписывается на другой язык или обрастает обертками на Python или Bash, всю структуру аргументов приходится дублировать вручную.

Разработчик jdx, известный по популярному версионному менеджеру mise, подошел к этой рутине системно и создал проект Usage.

Контракт вместо разрозненных костылей

Основная мысль Usage простая: консольному софту нужен свой аналог OpenAPI или Swagger. Вместо того чтобы привязывать описание аргументов к конкретной библиотеке конкретного языка, Usage предлагает единую переносимую спецификацию в формате KDL.

KDL здесь выбран не случайно. Этот документный язык чище и нагляднее JSON или YAML, в нем удобно описывать вложенные команды, флаги, короткие алиасы и типы данных.

Один раз описав интерфейс утилиты в таком формате, вы закрываете сразу несколько задач:

Реклама
  • Генерация скриптов автодополнения для всех популярных командных оболочек.
  • Автоматическая сборка документации в Markdown и man-страниц.
  • Парсинг аргументов из скриптов на других языках.
  • Скаффолдинг кода под разные CLI-библиотеки.

Как это выглядит в Rust

Если вы пишете на Rust, писать KDL-манифест руками вообще не обязательно. В проекте есть крейт usage-rs, который генерирует спеку прямо из структуры данных через derive-макросы.

Вот так выглядит базовый пример:

[dependencies]
usage = { package = "usage-rs", version = "6" }
use usage::Cli;

#[derive(Cli)]
#[usage(bin = "example", version)]
struct App {
    /// Print more detail.
    #[usage(short = 'v', long, count)]
    verbose: u8,

    /// Files to process.
    files: Vec<String>,
}

fn main() {
    let app = App::parse();
    // app.verbose и app.files готовы к работе
}

Парсер на этапе выполнения не тянет за собой лишних тяжелых зависимостей. При этом из этой же структуры можно сразу экспортировать готовую KDL-спецификацию и использовать ее во внешней инфраструктуре сборки или в CI/CD пайплайнах.

Отличия от привычного clap

Большинство Rust-разработчиков привыкли использовать clap. Автор Usage прямо признает влияние этой библиотеки и сохранил похожий формат вывода справок и сообщений об ошибках, чтобы переход был максимально безболезненным.

Разница кроется в философии. clap ориентирован строго на Rust-экосистему. usage выносит саму схему интерфейса на уровень выше, превращая ее в универсальный контракт. Вы можете взять спеку и распарсить аргументы в Bash-скрипте через CLI-утилиту usage, не переписывая логику валидации флагов.

Среди спонсоров проекта уже числятся такие компании, как 37signals. Это показывает интерес индустрии к унификации терминальных интерфейсов.

Кому проект пригодится прямо сейчас

Usage вряд ли нужен для одноразового скрипта на двадцать строк. Однако инструмент отлично вписывается в разработку сложных внутренних утилит компании, CLI-клиентов для API и платформенных инструментов, которыми пользуются разные команды.

Если вы устали вручную синхронизировать документацию к флагам и писать скрипты автокомплита под каждую оболочку, к проекту определенно имеет смысл присмотреться. Документация и руководства по миграции доступны на официальном сайте usage.jdx.dev.

🍪 Мы используем файлы cookie и сервис аналитики Яндекс.Метрика, чтобы сайт работал лучше. Продолжая пользоваться devtrends.ru, вы соглашаетесь с обработкой данных согласно Политике конфиденциальности.