Files
jellybit/CLAUDE.md
T
avandClaude Opus 4.8 2ec952c810 backlog: интеграция скилла ведения беклога
Беклог теперь ведётся пользовательским скиллом `backlog` (заведение из
диалога, разбор находок ревью, груминг, приоритизация, декомпозиция,
штурм). CLAUDE.md делегирует ему формат и держит только проектные
тонкости; добавлены источники задач (диалог, Tududi, находки ревью) и
кладбище `docs/backlog/CLOSED.md` для выкинутого без реализации.

- task-pipeline: шаги 1 и 9 больше не описывают формат сами, ссылаются на
  скилл; шаг 9 гоняет `backlog.py check` после удаления файла задачи.
- review-pipeline: отложенная реальная находка (не для текущего мерджа)
  заводится задачей через скилл с тегом партии review-ГГГГ-ММ-ДД.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-23 21:26:11 +03:00

13 KiB
Raw Blame History

CLAUDE.md

Памятка для работы над jellybit. Перед задачей прочитай также README.md, BRIEF.md и docs/specs/architecture.md. Разработка идёт по Spec Driven Development через OpenSpec — см. раздел ниже.

Что это

Связующий сервис qBittorrent ↔ Jellyfin: принимает торрент + контекст, качает, распознаёт фильм/сериал (LLM + контекст + опц. метабазы) и раскладывает файлы для Jellyfin хардлинками. Деплоится на домашний медиа-сервер umbar (/home/av/projects/private/umbar) — туда копируется готовый бинарь.

Стек и принципы

  • Go, один статический бинарь (CGO_ENABLED=0). Почему — см. ADR-2026-06-13-go-single-binary.
  • SQLite как хранилище (чистый Go-драйвер modernc.org/sqlite).
  • Конфигурация — TOML. Логи — структурированный JSON (log/slog).
  • Хардлинки, источник не трогаем — qBittorrent продолжает раздачу, диск не дублируется.
  • Единое ядро, тонкие транспорты — вся логика приёма в use-case Ingest; HTTP API, веб-UI и Telegram — лишь обёртки над ним.
  • Минимум компонентов — в духе umbar, без зоопарка сервисов. Внешние базы метаданных (TMDB/TVDB) опциональны, включаются конфигом.

Инварианты (безопасность данных)

  • Источник неприкосновенен: только mkdir / link(2) / unlink своих ссылок; никогда не трогаем файлы под paths.downloads.
  • Целевой путь санитизируется и проверяется, что он строго под paths.movies/series (защита от traversal); существующее не перезаписываем.
  • Выход LLM недоверенный — безопасность на валидации пути, не на промпте. Авто-раскладка только при подтверждённом матче в базе.
  • Секреты не попадают в логи — пароли qBittorrent, API-ключи LLM/метабаз, auth-заголовки. Подробнее — docs/conventions/logging.md.
  • Запуск: контейнер под 1000:1000, в общей docker-сети (адресация по именам), mount /srv/media (единая песочница) + data-том для SQLite/конфига.

Spec Driven Development (OpenSpec)

Изменения ведём через OpenSpec (CLI openspec, v1.x). Сначала спецификация — потом код.

  • openspec/specs/<capability>/spec.mdактуальные capability-спеки: что система делает сейчас. Capability — это поведение/домен (ingest, recognition, file-layout, review, notifications), а не пакет кода.
  • openspec/changes/<id>/ — предлагаемое изменение: proposal.md (зачем и что), design.md (как, для нетривиальных), дельта-спеки (ADDED/ MODIFIED/REMOVED Requirements), tasks.md (шаги). После реализации change архивируется в openspec/changes/archive/, дельты вливаются в openspec/specs/.
  • openspec/config.yaml — язык и правила оформления спек (читай перед написанием).

Поток работы — через слэш-команды opsx:* (канонический набор, его поддерживает openspec update): opsx:explore (продумать), opsx:propose (завести change), opsx:apply (реализовать tasks), opsx:sync/opsx:archive (влить и архивировать). Skills openspec-* — то же, но предыдущего поколения; для новой работы используем opsx:*.

