С телефона в Альпах — в Microsoft Store за две недели: нативный GUI для PostgreSQL через облачный Claude Code

Я больше десяти лет пишу коммерческий код под .NET, живу в Праге, PostgreSQL — мой ежедневный рабочий инструмент. В начале июля я сидел в отпуске в Альпах — без ноутбука, только с телефоном — и мне было банально скучно: весь ютуб к тому моменту был досмотрен. Зато у меня обнаружились неиспользованные лимиты Claude Code и хорошо выдержанная рабочая фрустрация: pgAdmin, которому нужно секунд тридцать, чтобы запуститься, когда надо быстро что-то проверить, и вечная лотерея с кавычками — где двойные, где одинарные, я не угадывал никогда. Сложив скуку, лимиты и фрустрацию, я решил, что пора сделать что-нибудь полезное.

За выходные, целиком с телефона, не написав руками ни строчки кода, я получил первую рабочую версию клиента для Postgres: подключение к базе, дерево схемы, редактор с подсветкой, стриминг результатов. Потом были две недели вечеров после работы — полировка, ручное тестирование, 17 релизов. Сегодня pgNimbus опубликован в Microsoft Store, есть macOS-бета и Linux-пакеты, MSI весит 19 МБ, а от клика до окна проходит около 100 миллисекунд.

Это мой первый публичный опенсорс-проект, и это статья о том, как на самом деле выглядит разработка, когда IDE — это чат: что агент делает сам, где без человека никак, и какие грабли по дороге были настоящими, а не из презентаций.

1. Выходные с телефона

Идея «быстрого клиента для Postgres» не нова, ниша давно описана: pgAdmin и DBeaver мощные, но тяжёлые; TablePlus быстрый и красивый, но закрытый и платный; HeidiSQL быстрый и открытый, но родом из другой эпохи и MySQL-first. Дырка «по-настоящему быстрый + опенсорс + современный UI» так и стоит незанятая — в неё я и целился.

Разработка с телефона выглядит менее героически, чем звучит. Облачный Claude Code — это веб-клиент: агент работает в песочнице с полноценным репозиторием, а ты пишешь ему задачи в чат. Читать диффы с экрана телефона — занятие для сильных духом, так что моя «среда разработки» в те выходные свелась к трём вещам: скриншоты приложения, которые агент присылал из облака, обновляющийся README и его собственные рассуждения по ходу работы. Первый коммит — 4 июля: скаффолд решения на .NET и Avalonia, два проекта — PgNimbus.Core (движок, зависит только от Npgsql) и PgNimbus.App (весь UI). В тот же день появились дерево схемы, менеджер подключений с хранением паролей в DPAPI и инлайн-редактирование в гриде. Не потому что я такой быстрый — потому что каждая из этих задач для агента — это час-полтора работы, а от меня требовались постановка и «нет, переделай вот это».

Честно признаюсь: это затягивает почище любого сериала. Наблюдать за ходом мысли модели — как она разворачивает себе окружение с нуля (в голой песочнице нет ни .NET, ни дисплея, ни Postgres — она ставила всё через apt, поднимала Xvfb, локальный Postgres с тестовыми данными), запускает приложение под виртуальным дисплеем, скриншотит его и по этим же скриншотам дебажит — оторваться невозможно. Смотришь на очередной скриншот приложения, которого утром ещё не существовало, и ловишь себя на том, что обновляешь чат чаще, чем ленту. Тесты она гоняла сама и собственные регрессии тоже находила сама.

Где приходилось направлять: во всём, что касается вкуса и приоритетов. Агент с одинаковым энтузиазмом сделает и нужную фичу, и ненужную, и на каждую предложит кнопку в тулбаре. Половина моих реплик в те выходные — это «нет», «проще», «убери кнопку, пусть будет в палитре команд». Из этого потом выросли письменные правила проекта, о них ниже.

Что не получалось: всё, что упирается в живой пиксель. Классика жанра — иконка приложения. Агент честно сгенерировал скриптом все размеры из одного мастера, и на панели задач Windows это выглядело как мутное пятно; в итоге в репозитории лежат отрисованные отдельно мастера под каждый размер (16, 24, 32, 48 px — свои, не даунскейл), а скрипт их только собирает. Или иконка в таскбаре Windows 11, которую Avalonia через Window.Icon обновляет в заголовке окна, но не на панели задач — пришлось разбираться и слать WM_SETICON напрямую через P/Invoke. Такие вещи агент не увидит сам — их видит человек, который запустил приложение на настоящей машине.

