Да, я убрал из заголовка "за выходные", потому что проект чутка растянулся. Но идёт весело!
У него и веб-версия теперь есть: https://mini.qyp.ai

Напомню: я давно хотел пощупать Tauri v2, и новомодные фреймворки для построения AI-агентов (ai-sdk / mastra / llamaindex).
Идея простая: десктопное приложение, дешборд на весь экран, справа интерфейс чата. Просим ИИ вывести на дешборд какую-то информацию в духе "сколько новых юзеров за последнюю неделю" - ИИ пишет код виджета, и размещает его на дешборде. Под капотом - runtime компиляция React.js + sql-коннекторы.
Полный open-source, весь код в репозитории: https://github.com/ElKornacio/qyp-mini
Всего будет 5.5 частей:
Делаем runtime-компиляцию TSX-компонентов (предыдущая часть) 2.5. Причесываем интерфейс и подключение к БД, сетапим Claude Code (эта часть)
Делаем AI-агента и сравниваем AI-фреймворки
Учим агента писать код и делать SQL-запросы
Собираем всё в кучу и причёсываем
Поехали!
Причесываем рантайм среду
Как вы может помните, наши виджеты умеют делать так:
import { runSql } from '@/lib/utils';
await runSql('select * from users');
Коннект к базе у нас привязан к дешборду. Один и тот же виджет может быть размещён на разных дешбордах, и, соответственно, runSql
должен выполняться на разных базах. Соответственно, нам надо чтобы runtime-контекст виджета был привязан к дешборду, чтобы на этапе инициализации рантайма, мы сразу могли пробросить конкретную функцию с привязанной БД.
Завёл под это отдельный класс WidgetRuntime
, который инкапсулирует все стадии обработки виджета:
Получили исходный код
Скомпилировали код, получили
jsBundle
,cssBundle
Подключили текущий контекст (коннект к БД)
Собрали компонент (пробросили контекст, выполнили код модуля, вытащили из
exports.default
компонент)

Эта рантайм-обертка собрана с небольшим заделом на будущее - далее, когда код виджетов будет писать ИИ, нам важно сразу же собрать виджет в изолированной среде, и в случае ошибок и багов - автоматически давать фидбек ИИ, чтобы он мог автономно править код.
Изучаем Claude Code, чтобы он сделал нам дешборды
Мне хотелось дешборд со строгой сеткой, в которую и будут встраиваться виджеты. Чтобы можно было их перетягивать, ресайзить, и они подстраивались под размер своего контейнера.

