Как стать автором
Поиск
Написать публикацию
Обновить

Пилим стартап, часть 2.5. Мини-гайд по Claude Code, причесываем UI

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров2.1K

Да, я убрал из заголовка "за выходные", потому что проект чутка растянулся. Но идёт весело!
У него и веб-версия теперь есть: 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 частей:

  1. Делаем скелет приложения

  2. Делаем runtime-компиляцию TSX-компонентов (предыдущая часть) 2.5. Причесываем интерфейс и подключение к БД, сетапим Claude Code (эта часть)

  3. Делаем AI-агента и сравниваем AI-фреймворки

  4. Учим агента писать код и делать SQL-запросы

  5. Собираем всё в кучу и причёсываем

Поехали!

Причесываем рантайм среду

Как вы может помните, наши виджеты умеют делать так:

import { runSql } from '@/lib/utils';

await runSql('select * from users');

Коннект к базе у нас привязан к дешборду. Один и тот же виджет может быть размещён на разных дешбордах, и, соответственно, runSql должен выполняться на разных базах. Соответственно, нам надо чтобы runtime-контекст виджета был привязан к дешборду, чтобы на этапе инициализации рантайма, мы сразу могли пробросить конкретную функцию с привязанной БД.

Завёл под это отдельный класс WidgetRuntime, который инкапсулирует все стадии обработки виджета:

  1. Получили исходный код

  2. Скомпилировали код, получили jsBundle, cssBundle

  3. Подключили текущий контекст (коннект к БД)

  4. Собрали компонент (пробросили контекст, выполнили код модуля, вытащили из 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 не устоит.

Из популярных в коммьюнити идей, обычно делают что-то типа такого:

  1. code-reviewer - ревью изменений, прогон tsc --noEmit, eslint --fix, тесты, предложения диффов.

  2. perf-auditor - фокус на перфомансе, сборка версии проекта со статистикой по скорости, подсказки по бандлу и @typescript-eslint.

  3. 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, и вуаля, наша веб-версия готова:

https://mini.qyp.ai

Думаю, так следить за прогрессом будет гораздо нагляднее.

Заключение

Спасибо, что читаете! Небольшой выходной проектик чутка разросся, но, думаю, половина пути уже позади.
Впереди самое интересное - делаем интерфейс чата (скучно) и тестируем разные фреймворки для создания ИИ-агентов (весело). Следующая часть как раз будет со сравнением фреймворков, stay tuned!


А ещё, я очень много пишу про стартапы, новости ИИ, разработку с ИИ, и многое другое у себя в телеграм-канале. Даже про этот проект я пишу там обычно на несколько дней раньше Хабра. В общем, там здорово!

Теги:
Хабы:
-1
Комментарии1

Публикации

Ближайшие события