Поэтому домой из отпуска я, чего уж там, спешил: очень хотелось наконец запустить собранное приложение на настоящей машине, а не разглядывать его через скриншоты. Первый запуск оправдал ожидания в обе стороны: недоделок и косяков нашлась сразу куча — но база оказалась более чем рабочей, и её можно было начинать полировать.

Главное окно pgNimbus: редактор запросов, результаты, дерево схемы
Главное окно pgNimbus: редактор запросов, результаты, дерево схемы

Главное окно: редактор, стриминговый грид результатов, дерево схемы из pg_catalog.

2. Две недели вечеров и CLAUDE.md как архитектурный надзор

Так проект переехал в режим «вечера после работы». С 6 по 18 июля — 17 тегов, от v0.1.0 до v0.7.5. Это не 17 больших релизов, конечно: часть — минорные фиксы, найденные при ручном прогоне. Но каждый тег — это полный прогон релизного пайплайна, включая бенчмарки, так что дисциплина «main всегда собирается и измеряется» держалась с первой недели.

Главный инструмент управления агентом оказался неожиданно скучным: файл CLAUDE.md в корне репозитория. Это память проекта, которую агент читает в начале каждой сессии. Туда я складывал не документацию, а правила: «PgNimbus.Core не имеет UI-зависимостей», «стриминг и отмена запросов не обсуждаются», «каждая новая всегда видимая кнопка по умолчанию отклоняется — второстепенные действия живут в палитре команд», «двойной клик по элементу списка выполняет его основное действие». Звучит как банальности, но эффект накопительный: агент без таких правил каждый раз изобретает архитектуру заново, а с ними — держит линию через десятки сессий, между которыми у него нет никакой памяти.

Разделение ролей за эти две недели устоялось такое: агент пишет код, тесты и CI; я пишу правила, ревьюю каждый PR, руками прогоняю сборку на живой базе и отвечаю за то, что уходит в релиз. Это не «AI сделал всё за меня» — это скорее работа тимлидом у очень быстрого, очень исполнительного джуна с энциклопедическими знаниями и полным отсутствием мнения о том, что важно. Мнение — моя работа.

Ручное тестирование при этом никуда не делось, и именно оно ловило самое интересное. Скролл результатов на macOS, где двигался скроллбар, но не контент (тач-обработчик колеса писал в ScrollBar.Value напрямую, а DataGrid реагирует только на пользовательские события скролла). Гейткиперский диалог «приложение повреждено» на неподписанной macOS-бете. Ни одну из этих вещей агент не нашёл бы в песочнице — там нет ни macOS, ни настоящего тачпада.

3. Почему быстро И маленько: NativeAOT

Тезис проекта — скорость, и здесь всю тяжёлую работу делает NativeAOT: .NET-код компилируется сразу в машинный, без JIT и без рантайма в комплекте. Разница ощущается кожей: около 100 мс от клика до отрисованного окна против ~700 мс у обычной JIT-сборки того же кода. И размер: MSI — 19 МБ, потому что не надо тащить рантайм.

Холодный старт pgNimbus: от запуска процесса до готового окна
Холодный старт pgNimbus: от запуска процесса до готового окна

Холодный старт NativeAOT-бинарника. Гифка длиннее, чем сам старт.

Публикация выглядит буднично:

dotnet publish PgNimbus.App -c Release -r win-x64 -p:PublishAot=true

Но AOT — это контракт: никакой рефлексии в рантайме, никакой динамической генерации кода. Три грабли из этого репозитория, на которые стоит показать пальцем, если вы соберётесь повторить путь:

Сателлитные сборки + InvariantGlobalization. Сочетание InvariantGlobalization=true с culture-named сателлитной сборкой роняло Avalonia под AOT прямо на старте — причём с абсолютно сбивающей с толку ошибкой «avares://… not found», как будто потерялся ресурс. Лечится одной строкой в csproj, но чтобы её написать, надо сначала понять, что резолвер ассетов тут ни при чём:

<InvariantGlobalization>true</InvariantGlobalization>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>

Рефлексия в биндингах грида. Биндинг колонок результатов через индексаторный путь "[i]" — это рефлексия, под AOT она молча не работает. Колонки в pgNimbus биндятся через конвертер (RowIndexConverter), а на уровне проекта включён AvaloniaUseCompiledBindingsByDefault, чтобы рефлексионный биндинг не пролез случайно.

