У нашей отрасли странные отношения с терминальными и командными интерфейсами. Пришло время их пересмотреть.
В последнее время активно уговаривает друзей попробовать строить нативные пользовательские интерфейсы. Несколько месяцев назад было создано первое серьёзное приложение для Mac, и с тех пор появилось больше нативных UI-штуковин, чем за всю предыдущую карьеру. Вот небольшая экскурсия.

Это MDV.app — лучший просмотрщик Markdown в мире, пока кто-нибудь не напишет действительно серьёзный аналог. Об MDV уже написано немало, повторяться смысла нет. Но программа действительно хороша.
В написании этого UI-кода почти не пришлось участвовать руками. А зачем? Как и большинство пользовательских интерфейсов, MDV не совершает переворота в индустрии — задача не из сложных. Но создавать хороший UI непросто: такой код скучный, повторяющийся, требовательный к деталям и завязан на знание платформенных концепций. Чтобы набить в этом руку, нужны годы. Именно поэтому такую программу никогда не стали бы писать вручную. Вместо этого её просто вызвали к жизни.
Идём дальше:

Последний год ушёл на прохождение Math Academy — от Foundations I до Machine Learning, что можно коротко описать как «самостоятельно выучил матан». Math Academy нравится очень сильно, и о ней есть что сказать отдельно, но здесь это лишь предыстория ещё одного вызванного к жизни SwiftUI-приложения: нативного фронтенда в стиле калькулятора для SageMath — стандартной математической системы для криптографов.
Три главные вещи, которые даёт это приложение: автоматический рендеринг вывода Sage в LaTeX (что становится всё удобнее по мере погружения в многомерный матан), доступ к методам Sage на объектах вроде векторов, матриц и выражений одним кликом (гораздо приятнее, чем набирать trig_simplify снова и снова), и «маленький язык» сокращённых команд для типовых операций вроде «взять градиент этого выражения». [1,2;3,4] в этой системе — это матрица; этого уже достаточно, чтобы оценить идею.
Упаковывать это приложение никто не собирается. Кому нужно — можно сделать скриншот этого раздела и отдать его Claude. Он соберёт что-то полезное. Понятно, к чему всё идёт.

Это DJ Roomba, плеер Apple Music. Карта жанров — сомнительная фича (было бы полезнее, если бы кто-то навёл порядок во всех жанровых метках, часть которых тянется ещё с первых рипов MP3 в 1997 году). А вот что не сомнительно — встроенный LLM-агент с вызовами инструментов для чтения библиотеки, списка последних прослушанных треков и очереди. «Иду в мастерскую в подвале собирать рамку для картины, дай плейлист без провалов под настроение». Оказывается, настроение — это «побольше Курта Вайла и Тома Петти». Без вопросов.
За плеером стоит SQLite-база — вполне разумная, с адекватной схемой, что тоже оказалось неожиданно полезной фичей.
Не совсем понятно, что думать о программах такого рода. Это музыкальный плеер с ИИ-ассистентом, который воспроизводит 90% интерфейса Music.app — вечного личного компьютерного врага номер один. Это персональный компьютерный эквивалент убийства дракона. Но при этом не было написано ни строчки кода. Так это разработка софта или просто настройка компьютера под себя?
Держите эту мысль в голове.

Это персональная LLM-вики. Кто-нибудь должен написать популярный, широко расходящийся материал о том, насколько ценна самоуправляемая вики: скармливаешь ей исходные материалы, задаёшь вопросы — и она сама пишет статьи. Идея на удивление полезная, приятно, что до неё дошли.
Self Driving Wiki.app писалась с удовольствием. В отличие от DJ Roomba, где напрямую встроен клиент Responses API, это приложение под капотом использует claude -p. Из предположения, что агентам удобнее рыться в файловой системе, было вызвано к жизни расширение виртуальной файловой системы macOS, которое отражает содержимое SQLite-базы как read-only смонтированную файловую систему внутри песочницы приложения.
Было ли это, вероятно, излишним? Усложняет ли это установку приложения — например, требуя почему-то запуска именно из /Applications? Да, и ещё раз да. Но именно такие вылазки в яко-шейвинг были главным удовольствием разработки софта в доLLM-эпоху, и приятно осознавать, что это удовольствие всё ещё доступно.