Писать руками не хотелось, затаскивать какой-то сложный внешний layout engine - тоже не хотелось.
Завёл под это дело Claude Code - давно хотел сравнить его с Cursor. По началу шло туго. После того, как я сконвертировал global.mdc
(моё always-apply правило) из Cursor в CLAUDE.md
, и перетащил свой analyze-and-implement workflow из Supercode в subagent + custom slash команду для Claude Code - стало пободрее. Детально рассказывать про конвертацию workflow из Суперкода в Claude Code мне в этой статье не хочется, думаю, я про это как-нибудь отдельный гайд напишу.
Если вам хочется почитать официальные гайды, то вот:
Гайд Supercode по Smart Actions (суперкод работает только в. Cursor, поэтому их я и переделывал под Claude Code)
Гайд Claude Code по Subagents
Гайд Claude Code по Custom Slash Commands
Здесь мне хочется просто в целом рассказать про то, как Subagents и Custom Slash Commands в Claude Code устроены, и как можно их настроить под подобный проект.
Subagents
Субагенты - это преднастроенные "личности" Claude Code для конкретных задач. У каждого свой системный промпт, отдельное окно контекста и инструменты. Он может автоматом делегировать им часть работы или их можно дёрнуть явно. Они помогают разгрузить контекст основного диалога, и и повысить точность на изолированных тасках. Плюсы:
Изоляция контекста: каждый субагент мыслит в собственной песочнице, не засоряя контекст основной ветки рассуждений. Полезно при длинных сессиях, пошаговой отладке, анализе больших кодовых баз.
Отдельные роли: отдельный промпт и набор инструментов под ревью, миграции, работу с БД, генерацию тестов, CI и т.д.
Субагенты могут быть описаны как в проекте, так и быть глобальными (в папке home), что довольно удобно для переиспользования.
Субагенты описываются Markdown-файлами с фронтматтером (текстовым заголовком файла). Проектные лежат в .claude/agents/…
, глобальные в ~/.claude/agents/…
Формат файла:
---
name: code-reviewer
description: Use proactively to review changed TS files and enforce our style guide
tools: Bash(git diff:*), Bash(npm run lint:*), Bash(npm run test:*)
---
You are a principled code reviewer for a TypeScript monorepo.
Focus on readability, public API stability, and performance.
When violations are found, propose minimal diffs and explain trade-offs.
Поля:
name
- имя (kebab-case).description
- когда и зачем вызывать агента; можно явно писать штуки типа "use PROACTIVELY", чтобы основной агент почаще дёргал этого субагентаtools
- можно сузить доступ к конкретным инструментам (иначе унаследует их от основной сессии, включая MCP).
Но вообще удобнее настраивать субагентов через /agents: появится интерактивный менеджер со списком всех доступных инструментов (включая MCP), правами и подсказками.
Как вызвать:
Автоматом: Claude сам делегирует задачу, если на основе вашего запроса и description субагента он сочтёт это нужным. Как я писал выше - фразы вроде "use PROACTIVELY" в описании агента повышают шанс автозапуска.
Явно: ну, просто скажите: "Use the code-reviewer subagent to check my last commits." и Claude не устоит.
Из популярных в коммьюнити идей, обычно делают что-то типа такого:
code-reviewer - ревью изменений, прогон
tsc --noEmit
,eslint --fix
, тесты, предложения диффов.perf-auditor - фокус на перфомансе, сборка версии проекта со статистикой по скорости, подсказки по бандлу и
@typescript-eslint
.docs-writer - обновление README/Storybook/докблоков по диффам, генерирует доки в бекграунде, пока основные агенты пишут код
В качестве вдохновения можно посмотреть готовые коллекции, они быстро гуглятся и их много.
Небольшие советы на основе официального гайда:
"Короткий input -> длинная работа": старайтесь выносить всякие "поисковые" и "обзорные" задачи (прогон тестов, анализ артефактов билда) субагентам, чтобы не засорять основной контекст.
Описывайте стиль и границы: прямо в системном промпте прописывайте какими вы хотите видеть стиль правок, доступы, формат диффов, критерии завершения, и прочее.
Теперь немного про Custom Slash Commands
Custom Slash Commands - это настраиваемые команды в Claude Code. По сути, это Markdown-шаблоны с фронтматтером, которые можно запускать как /name [args]. По аналогии с субагентами - их можно держать как в проекте, так и глобально. Но команды ещё и поддерживают неймспейсы через подпапки, аргументы, вставку файлов и выполнение ограниченных bash-команд до запуска промпта.
Проектные лежат в .claude/commands/…
- отображаются в /help с пометкой (project), а глобальные лежат в ~/.claude/commands/…
- и показываются с пометкой (user).
Немного про аргументы: всё то, что вы передали в команду в качестве аргументов через /<command-name> [arguments]
будет подставлено внутрь markdown-файла команды, вместо $ARGUMENTS
. В целом, если вы юзали в Курсоре smart actions через supercode - принцип точно такой же как там с $prompt
/ $systemPrompt
, концепция та же.
Создать новую команду можно так:
mkdir -p .claude/commands
echo "Analyze this code for performance issues and suggest optimizations:" \
> .claude/commands/optimize.md
# Теперь доступно: /optimize
Подпапки превращаются в префиксы, к примеру, файл .claude/commands/frontend/component.md
создаст команду /frontend:component
. Что касается аргументов, то их использование может выглядеть так:
# .claude/commands/fix-issue.md
Fix issue #$ARGUMENTS following our coding standards
# И вызов через:
# /fix-issue 123
Но самый сок в том, что в аргументы можно закидывать содержимое целых файлов через @
:
Compare @packages/ui/src/Button.tsx with @packages/ui/src/IconButton.tsx
А !
позволяет выполнить bash-команды до запуска промпта, добавив их вывод в контекст. В фронтматтере явно пропишите разрешённые команды через allowed-tools с префиксом Bash(...), и дальше прям в тексте используйте команды, вот так:
---
allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(npm run build:*)
description: Prepare release notes from the latest changes
argument-hint: [sinceTag]
---
## Context
- Git status: !`git status`
- Diff since tag: !`git log --oneline $ARGUMENTS..HEAD`
## Task
Generate release notes grouped by package with breaking changes first.
Вновь же, если вы раньше юзали суперкодовские smart actions в Курсоре - то конструкция выше вам явно может напомнить там этот формат:
{
"Load Git Status to Prompt": {
"prompt": {
"command": "echo \"Prepare release notes: \" && git status"
}
}
}
А ещё, подключённые MCP-серверы могут публиковать собственные промпты как slash-команды для Claude Code (собственно, для этого в MCP и заводили промпты, самое время напомнить, что Anthropic - и есть авторы протокола MCP).
Примеры полезных команд:
1) /build - собрать проект и поправить типовые ошибки
~/.claude/commands/build.md
:
---
allowed-tools: Bash(npm ci:*), Bash(npm run build:*), Bash(git add:*), Bash(git commit:*)
description: Build the repo and fix errors
---
## Context
- Current branch: !`git branch --show-current`
- Build output: !`npm run -s build`
## Task
If the build fails, identify minimal code changes to fix type/lint errors.
2) /frontend:component - неймспейс для UI, .claude/commands/frontend/component.md
:
---
description: Scaffold or refactor React component with tests and stories
---
Read @packages/ui/CONTRIBUTING.md and follow patterns.
Generate a component skeleton or refactor based on the user's request.
Собираем веб-версию
В общем, попинав Claude Code в течение минут 30, я получил вполне хороший результат, который сам бы писал пару-тройку часов. Он справился раза с 5, но это в целом совершенно нормальный результат для ИИ, да ещё и нового для меня агента, к которому я не привык.
Теперь, когда дешборды были готовы, компоненты рендерились корректно, запросы в Postgres летели, и всё было здорово, мне захотелось упаковать фронт, который я использовал в Tauri, под веб. Исключительно для демки.
К сожалению, секьюрно ходить во многие БД через веб никак не получится: только проксируя запросы через собственный сервер, и, соответственно, все доступы тоже будут проходить через сервер. Мне показалось, что для демо-версии это небольшая проблема: основная ставка у нас на десктоп, а там всё локально.
Дополнительно, я решил поднять свою example-базу, с readonly юзером, и накатить туда каких-нибудь разношерстных данных, чтобы и тестить было веселее, и чтоб ИИ-агенту потом было где развернуться.
Дабы веб-версия работала, нам надо было вытащить все зависимости от Tauri в отдельный слой абстракции. Накидал Claude Code (далее - CC) задачку по созданию такой абстракции, бахнул имплементационный план через Opus, далее внёс изменения в код через Sonnet - завелось с полпинка, и заработало отлично.
Тут же заставил CC сделать мне в src-back
простенький Node.js-сервер для проксирования запросов в БД через TypeORM, и подключить к нему фронт. Это уж совсем детская задача, и тут ИИ справился с первой попытки.
Немножко причесываем, подключаем Cloudflare Pages, Wrangler, сетапим самый дешевый сервачок на DigitalOcean, и вуаля, наша веб-версия готова:
Думаю, так следить за прогрессом будет гораздо нагляднее.
Заключение
Спасибо, что читаете! Небольшой выходной проектик чутка разросся, но, думаю, половина пути уже позади.
Впереди самое интересное - делаем интерфейс чата (скучно) и тестируем разные фреймворки для создания ИИ-агентов (весело). Следующая часть как раз будет со сравнением фреймворков, stay tuned!
А ещё, я очень много пишу про стартапы, новости ИИ, разработку с ИИ, и многое другое у себя в телеграм-канале. Даже про этот проект я пишу там обычно на несколько дней раньше Хабра. В общем, там здорово!
deksden
В агентах/командах нынче можно указать модель: фронтмэттер тегом 'model: opus', например (или sonnet, haiku).
Полезно для агента, который пилит архитектуру или общий implementation plan - чтобы использовал opus. А для генерации кода оптимален sonnet: шустро, качественно. Для простых maintenance задач (типа, проверить ссылки в memory bank) наверное можно и хайку напрягать.
Опус доступен только в подписках Max, для Pro подписок - максимум sonnet.