Сериализация настроек. System.Text.Json с рефлексией под AOT тоже не жилец — все сторы (настройки, воркспейс, история запросов) ходят через source-generated контексты:

[JsonSourceGenerationOptions(WriteIndented = true)]
internal sealed partial class WorkspaceJsonContext : JsonSerializerContext;

Отдельная приятная деталь: агент про все три граблины знал — не в смысле «угадал», а в смысле «наступил, диагностировал по симптомам и починил» в той же песочнице, где собирал linux-x64 AOT-публикацию для проверки времени старта.

Стартовая гонка: pgNimbus против pgAdmin с холодного старта
Стартовая гонка: pgNimbus против pgAdmin с холодного старта

Та самая гонка, с которой всё началось: pgNimbus уже показывает результаты запроса, пока pgAdmin ещё думает над сплеш-скрином.

4. Кроссплатформенность почти бесплатно: Avalonia

UI написан на Avalonia 12 — один XAML-код на Windows, macOS и Linux, рендеринг через Skia. «Почти бесплатно», потому что 95% кода действительно общие, а оставшиеся 5% — это платформенные мелочи, съедающие непропорционально много времени: заголовок окна на macOS (слить командную панель с тайтлбаром, отступ под «светофор»), та самая иконка таскбара на Windows, Cmd вместо Ctrl в хоткеях (с одним осознанным исключением: автокомплит остался на Ctrl+Space, потому что Cmd+Space — это Spotlight).

Релизный пайплайн (release.yml) с одного тега собирает всё: Windows — AOT-публикация плюс per-user MSI через WiX; macOS — osx-arm64 на раннере macos-14, завёрнутый в .app и .dmg (Intel-маков среди раннеров GitHub больше нет — прощай, osx-x64); Linux — x64 и arm64 (arm64-нога собирается нативно на бесплатных ubuntu-24.04-arm раннерах, без кросс-компиляции), каждый в трёх форматах: AppImage, .deb и tar.gz. Плюс MSIX для Store и сгенерированные winget-манифесты. Один тег — девять устанавливаемых артефактов.

Из платформенных засад дороже всего обошлась macOS: Xcode 26 сломал Swift-автолинковку так, что NativeAOT перестал статически линковать системную криптобиблиотеку («symbol(s) not found for architecture arm64»), и апстрим закрыл issue как «not planned». Решение — прибить в CI новейший Xcode ниже 26-й мажорной версии и оставить комментарий потомкам.

5. «Быстрый» — это измеряемо

Слово «быстрый» в README ничего не стоит, поэтому в проекте оно измеряется на каждом релизе. Бенчмарк-пайплайн — это отдельный workflow, который запускается из релизного: поднимает Postgres в сервис-контейнере, собирает и JIT-, и AOT-варианты и меряет четыре вещи — время от старта процесса до первого отрисованного кадра (специальный probe-режим: приложение печатает window_ms и RSS и выходит), холодное подключение к базе, round-trip SELECT 1, время до первой пачки строк и полный стриминг 100 000 строк через тот же API, которым пользуется UI. Плюс размер: и AOT-бинарник отдельно, и весь публикуемый набор файлов — второе честнее, потому что нативные библиотеки Skia рядом с экзешником весят больше него самого.

Результаты каждого тега уходят в публичную историю: https://shman4ik.github.io/pgNimbus/dev/bench/. Смысл не в абсолютных числах (они зависят от железа раннера), а в тренде: если какой-то коммит сделал старт на 30% медленнее, это будет видимая ступенька на графике, привязанная к конкретному релизу. Регрессию производительности нельзя «не заметить» — она опубликована.

Стриминг — вторая половина тезиса о скорости. Результаты запроса не материализуются целиком, а текут в UI пачками примерно по 200 строк, так что первый экран данных виден задолго до конца запроса, а Esc действительно останавливает выполнение на середине, а не «после того как дочитаем»:

public sealed record ResultSet : StatementResult
{
    public required IReadOnlyList<ColumnInfo> Columns { get; init; }
    public required IAsyncEnumerable<RowBatch> Batches { get; init; }
}

6. PostgreSQL-first, а не наименьший общий знаменатель

Большинство универсальных клиентов читают схему из information_schema — стандартного, но обедняющего представления. pgNimbus ходит прямо в pg_catalog, поэтому дерево схемы видит материализованные представления, партиционированные таблицы и настоящие флаги первичных ключей из pg_constraint. Кроссплатформенность по базам данных не планируется вовсе: это клиент для Postgres, и точка.