Правила спек:

  • Каждое ### Requirement ОБЯЗАНО содержать литерал SHALL или MUST — иначе openspec validate падает.
  • Структурные заголовки и ключевые слова — английские (### Requirement:, #### Scenario:, GIVEN/WHEN/THEN, RFC 2119), остальной текст — русский.
  • Сценарии — в формате GIVEN/WHEN/THEN.
  • openspec validate --strict перед коммитом change.

Ревью (процесс, не артефакт): два чекпоинта — профиль design на предложении (после design/specs, ДО кода) и ревью изменения после apply, до archive. Оба идут через скилл .claude/skills/review-pipeline: детерминированный гейт (task gate) → сверка с дельта-спеками в обе стороны → generative-проходы → триаж с потолком 7 находок. Профиль (quick/standard/deep) выбирается по факту изменения, правило — в скилле.

Миграция: capabilities постепенно переносятся из docs/specs/ в OpenSpec (пилот — ingest). До переноса источник истины по теме — соответствующий файл в docs/specs/; перенесённое живёт в openspec/specs/.

Прочая документация

  • docs/specs/живые спецификации целевого состояния (архитектурный обзор + ещё не перенесённые в OpenSpec темы). Меняем по мере развития, держим в соответствии с кодом.
  • docs/adr/неизменяемый журнал решений, пишется постфактум, хранит почему. Правила — docs/adr/README.md.
  • docs/drafts/ — черновики: планы, идеи, ещё не принятые решения. Не источник истины.

Задачи и беклог

  • Единственный источник беклога — каталог docs/backlog/: одна задача = один markdown-файл (docs/backlog/<slug>.md) + строка в индексе README.md. Приоритеты: высокий/средний/низкий. Работа с беклогом (заведение из диалога, разбор находок ревью/аудита, груминг, приоритизация, декомпозиция, штурм идеи) — через скилл backlog; формат файла, слага, индекса и кладбища он и держит, здесь не дублируем.
  • Источники задач: диалог, инбокс Tududi и находки ревью. Отложенная находка review-pipeline (реальная, но не для текущего мерджа) заводится задачей через скилл backlog с тегом партии review-ГГГГ-ММ-ДД — так уже сделаны задачи review-* в беклоге.
  • Проектные тонкости для скилла backlog:
    • каталог беклога — docs/backlog/, язык — русский, слаги — латиница;
    • реализованная задача удаляется, её суть переезжает в docs/specs/docs/adr (это делает пайплайн задачи на шаге 9, не скилл беклога);
    • выкинутая без реализации уезжает строкой в docs/backlog/CLOSED.md (кладбище);
    • спекулятивные задачи помечены [idea] в заголовке (тип — английское ключевое слово idea/epic/task) — сперва штурм.
  • Tududi — только инбокс сырых идей (проект jellybit, project_id 14). Беклог там больше не ведём; идея из Tududi становится задачей, когда её оформляют файлом в docs/backlog/ через скилл backlog. Прежняя единая docs/backlog.md доступна в истории git.

Язык

  • Документация, комментарии, сообщения коммитов — русский.
  • Код и идентификаторы — английский.

Команды

Запуск через Task (task --list — полный список):

  • task setup — установка тулинга (golangci-lint + git-хуки lefthook)
  • task run — локальный запуск (go run ./cmd/jellybit --config ./config.toml)
  • task build — статический бинарь linux/amd64 для сервера
  • task test / task lint — тесты и golangci-lint
  • task gate — детерминированный гейт ревью (build/vet/lint/test/race/покрытие изменённых строк/миграции/секреты); блокирует опиниативные проходы ревью
  • task review:context — карта проекта для архитектурного прохода ревью
  • task tidygo mod tidy
  • task image — docker-образ из готового бинаря

Module path — git.vakhrushev.me/av/jellybit. Go 1.26, CGO_ENABLED=0. Стек: chi, sqlx + modernc.org/sqlite, goose (миграции), pelletier/go-toml/v2, log/slog.

Конвенции кода

  • Раскладка: cmd/jellybit (точка входа) + internal/<пакет> по компонентам из architecture.md.
  • Механизируемое проверяет task gate (.golangci.yml + internal/archrules): форма ошибок и логов, конфиг мимо env, время мимо store.Now(), AUTOINCREMENT в миграциях, направление зависимостей ядро↔транспорты. Пересказывать эти правила не нужно — гейт скажет точнее.
  • Прозой остаётся то, что правилом не выражается, и читается в источнике: ошибки (трансляция доменной ошибки на внешней границе, sentinel против типизированной), логи (уровень по адресату, единственный логирующий чокпоинт, ext.*, что не логируем), конфиг (секреты рендерит деплой в файл 0600, самодокументируемый config.example.toml, валидация на старте), БД (время в UTC RFC 3339, TEXT ULID через internal/ident, ident.Parse на входной границе).
  • Миграции БД (goose, internal/store/migrations; SQL для DDL, Go — когда нужен код) — при изменении структуры (таблица/столбец/индекс/связь) в том же change обновляем ER-схему docs/specs/database.md.
  • Веб-UI на htmx — единый партиал = страница = фрагмент, ветвление по isHTMX, деградация без JS, ошибка на htmx-пути = 200 + фрагмент, самозавершающийся поллинг: docs/conventions/web-ui.md.

Кросс-каттинг конвенции (как пишем код, а не что система делает) живут в docs/conventions/ и не переносятся в OpenSpec. Механизируемое там не держим: правило уезжает в .golangci.yml или в internal/archrules и вычёркивается из прозы и из промптов ревью — процедура в references/promote.md. Прозой остаётся только то, что правилом не выражается.