16 часов и 8600 строк: как Claude Code помог собрать персональный супер-апп

Я решил собрать для себя приложение, которое объединит несколько 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

Я работаю с 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

На поздних стадиях проекта начал использовать Compound Engineering Plugin для Claude Code. Идея плагина в том, что каждый цикл разработки накапливает знания: планы информируют будущие планы, ревью ловят больше проблем, паттерны документируются автоматически.

Каждая итерация должна делать следующую проще.

На практике это помогло уменьшить количество багов. Плагин включает агентов для code review, планирования и документирования паттернов. Можно запустить в автоматическом режиме и уйти за кофе.

У меня подписка за 200$, поэтому за токенами я особо не слежу.

Типичный workflow

  1. Планирование: Описываю что нужно сделать, Claude Code анализирует и предлагает план

  2. Исследование: Он изучает существующий код через агентов, понимает контекст

  3. Реализация: Пишет код с учётом паттернов проекта

  4. Проверка: Я смотрю результат, даю фидбек

  5. Деплой: Коммит, перезапуск сервисов

Большинство задач укладывается в 15-30 минут: от постановки до работающего кода.

День 1

День 1: Скелет приложения (2 часа)

  • Структура проекта (backend + frontend)

  • Базовый FastAPI с CORS и health checks

  • Next.js с App Router, настройка Tailwind

  • PostgreSQL, первые миграции

  • Nginx конфиг, SSL

  • systemd сервисы для backend и frontend

К концу дня: приложение открывается в браузере, показывает заглушку.

Fitness Module (4 часа)

  • Модели данных: планы тренировок, дни, упражнения, прогресс

  • API endpoints: CRUD для планов, отметка выполнения

  • Фронтенд: список планов, детали плана, текущая тренировка

  • Zustand store с персистенцией в localStorage

К к��нцу дня: можно выбрать план, смотреть упражнения, отмечать выполненные дни.

AI Agent + Zep (4 часа)

  • Интеграция Claude API с streaming

  • Agentic loop с MCP tools

  • Интеграция Zep Cloud для памяти

  • Чат-интерфейс с SSE

  • UI для отображения tool calls

Тут возникла проблема.

Проблема с Zep

Я уже использовал 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 часов. Урок: не копировать код из старых проектов без проверки актуальности зависимостей.

День 2: News Module + PWA (3 часа)

  • Интеграция 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)      │         │        │
│  │    └──────────────────────────────┘         │        │
│  └─────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────┘

Два разных подхода к AI-агентам

Фитнес-агент и новостной агент работают по-разному.

Фитнес-агент (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                                │
└───────────┴─────────────────┴────────────────────────────────────┘

Agentic Loop

Оба агента работают по одному паттерну: получают сообщение, решают нужно ли вызвать 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() и формирует ответ на основе результата.

Plan Navigator: оптимизация контекста

Проблема: план тренировок содержит 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, экономя токены и время.

Память через Zep Cloud

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 благодаря параллельным запросам.

Streaming

Ответы агента стримятся через 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 показывает статус: «Офлайн», количество действий в очереди, «Синхронизация...»

PWA: Service Worker

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 часа на то, что можно было избежать проверкой документации.

Всё не имеет смысла если это для личного проекта - мне хватает текущей архитектуры.

Заключение

Можно было проще.

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


  1. PelmenBlin
    22.01.2026 12:37

    Прикольно наблюдать за оптимизациями от 400 к 200 мс, когда у тебя приложение на go со всеми запросами к бд и постобработкой контента отдает ответ за 10мс.


    1. men10577 Автор
      22.01.2026 12:37

      У меня обращение во внешний сервис - Zep. Семантический поиск и саммаризация.


  1. VamWebStore
    22.01.2026 12:37

    Отличный разбор, спасибо, что так подробно расписали реальный продакшн-флоу.

    Особенно понравился подход с Plan Navigator и сжатым контекстом вместо прокидывания всего плана — очень здраво с точки зрения токенов и latency.

    Вопрос по PWA-части: сталкивались ли с какими-то edge cases при установке на iOS (особенно с повторной установкой или обновлением SW), или всё прошло относительно гладко?


    1. men10577 Автор
      22.01.2026 12:37

      У меня pixel, это был первый pwa в моей жизни


    1. ADEXITUM
      22.01.2026 12:37

      Сам недавно впилился в разработку коммерческого PWA.

      Вроде всё без танцев с бубном работает. Правда для пушей надо выкладывать в App Store.


  1. Dgbbjjhgv
    22.01.2026 12:37

    персональный супер-апп

    Прикольно конечно за 200$ в месяц

    А дальше что делать с этим аппом?


    1. men10577 Автор
      22.01.2026 12:37

      Подписка на Claude 200$. Странно покупать подписку за 200$ для создания одного приложения под личные потребности.

      Дальше - лежит, работает, собирает новости, аналитику, отслеживает тренировки. Я интегрирую в него постепенно данные от разных проектов, дашборды, выручку и другие метрики. Каждый такой блок функционала живёт своей жизнью и своим интерфейсом.


      1. Dgbbjjhgv
        22.01.2026 12:37

        Тут проблема в другом - в окупаемости.

        Теперь каждый второй может завайбкодить подобное по и выложить в стор. Там их уже не сотни, а тысячи подобных. Для кого это всё? В чём уникальность то?

        Более того такой софт надо поддерживать постоянно. Вдруг баги или на каком-нибудь телефоне криво отрисовывается кнопочка и съезжает шрифт.

        И автору софта приходится снова оформлять подписку на ии, чтобы пофиксить эти ошибки.

        И так по кругу...


        1. riky
          22.01.2026 12:37

          Если есть проблема окупаемости то каждый второй просто не будет это делать. Сделают только те кому надо/интересно.
          Такое делают те у кого уже есть прописка для работы


        1. alexey_nova
          22.01.2026 12:37

          Для кого это всё? В чём уникальность то?

          Автор в начале статьи написал.
          Для личного использования такие апы делаются. И судя по тому что это апп-агрегатор других приложений автора, подписка за 200$, очевидно, не для него покупалась.


        1. men10577 Автор
          22.01.2026 12:37

          Это же не для коммерции. А для своего удобства, в сторах этого нет, стоит мне это копейки.
          Я ИИ, и подписку, использую в своей работе и проектах, а это просто пример возможностей Claude Code


  1. lma10h
    22.01.2026 12:37

    Какой впн, где взять номер заморский для регистрации, как потом оплатить ? :)


    1. men10577 Автор
      22.01.2026 12:37

      Свой поднят, номер арендован был, есть карта.)


  1. Sneg47
    22.01.2026 12:37

    Я приложение писал полгода, иногдапо 12 часов в день, когда ещë топ моделью был соннет 3.7, с выходом лучших моделей применял их. Строк кода написано миллионы, само приложение состоит из десятков тысяч кода, если не из сотен. Более 40 экранов. Работает в основном локально. Но можно и посылать запросы к ии. Помогает полностью отслеживать свою жизнь и даже советы и всë это локально


    1. voidek
      22.01.2026 12:37

      Расскажи подробнее, дало ли это желанный эффект, выросла продуктивность или может больше контроля над жизнью стало, может нагляднее как-то всё стало, тоже думаю подобным заняться)


      1. Sneg47
        22.01.2026 12:37

        В приложение можно погрузить практически всю бытовую жизнь. То есть впринципе полный контроль.