Из этого растут фичи, которые в универсальном клиенте сделать трудно. Автокомплит знает о внешних ключах: после JOIN первыми предлагаются таблицы, связанные FK с уже упомянутыми, а после ON первой строчкой стоит готовое условие целиком — oi.order_id = o.id, одно нажатие. EXPLAIN и EXPLAIN ANALYZE рисуются деревом с per-node стоимостью и временем, а не простынёй текста. Есть live-монитор LISTEN/NOTIFY и окно активности сервера поверх pg_stat_activity — с кнопками cancel и terminate для чужого зависшего запроса.

Автокомплит: FK-ranked таблицы после JOIN и готовое условие после ON
Автокомплит: FK-ranked таблицы после JOIN и готовое условие после ON

После JOIN — таблицы, связанные внешним ключом, после ON — готовое условие соединения.

Дерево плана EXPLAIN ANALYZE рядом с исходным текстом
Дерево плана EXPLAIN ANALYZE рядом с исходным текстом

EXPLAIN ANALYZE деревом: стоимость и фактическое время на каждом узле.

Отдельно — safe mode, фича, выросшая из личного страха инлайн-редактирования на проде. Правки ячеек, вставки и удаления по умолчанию не летят в базу сразу: они копятся локально (изменённые строки подсвечены), а кнопка «Review & commit» показывает точный сгенерированный SQL и применяет всё одной транзакцией. Или отменяет — и тогда в базу не ушло вообще ничего. Режим включён по умолчанию: SafeModeEdits = true в настройках.

И про телеметрию: её нет. Совсем — ни аналитики, ни crash-репортов, ни проверок обновлений. Единственные сетевые соединения, которые открывает приложение, — те, что вы настроили сами: ваши серверы Postgres и, если используете, SSH-туннели. Для инструмента, через который проходят продакшн-креды и продакшн-данные, мне это кажется не фичей, а гигиеническим минимумом; проверяется чтением кода, благо он открыт.

7. Дистрибуция без бюджета: Microsoft Store за $0

У бесплатного опенсорс-проекта нет денег на Authenticode-сертификат, а без подписи прямой MSI встречает пользователя SmartScreen-предупреждением. Классическая развилка: платить несколько сотен долларов в год за сертификат — или найти обходной путь.

Обходной путь — Microsoft Store, и он бесплатный. Хитрость в том, что Store переподписывает загруженный MSIX собственным доверенным сертификатом при сертификации: пакету нужен лишь одноразовый self-signed серт, чтобы пройти требование загрузки, — не купленный. В CI это выглядит так: скрипт пакует AOT-публикацию в MSIX, подписывает эфемерным сертификатом из New-SelfSignedCertificate (и тут же удаляет его из хранилища), артефакт вручную уходит в Partner Center. Первая же отправка прошла сертификацию, листинг живой: ID 9N6SZT42XJ24. Бонусом Store-приложения автоматически видны в winget через источник msstorewinget install pgNimbus --source msstore работает без отдельного PR в winget-pkgs.

Самая же неожиданная возня была не с подписью, а с иконками. Положить в MSIX по одному PNG на логотип недостаточно: Windows молча подкладывает под иконку цветную плашку и мылит её на таскбаре и в диалоге установки, если не находит файл нужного размера с нужным квалификатором. Нужен набор scale-100/125/150/200/400 плюс отдельные «unplated» варианты для таскбара — и всё это ещё надо скомпилировать в resources.pri утилитой makepri, иначе квалифицированные имена файлов просто лежат в пакете мёртвым грузом. Инструкции, почему у вашего MSIX «иконка какая-то не такая», собирались по крупицам — теперь они живут в памяти проекта, чтобы следующая сессия агента не открывала это заново.

Прямой MSI при этом остаётся — неподписанным, per-user (ставится в профиль, без прав администратора: неподписанный плюс UAC — совсем плохое сочетание). Это осознанное решение, а не долг: Store даёт доверие и автообновления за ноль, платный сертификат не даёт ничего сверх этого.

8. Честные выводы

Что агентная разработка делает хорошо. Объём: за две недели вечеров сделано то, на что у меня одного ушли бы месяцы, — не потому что агент пишет код лучше меня, а потому что он пишет его параллельно со мной спящим и не устаёт от рутины вроде CI-пайплайнов, упаковки в пять форматов и правки тестов. Инфраструктуру — CI, бенчмарки, скрипты сборки под три ОС — агент делает едва ли не лучше, чем фичи: там меньше вкусовщины и больше проверяемых критериев успеха.