Вот кое-что, что используется постоянно: полуавтоматический трекер пищевых макронутриентов (гипер-респондер на дозе 2.5 без побочек — вещь что надо). Как и многие, здесь тоже сидят на тирзепатиде. Приложение — ещё один простой агент поверх GPT-5, который берёт короткие описания вроде прикинь калории от пробы теста для торта и крем-чиза (но сам торт не ел) и переводит их в оценку потребления.

А вот приложение в строке меню, которое отслеживает температуру по всему дому с помощью дешёвых датчиков TP-Link — тех самых, что заодно дают Компартии Китая доступ к Apple TV. Обычно после сборки чего-то подобного можно было бы много рассказать о протоколах и HTTP API, которыми пользуются эти устройства, но в данном случае разбираться в этом самостоятельно не пришлось, так что известно лишь одно: есть два разных пути авторизации — для получения данных из облака и напрямую от датчика.

Наконец, раз уж речь зашла об Apple TV — вот святой Грааль нативной разработки под macOS: рабочий пульт управления Apple TV прямо в строке меню (а заодно и для телевизора Roku, и для ресивера Denon — универсальный пульт как-никак). Пару лет назад за такое было бы не жалко заплатить хорошие деньги, потому что это классический портрет задрота, который держит открытый MacBook на коленях, смотря «Дом ниндзя» вместе с супругой.
Напрямую разговаривать с Apple TV — та ещё морока. Но оказалось, что кто-то уже разобрался с этим и написал Python-библиотеки. Использовать их «напрямую» не пришлось, потому что это нативное Swift-приложение, но это неважно: всё, что написано на Python, с тем же успехом могло бы быть реализовано на Swift, C# или Brainfuck. Для передовой модели разницы никакой.
Некоторая самокритичность присутствует. Хвастаться пачкой сгенерированных SwiftUI-интерфейсов — значит напрашиваться на суровую и беспощадную критику их визуального дизайна. Пожалуйста, критикуйте. Но как давний клиент App Store: все эти дизайны как минимум на голову выше среднего уровня. Пять лет назад, будь в команде живой macOS-UI-специалист, результат такого качества вызвал бы искренний восторг.
По правде говоря, эти вещи почти не воспринимаются как «приложения» (распространять их никто не собирается). Это скорее артефакты того, как заставить компьютер делать нужное — именно так, как хочется. Как юниксовый нёрд, всегда была возможность делать это на языке командной строки. Теперь то же самое так же легко делать через графические интерфейсы.
❦
Терминальные интерфейсы строят потому, что вынуждены, а не потому, что должны.
Но сначала — пара слов о CLI и TUI: интерфейсы командной строки и терминальные пользовательские интерфейсы — оба продукты 1970-х, скроенные под ограничения телетайпов и тупых видеотерминалов. Оба склонны быть устаревшими, недружелюбными и ограниченными по сравнению с графическими интерфейсами. Но эти черты присущи именно TUI, а не CLI. У CLI есть незаменимые задачи. Делать CLI — почти всегда хорошая идея. Делать TUI — почти никогда.
Ещё в 1999 году Нил Стивенсон написал эссе о интерфейсах командной строки, которое отбросило область human-computer interaction лет на 20 назад. В нём он изображает жречество юниксовых нёрдов, владеющих CLI, как могущественных Морлоков, держащих на своих плечах всю компьютерную индустрию. Элои же пользуются GUI вроде Microsoft Word. Из-за такого щедрого фансервиса «В начале была командная строка» превратилась в один из священных текстов отрасли, несмотря на то, что 25 лет спустя почти ничего в ней не выдерживает проверки временем.
На самом деле терминальные интерфейсы существуют вовсе не благодаря какой-то особой машинной эмпатии между компьютером и оператором. Есть всего две причины, по которым появились TUI: модемы и нежелание юниксовых нёрдов учить Motif.
И их можно понять. В середине 1990-х пришлось немного поработать с Motif, и это отбило охоту заниматься разработкой UI на следующие 29 лет. Curses — тоже не подарок, но освоить его можно за пять минут. Без шуток: сегодня для TUI никто не выберет чистый curses, но стоит попросить ChatGPT дать краткую выжимку («не тратить время на объяснение концепций») минимума, необходимого для написания pico. Взять выданный им код и скомпилировать — он работает. И понятно, куда двигаться дальше. Просто там особо нечего изучать.
Агент способен надёжно собрать вполне приличный нативный интерфейс для macOS просто за счёт использования фреймворков SwiftUI так, как рекомендует Apple. В этом разница между нативными приложениями и веб-интерфейсами: однотипность здесь — плюс, нативные приложения и должны быть похожи друг на друга.
А вот и одна из проблем TUI: даже с хорошим фреймворком вроде Ratatui, Textual или Bubbletea приходится бороться с терминалом, чтобы асимптотически приблизиться к тому, что любой нативный фреймворк делает хорошо из коробки. Прокрутка и цели прокрутки — очевидный пример. Drag-and-drop — ещё один. Выделение текста становится головной болью, когда рамки окон рисуются посредством внутриполосной сигнализации! Несколько плавающих окон. И это всё ещё до работы с изображениями.
Можно за час получить сносную версию многих стандартных элементов управления в TUI-фреймворке: выбор даты, защищённое текстовое поле, прогресс-бар, текстовый редактор. Но большинство из них будут хуже системных аналогов и плохо компонуются друг с другом без дополнительных усилий.
В нативном UI всё это просто работает из коробки.
Сейчас наверняка захочется без обиняков объяснить, почему в 2046 году все всё ещё будут с удовольствием пользоваться TUI. Стоит заранее ответить на пару таких аргументов.
TUI — экономичные и быстрые интерфейсы с высокой плотностью информации. Нёрды ценят их не только за ретро-эстетику. Им нравится решать сложные задачи за секунды парой нажатий клавиш.
Всё это правда, но чтобы аргумент звучал убедительно, начинать абзац пришлось бы со слова «только», а это было бы неправдой. Графические интерфейсы действительно редко бывают экономичными, плотными и клавиатурно-ориентированными. Но обычно потому, что их не проектируют под нёрдов (даже в Linux графические интерфейсы часто амбициозно нацелены на мифического обычного пользователя «Linux на десктопе»). Ничто не мешает спроектировать плотный и экономичный GUI. Это уже сделано!
Все эти удобства TUI — веский аргумент в пользу того, чтобы делать больше графических интерфейсов, ведь экспериментировать с ними стало легко и дёшево. Хочется увидеть нативный UI, который вобрал бы в себя всё лучшее из Magit или Lazygit (и желательно, чтобы его не пришлось собирать самому).
Следующий аргумент: TUI работают через SSH-соединения. Если нужен пользовательский интерфейс на проде — это будет TUI.
Проблема этого аргумента в том, что пользовательский интерфейс на проде, скорее всего, не нужен. Нужен интерфейс командной строки на проде, которым будет управлять пользовательский интерфейс на MacBook. Любой, кто хоть раз что-то делал с bpftrace, знает это на собственной шкуре — как минимум с третьего раза, когда пришлось рисовать столбчатую диаграмму из хэш-символов. К счастью, прецедент есть: посмотрите на Emacs TRAMP, который эффективно скрывает SSH-соединения и предоставляет нативный (и графический, если хочется) редакторский опыт работы с удалёнными файлами, который даже работает с LSP и Magit.
Ещё скажут, что TUI доступны для людей с ограничениями по зрению и другими особенностями (accessibility).
Проблема этого аргумента в том, что он, скорее всего, неверен. Здесь стоит быть осторожным, поскольку личного опыта использования функций доступности нет — приходится опираться на опыт людей, которые занимаются accessibility профессионально. Вот докладчик, описывающий, как скринридеры зачитывают построчные обновления «хрома» TUI: решётка, решётка, решётка, решётка, тире, тире. Звучит не очень.
Современные нативные UI-фреймворки изначально проектировались с прицелом на хорошую доступность. SwiftUI хранит два дерева интерфейса — визуальное и семантическое дерево доступности. Есть TUI-фреймворки, которые похвально пытаются решить эту проблему. Речь не о том, что TUI не может быть доступным — просто доступность не повод предпочитать TUI графическим интерфейсам.
Наконец, есть один действительно сильный аргумент в пользу TUI: они кроссплатформенны.
Агент вполне способен собрать нативный UI под Windows и Linux, и результат наверняка окажется приличным. Но десктопов с Windows и Linux под рукой нет, чтобы опробовать эти интерфейсы, и хотя почва под ногами явно смещается, все, наверное, согласятся, что между вайб-кодингом и вайб-шиппингом всё ещё есть важная разница. Кто-то скоро выпустит приложение, которое даже не открывал и не тестировал. Но это будет не он.
При этом, собирая TUI, можно быть достаточно уверенным, что пользователи Linux получат тот же опыт. Это немало. Но стоит помнить: приложения делаются не для чужого использования, а для себя. Ради пользователей Linux, которым отдаются программы, даже не предназначенные для публикации, жертвовать удобствами TUI — слишком дорогая цена.
Пару лет назад все эти аргументы звучали бы совершенно глупо. Не потому, что TUI были хороши, а потому, что нативный UI не был разумным запросом. Доказательство тому — почти десятилетие, прожитое с Electron-приложениями. Всё потому, что качественный нативный UI было трудно делать. Но теперь это не так, и стоит делать его чаще.
❦
Судить можно только о разработке под macOS, но есть предположение, что GTK 4 под Linux и WinUI 3 под Windows сравнимо просты. Если интерес разгорелся — хорошая новость: сделать приличное нативное macOS-приложение не так уж сложно.
Подход был такой: пороться по подборкам навыков (skills), в итоге взяв этот навык дизайна для macOS, базовый навык типографики (сегодня на Github найдётся и получше того, что использовалось здесь) и навык SwiftUI от Пола Хадсона. Также был взят навык языка Swift от Airbnb — забота об идиоматичности генерируемого кода никуда не делась.
Стоит убедиться, что включён computer-use или как там это называется в Codex. Хочется запустить задачу, пойти пообедать и вернуться к приложению, которое работает достаточно хорошо, чтобы отладка стала приятной. Это работает намного лучше, когда агент может видеть и управлять приложением.
Главное улучшение качества жизни — больше никогда не открывать Xcode. К счастью, друг Джош написал сборочный процесс, полностью управляемый через Makefile, после попытки самостоятельно скомпилировать MDV. Теперь Claude просто копирует этот процесс в каждый новый проект.
Собственно, весь процесс сейчас сводится к этому: копируется шаблонная папка приложения, в ней открывается Claude или Codex, и ему объясняется, что нужно построить. Шаблон вряд ли идеален, и кто-то более компетентный наверняка должен собрать по-настоящему хороший SwiftUI-прото-проект (а если такой уже существует — стоит о нём рассказать).
Похожий процесс используется и для сборки TUI-приложений (стоит попросить агента тестировать TUI через tmux — работает отлично). Но не факт, что когда-нибудь ещё захочется собирать TUI.
❦
Фронтенд-разработчики, бэкенд-разработчики, дайте только сказать: речь не о том, чтобы похоронить TUI, а о просьбе прекратить создавать новые.
Стоит признаться сразу: TUI никогда особо не нравились. В 1990-х пользовался Mutt (до этого Elm, а ещё раньше Pine) — пока не появилась возможность перейти на графический почтовый клиент.
Весь этот текст можно было бы прочитать как язвительное признание в личных предпочтениях. Что ж, в своём духе.
Но интересно здесь не то, нравятся ли терминальные интерфейсы лично кому-то. Портить кому-то удовольствие не входит в задачу. Замечено кое-что, что, кажется, ещё не до конца осознано: после десятилетий деления разработки на «фронтенд» и «бэкенд», а фронтенда — ещё и на «веб» и «нативное», агенты стёрли большинство этих границ. Теперь вполне разумно по умолчанию строить нативные пользовательские интерфейсы для чего угодно, и эти интерфейсы будут вполне неплохими (или что там сходило за нативное последние десять лет).
Если, как и многие, годами считать себя системным программистом, который не пишет код пользовательского интерфейса, или, того хуже, что место в индустрии — это писать интерфейсы, где окна рисуются символами ASCII, — время пересмотреть эту позицию.
Одно дело — просто не интересоваться пользовательским интерфейсом или даже питать отвращение к хорошему UI в пользу странной эстетики 1970-х (осуждать не за что: было время, когда использовался Enlightenment). Но если внутри юниксового Морлока прячется тайный симпатизант Элоев, ценящий такие интерфейсы, как NetNewsWire, Transmit, Little Snitch и Audio Hijack — стоит остановиться и прислушаться. Если ни один из пяти сотен одноразовых CLI-скриптов ещё не превращён в нативное приложение — это упущенная возможность. Стоит попробовать собрать нативный UI. Это вполне может изменить взгляд на разработку.