16 часов и 8600 строк: как Claude Code помог собрать персональный супер-апп
- пятница, 23 января 2026 г. в 00:00:08
Я решил собрать для себя приложение, которое объединит несколько AI-модулей в одном месте: фитнес-трекер с AI-тренером, новостной дайджест по AI/ML, дашборды для других проектов. Не SaaS для всех, а инструмент для себя. PWA, чтобы работало как нативное приложение на телефоне.
В итоге: 4 дня по 4 часа, 8600 строк кода, работающий продукт в production. Расскажу как это получилось.

Вместо десятка разных приложений и сервисов собрать всё нужное в одном месте. Под себя, без компромиссов.
Минус очевиден: ROI отрицательный в денежном выражении. Но экономит мне время.
Fitness Module: AI-тренер с готовыми планами тренировок. Не просто список упражнений, а агент, который понимает контекст: что я делал раньше, какие есть ограничения, как прогрессирую. С долгосрочной памятью, которая накапливает знания о пользователе.

AI News Module: ежедневный дайджест по AI/ML. Grok с доступом к поиску и Twitter собирает новости, GitHub trending, исследования. Можно обсудить любую новость в чате.

Dashboard Modules: статистика других проектов (генерация изображений, Telegram-боты).

Выбирал то, с чем комфортно работать самому Claude:
Backend: Python 3.12, FastAPI, SQLAlchemy 2.0 (async), PostgreSQL, Alembic для миграций
Frontend: Next.js с App Router, React 19, TypeScript, Tailwind CSS, Zustand для state management
AI: Claude Sonnet 4.5 для фитнес-агента (нужен большой контекст и качественные ответы), Grok 4.1 для новостей (встроенный поиск и доступ к Twitter), Zep Cloud для долгосрочной памяти
Инфраструктура: VPS, Nginx, systemd
Я работаю с Claude Code CLI с самого его появления, как продакт, проджет и архитектор, а пишет код. Не «напиши мне приложение», а итеративная работа: обсуждаем задачу, он реализует, я проверяю, корректируем.
Для Helper я создал четыре специализированных агента:
.claude/agents/
├── helper-ai.md # AI интеграция (Claude, Grok, Zep)
├── helper-backend.md # Backend разработка
├── helper-frontend.md # Frontend разработка
└── helper-db.md # База данных и миграции
Каждый агент знает контекст своей области: какие паттерны используем, где лежат файлы, какие есть ограничения. Пример агента для AI-интеграции:
---
name: helper-ai
description: AI integration for Helper PWA
tools: Read, Write, Edit, MultiEdit, Bash, Glob, Grep
---
# Helper AI Integration Agent
## Context
- Fitness Agent: Claude Sonnet 4.5 with MCP tools
- News Agent: Grok 4.1 with web_search/x_search
- Memory: Zep Cloud
## Patterns
- Agentic loop with max_turns protection
- SSE streaming for chat responses
- Graceful degradation for memory operations
Когда даю задачу типа «добавь новый tool для агента», Claude Code уже знает структуру проекта, паттерны и может сразу писать код в нужном стиле.
На поздних стадиях проекта начал использовать Compound Engineering Plugin для Claude Code. Идея плагина в том, что каждый цикл разработки накапливает знания: планы информируют будущие планы, ревью ловят больше проблем, паттерны документируются автоматически.
Каждая итерация должна делать следующую проще.
На практике это помогло уменьшить количество багов. Плагин включает агентов для code review, планирования и документирования паттернов. Можно запустить в автоматическом режиме и уйти за кофе.
У меня подписка за 200$, поэтому за токенами я особо не слежу.
Планирование: Описываю что нужно сделать, Claude Code анализирует и предлагает план
Исследование: Он изучает существующий код через агентов, понимает контекст
Реализация: Пишет код с учётом паттернов проекта
Проверка: Я смотрю результат, даю фидбек
Деплой: Коммит, перезапуск сервисов
Большинство задач укладывается в 15-30 минут: от постановки до работающего кода.
Структура проекта (backend + frontend)
Базовый FastAPI с CORS и health checks
Next.js с App Router, настройка Tailwind
PostgreSQL, первые миграции
Nginx конфиг, SSL
systemd сервисы для backend и frontend
К концу дня: приложение открывается в браузере, показывает заглушку.
Модели данных: планы тренировок, дни, упражнения, прогресс
API endpoints: CRUD для планов, отметка выполнения
Фронтенд: список планов, детали плана, текущая тренировка
Zustand store с персистенцией в localStorage
К концу дня: можно выбрать план, смотреть упражнения, отмечать выполненные дни.
Интеграция Claude API с streaming
Agentic loop с MCP tools
Интеграция Zep Cloud для памяти
Чат-интерфейс с SSE
UI для отображения tool calls
Тут возникла проблема.
Я уже использовал Zep в другом проекте полгода назад. Взял код оттуда, адаптировал под новую структуру. В процессе понял, что у агента что-то не так и знает про меня меньше, чем было информации в диалогах.
Оказалось, Zep обновился. Методы, которые я использовал, частично уже не работали, частично изменились и расширились.
Что пришлось переделать:
Batch добавление сообщений: Раньше добавлял user message и assistant message отдельными вызовами. Теперь можно одним:
# Было: 2 API calls
await client.thread.add_message(user_msg)
await client.thread.add_message(assistant_msg)
# Стало: 1 API call
await client.thread.add_messages(
messages=[user_msg, assistant_msg],
return_context=True
)
Параллельное получение контекста: Раньше получал user context и делал semantic search последовательно. Теперь параллельно:
# Было: 200-400ms последовательно
context = await self.get_user_context(user_id)
search = await self.search_graph(user_id, query)
# Стало: 100-200ms параллельно
results = await asyncio.gather(
self.get_user_context(user_id),
self.search_graph(user_id, query)
)
Graceful degradation: Добавил обработку ошибок, чтобы проблемы с Zep не ломали весь чат:
try:
context = await zep.get_context(user_id)
except Exception:
context = "" # Продолжаем без контекста
На переделку Zep-интеграции ушло около 2 часов. Урок: не копировать код из старых проектов без проверки актуальности зависимостей.
Интеграция Grok API с web_search и x_search tools
Новостной дайджест: категории, избранное
Service Worker: стратегии кэширования
PWA manifest, иконки, shortcuts
Тестирование на телефоне
К концу дня: приложение можно установить на телефон, оно работает offline для статики.
Высокоуровнево всё выглядит так:
┌─────────────────────────────────────────────────────────┐
│ Helper PWA │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Fitness │ │ AI News │ │ Dashboards │ │
│ │ Module │ │ Module │ │ Module │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ ┌──────▼───────────────▼───────────────▼──────┐ │
│ │ Frontend (Next.js) │ │
│ │ React + Zustand + Tailwind │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ SSE / REST │
│ ┌──────────────────────▼──────────────────────┐ │
│ │ Backend (FastAPI) │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │FitnessAgent │ │ NewsAgent │ │ │
│ │ │ (Claude) │ │ (Grok) │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ │ │
│ │ │ │ │ │
│ │ ┌──────▼────────────────▼──────┐ │ │
│ │ │ Zep Cloud (Memory) │ │ │
│ │ └──────────────────────────────┘ │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Фитнес-агент и новостной агент работают по-разному.
Фитнес-агент (Claude Opus 4.5) использует MCP tools. Это значит, что я определяю инструменты на своей стороне, а Claude решает когда их вызывать. 11 инструментов: получить план, отметить день выполненным, добавить заметку к упражнению, создать новый план и т.д. Изначально был Sonnet, но мы слишком много спорили, а в сообщениях было больше воды, поменял и не стал его терпеть.
Новостной агент (Grok 4.1 fast) использует server-side tools. Grok сам ходит в интернет чере�� web_search() и x_search(). Мне не нужно реализовывать web scraping, всё происходит на стороне xAI. Позже еще добавил инструмент для анализа трендов github.
┌───────────┬─────────────────┬────────────────────────────────────┐
│ Аспект │ Фитнес (Claude) │ Новости (Grok) │
├───────────┼─────────────────┼────────────────────────────────────┤
│ Модель │ Sonnet 4.5 │ Grok 4.1 │
├───────────┼─────────────────┼────────────────────────────────────┤
│ Tools │ MCP (БД, планы) │ Server-side (web_search, x_search) │
├───────────┼─────────────────┼────────────────────────────────────┤
│ Память │ Zep Cloud │ Нет (stateless) │
├───────────┼─────────────────┼────────────────────────────────────┤
│ Streaming │ SSE │ SSE │
└───────────┴─────────────────┴────────────────────────────────────┘
Оба агента работают по одному паттерну: получают сообщение, решают нужно ли вызвать tool, если да, вызывают и продолжают. Защита от бесконечных циклов через max_turns:
max_turns = 10
for turn in range(max_turns):
response = await model.create(messages, tools)
if response.stop_reason != "tool_use":
break # Агент закончил
# Выполняем tools и продолжаем
Когда пользователь пишет «что у меня сегодня?», агент сам вызывает get_current_workout() и формирует ответ на основе результата.
Проблема: план тренировок содержит 116 упражнений (4 недели × ~4 дня × ~7 упражнений). Передавать всё в каждый запрос дорого и избыточно.
Решение: Navigator генерирует компактную сводку (~500 символов):
## План тренировок (навигатор)
**Активный план:** Ятс для здоровья спины
Прогресс: Неделя 4/4, 87% (14/16 дней)
**Текущая тренировка** (⏳ следующая):
Неделя 4, День 3: Плечи + Шея
Упражнения (7): Жим гантелей сидя, Разводка...
**Последние тренировки:**
- ✓ Н4Д2: День Б (20.01)
- ✓ Н4Д1: День А (18.01)
**Статистика:** streak 5, completion: 92%
Агент может ответить на простые вопросы («какая тренировка сегодня?») без tool calls, экономя токены и время.
LLM не помнит между сессиями. Пользователь говорит «у меня болит плечо», через неделю агент предлагает жим над головой.
Zep Cloud автоматически извлекает факты из разговоров, строит граф знаний, предоставляет semantic search.
async def get_full_context(self, user_id: str, current_query: str) -> str:
# Параллельный fetch для скорости (50% latency reduction)
tasks = [
self.get_user_context(user_id), # Summarization
self.search_graph(user_id, current_query) # Semantic search
]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Combine into context string...
Latency: 100-200ms благодаря параллельным запросам.
Ответы агента стримятся через SSE. Пользователь видит как агент «думает»: появляется текст, потом индикатор вызова tool, потом результат, потом продолжение ответа.
Иногда у меня может не быть интернета, а тренировку я хочу посмотреть.
Zustand persist + offline queue. Без IndexedDB, просто localStorage (~2KB на план при лимите 5MB).
interface OfflineAction {
type: 'complete' | 'skip';
dayId: string;
reason?: string;
}
// В completeDay():
if (!navigator.onLine) {
set((state) => ({
offlineQueue: [...state.offlineQueue, { type: 'complete', dayId }],
// Optimistic update
currentDay: { ...state.currentDay, completed: true }
}));
return true; // Success — queued for sync
}
При появлении сети очередь автоматически синхронизируется:
window.addEventListener('online', async () => {
const { offlineQueue, syncOfflineQueue } = get();
if (offlineQueue.length > 0) {
await syncOfflineQueue();
}
});
UI показывает статус: «Офлайн», количество действий в очереди, «Синхронизация...»
Service Worker написан вручную, без Workbox или других библиотек. Три стратегии кэширования:
Stale While Revalidate для статики: отдаём из кэша мгновенно, обновляем в фоне.
Network First для API: сначала пробуем сеть, если не получилось, берём из кэша.
No caching для SSE: стриминговые endpoints пропускаем.
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
if (url.pathname.includes('/chat/stream')) {
return; // SSE не кэшируем
}
if (url.pathname.startsWith('/api/')) {
event.respondWith(networkFirst(event.request));
} else {
event.respondWith(staleWhileRevalidate(event.request));
}
});
Статистика кода:
Компонент | Строки |
|---|---|
Backend Python | ~3000 |
Frontend TypeScript | ~5100 |
Конфигурация | ~500 |
Итого | ~8600 |
Время:
4 дня по 4 часа = 16 часов
Из них ~2 часа на переделку Zep-интеграции
Технические цифры:
11 MCP tools для фитнес-агента
116 упражнений в плане (4 недели × ~4 дня × ~7 упражнений)
~500 символов в Plan Navigator (вместо полного плана)
~2KB localStorage на план (лимит 5MB)
100-200ms latency Zep (параллельный fetch)
Стоимость AI:
Claude Sonnet 4.5: $3/$15 per 1M tokens (input/output)
Grok 4.1 Fast: $0.20/$0.50 per 1M tokens
Grok существенно дешевле для задач где не нужен большой контекст и сложное рассуждение.
Claude Code: Когда есть чёткое понимание архитектуры и требований задача, Claude Code может писать код быстро и качественно. Работа должна строится итерациями через фидбек.
Агенты в CLI: Специализированные агенты для разных частей проекта экономят время. Они не тратят основной контекст.
Compound Engineering Plugin: Помогает накапливать знания о проекте. Особенно полезно когда возвращаешься к коду через неделю.
Для внешних сервисов: Zep может упасть, API может тормозить. Если это не блокирует основной flow, приложение продолжает работать.
Plan Navigator вместо полного контекста: Компактная сводка ~500 символов вместо 116 упражнений. Агент отвечает на простые вопросы без tool calls, экономя токены.
Разные модели для разных задач: Claude для сложных задач с памятью, Grok для задач с поиском. Grok в 10 раз дешевле, и для новостного дайджеста этого достаточно.
Копирование кода из старых проектов без проверки: Зависимости обновляются, API меняются. Потратил 2 часа на то, что можно было избежать проверкой документации.
Всё не имеет смысла если это для личного проекта - мне хватает текущей архитектуры.
Можно было проще.