Где без человека никак. Вкус и приоритеты: что не делать — целиком человеческое решение, и это половина продукта. Живое железо: настоящий тачпад, настоящий таскбар, настоящая продакшн-база — песочница этого не заменяет, и самые неприятные баги были найдены руками. Ответственность: под релизом стоит моё имя, а не имя модели; каждый PR прочитан, каждый релиз прощёлкан. И письменные правила — оказалось, что главный навык работы с агентом — это не промптинг, а способность превратить своё «мне не нравится» в правило, записанное так, что оно переживёт сотню сессий.

pgNimbus сейчас — это версия 0.7.5: работающий, быстрый, ежедневно используемый мной клиент, но всё ещё молодой проект. Роадмап открыт — он лежит прямо в README, от таблично-индексной статистики до PostGIS-вьювера. И мне правда нужен фидбек: я один, вечеров в неделе пять, и порядок, в котором фичи будут появляться, стоит определять не моими предпочтениями.

Что делать следующим?

  1. ER-диаграммы — автоматически разложенный граф внешних ключей схемы, с экспортом в SVG.

  2. Дифф EXPLAIN-планов — прогнать запрос до и после индекса и сравнить деревья планов узел к узлу.

  3. UI для бэкапов — оркестрация pg_dump/pg_restore с прогрессом.

  4. Приватный AI-ассистент (BYOK) — свой ключ или локальная модель, явный opt-in, ничего не покидает машину.

Голосуйте в опросе под статьёй, а если есть что сказать развёрнуто — жду в Discussions. Ну и ⭐ на GitHub, если идея «быстрый + открытый + современный» вам близка — для проекта без бюджета на маркетинг звёзды и есть маркетинг.


Комментарии (6)


  1. MonkAlex
    22.07.2026 10:55

    Пользуюсь DBeaver-ом, запуск действительно занимает время, но я его не закрываю.

    Ну т.е. я его открыл и он может работать месяц. Поэтому время запуска не считаю критичным. К слову, так же оценивал и различные новости об ускорении запуска виндовс, потому как... зачем?

    Запросы писать гуй действительно не требовательный, поэтому из интересного отметил бы любые улучшения в анализе запросов (EXPLAIN).

    Успехов, хороший инструмент лишним не будет.


    1. Shman4ik Автор
      22.07.2026 10:55

      Справедливо если клиент открыт месяцами, старт роли не играет. Но у меня наоборот: на винде люблю каждый день начинать с чистого запуска, и когда неиспользуемое приложение висит в трее меня это бесит. Собственно, поэтому и решил сделать свой GUI.

      Про EXPLAIN взял на заметку, потрачу пару сессий с Клодом на ресёрч и имплементацию.

      Спасибо за коммент!


  1. unnamed63
    22.07.2026 10:55

    Это то, чего не хватало в pgAdmin! Иногда надо выполнить короткий запрос, но запуск pgAdmin занимает очень много времени, а тут реально мгновенно! Надеюсь добавятся новые функции, хотелось бы увидеть бэкап\рестор (желательно с проверкой рестора) и мониторинг основных метрик PostgreSQL, не всегда и не все могут поставить отдельную систему мониторинга. Успехов в вайбкодинге!)


    1. Sleuthhound
      22.07.2026 10:55

      Для cli уже давно есть pgcenter

      А бэкап и рестор это отдельная длинная история и утилит тут придостаточно.


      1. unnamed63
        22.07.2026 10:55

        на Windows меньше гораздо, а некоторым приходится работать с 1с, postgresql на windows)


    1. Shman4ik Автор
      22.07.2026 10:55

      Спасибо, прямо в точку по мотивации! По твоим хотелкам:

      Мониторинг метрик уже есть: панель Database Overview (размер БД, cache-hit, самые большие отношения, seq-vs-index scan, неиспользуемые индексы) и окно Server Activity (pg_stat_activity + дерево кто-кого-блокирует по pg_blocking_pids). Открываются из палитры Ctrl+K. Отдельную систему мониторинга ставить не надо.

      Бэкап/рестор — да, в бэклоге (pg_dump/pg_restore с прогрессом), и проверку восстановления учту. Если попробуешь мониторинг расскажи, чего не хватает.