Skill #1 · Pipeline coordinator

video-orchestrator

Дирижёр всего видео-конвейера. Получает запрос «сделай 3 ролика для бас дент» и гоняет цепочку copywriter → voiceover → director → captions → music → reviewer. Резолвит проект из команды, поднимает preflight, координирует sub-скиллы и отдаёт готовые .mp4.

Путь
~/.claude/skills/video-orchestrator/
Триггеры
сделай ролики, запусти производство, produce videos, make ads, запусти конвейер, pipeline, полный цикл, видео для таргета, нужны ролики, сделай креативы
Зависит от
все sub-скиллы (copywriter / voiceover / director / captions / reviewer), ELEVENLABS_API_KEY, ffmpeg/ffprobe
Пэйрится с
project-setup (через check_project.py), все sub-скиллы пайплайна

Что делает простыми словами

Это top-level дирижёр. Юзер говорит «сделай 3 ролика для имплантов» — а orchestrator под капотом:

  1. Определяет, какой проект имеется в виду (bas-dent, fitzone, apparatus, etc.)
  2. Читает project.yaml этого проекта → знает язык, ниши, голос-настройки, бренд
  3. Прогоняет preflight check (есть ли клипы, голоса, ключи)
  4. Запускает copywriter N раз — получает N скриптов
  5. Запускает voiceover на каждый текст — получает N mp3
  6. Прогоняет audio_process.py — убирает паузы, нормализует громкость
  7. Запускает director — собирает по 2-3 варианта на каждый ролик
  8. Накладывает hook + субтитры (captions через render_final.py)
  9. Накладывает фоновую музыку (overlay_music.py) — отдельным шагом
  10. Прогоняет reviewer для QA
  11. Выдаёт юзеру список финальных .mp4

Без orchestrator пришлось бы каждый скилл вызывать вручную и держать в голове, где какой файл лежит, какая длительность и какие настройки. С ним — одна команда даёт готовые ролики.

Каждый шаг — отдельный скилл с собственными скриптами. Orchestrator не дублирует логику. Он знает порядок и параметры, дёргает чужие scripts/, передаёт пути и фолбэчит при ошибках.

Два пайплайна (по формату ролика)

Voiceover (дефолтный)

copywriter voiceover (ElevenLabs) audio_process director (assemble, БЕЗ музыки) render_final (hook + captions) overlay_music reviewer

Длительность диктует озвучка (15-60 сек). Музыка — последний шаг, отдельно от assemble.

Textover

copywriter (textover_hook) director (clips + музыка) remotion (text overlay) reviewer

Фиксированные 15 сек, без озвучки, без Whisper, без captions. Текст рендерится анимацией поверх видео через Remotion.

Project Resolution

Каждый запуск должен знать «к какому проекту относится команда». Порядок резолва:

  1. Явно в команде: «сделай 3 видео для бас дент» → slug bas-dent → читаем video-projects/bas-dent/project.yaml
  2. Единственный проект: если в ~/video-projects/ только одна папка с project.yaml — используем её автоматически
  3. Неоднозначно: если проектов несколько и юзер не указал → спрашиваем
После резолва orchestrator передаёт sub-скиллам конкретные параметры из yaml: slug → scoping в БД, language → captions/voiceover, service_directions → copywriter, veo.* → clipgen, voiceover.* → voiceover, captions.* → captions, remotion.brand.* → motionfx, director.* → director.
director.db лежит ОБЩАЯ на все проекты — в ~/video-projects/director.db, не внутри папки проекта. Изоляция через junction-таблицы.

Два режима работы

РежимПоведениеКогда выбирать
auto (default) Гонит весь pipeline без остановок. Юзер ждёт и получает финал. Когда юзер доверяет системе и хочет скорости. Команда: «сделай 3 ролика, автомат»
semi-auto Останавливается на чекпоинтах, ждёт approval/edit Когда нужен творческий контроль. Команда: «покажи тексты перед озвучкой»

Чекпоинты semi-auto

  1. После генерации текстов — показать скрипты, ждать approval/edits
  2. После voiceover — отчитаться о длительности, спросить «ок?»
  3. После montage plan — показать какие клипы под какой сегмент идут, до сборки
  4. После выбора caption-стиля — какой preset рендерим (neon/marker/cyber/...)
  5. Перед overlay_music — какой трек и какая громкость
  6. После reviewer — показать оценки, спросить нужны ли правки

Preflight: check_project.py

Главный скрипт скилла — pre-flight check, который запускается ДО любого pipeline-run'а. Он проверяет:

Что проверяетЗачем
project.yaml существует и валиденБез него ничего не запустится
Проект зарегистрирован в projectsИначе junction-таблицы не будут работать
Brief сохранёнCopywriter без брифа пишет в пустоту
Минимум 5-10 клипов в библиотекеDirector не сможет собрать ролик без материала
Минимум 1 голос в пулеVoiceover нужен пул для rotation
ELEVENLABS_API_KEY в envБез ключа ElevenLabs упадёт
ffmpeg + ffprobe в PATHВсе сборки идут через них
python ~/.claude/skills/video-orchestrator/scripts/check_project.py ~/video-projects/bas-dent

Возвращает структурированный отчёт «что готово / что недостаёт». Если чего-то нет — orchestrator говорит юзеру, какой скилл нужен («запусти clipgen для клипов», «добавь голоса через voiceover add-voice»).

GOOGLE_API_KEY не нужен для core pipeline. Он требуется только если ты ещё и НОВЫЕ клипы генеришь через Veo (clipgen). Для «текст → аудио → сборка» хватает одного ELEVENLABS_API_KEY.

Команды основных шагов

Тексты (Copywriter)

python ~/.claude/skills/video-copywriter/scripts/db.py get-brief <project-dir>
python ~/.claude/skills/video-copywriter/scripts/db.py list-transcriptions <project-dir> --json
python ~/.claude/skills/video-copywriter/scripts/db.py list-texts <project-dir> --json --limit 10

# Сохранить сгенерированный текст:
python ~/.claude/skills/video-copywriter/scripts/db.py save-text <project-dir> \
  --type storytelling --for-video --text "<текст>"

Озвучка (Voiceover)

python ~/.claude/skills/video-voiceover/scripts/db.py next-voice <project-dir>

python ~/.claude/skills/video-voiceover/scripts/tts.py \
  --project-dir <project-dir> \
  --text "<текст>" \
  --voice-id <voice-id>

python ~/.claude/skills/video-voiceover/scripts/audio_process.py \
  --input voiceover.mp3 --output voiceover_processed.mp3

Сборка (Director)

python ~/.claude/skills/video-director/scripts/probe_audio.py voiceover.mp3
python ~/.claude/skills/video-director/scripts/db.py list-clips <project-dir> --json

# Сборка БЕЗ музыки (для voiceover pipeline!):
python ~/.claude/skills/video-director/scripts/assemble.py \
  --project-dir <project-dir> \
  --voiceover voiceover_processed.mp3 \
  --montage-plan '[...]' \
  --variant-name "video1_a" \
  --transition fade --transition-duration 0.5 \
  --sfx-transition <project-dir>/sfx/whoosh.mp3

Hook + Captions (render_final.py)

# Одним проходом Remotion — hook анимация на первой сцене + караоке-субтитры:
python ~/.claude/skills/video-captions/scripts/render_final.py \
  --video assembled.mp4 \
  --text "<полный текст озвучки>" \
  --voiceover voiceover_processed.mp3 \
  --preset neon \
  --caption-style karaoke \
  --hook-duration <sec первого предложения> \
  --sfx-file ~/video-projects/sfx/text/pop_bright.mp3 \
  --project-dir <project-dir> \
  --language ru \
  --model small

Music overlay (последний шаг)

python ~/.claude/skills/video-director/scripts/overlay_music.py \
  --video video_final.mp4 \
  --music <project-dir>/music/dramatic.mp3 \
  --volume 0.20 \
  --fade-in 2.0 --fade-out 2.5

Reviewer (опц. но рекомендуется)

python ~/.claude/skills/video-reviewer/scripts/review_video.py \
  --video captioned.mp4 --frames 15

Hook duration — критичная фишка

Per project memory: hook + первая сцена = длительность ВСЕГО первого предложения. Измерять Whisper'ом ДО сборки, второй клип идёт только после.

Замер первого предложения:

python ~/.claude/skills/video-captions/scripts/transcribe_words.py \
  --audio voiceover.mp3 --language ru --text "<текст>" --json \
  | jq -r '.words | map(select(.word | test("[.!?…]$"))) | .[0].end'

# → 4.3   ← это hook_duration; первый сегмент trim_end тот же

Whisper-кэш ключуется по sha1(audio path + mtime + size + model + lang + text hash) — повторный вызов на тот же mp3 моментален и бесплатен.

Partial runs

Orchestrator умеет запускать только часть pipeline:

ЗапросЧто запускается
«только тексты»copywriter → стоп
«только озвучки»(тексты есть) → voiceover → стоп
«только сборка»(озвучки есть) → director → стоп
«только субтитры»(видео есть) → captions → стоп
«тексты + озвучки»copywriter → voiceover → стоп
«сборка + субтитры»director → captions → стоп
«с новыми клипами»clipgen → full pipeline

Внутренности

Скрипты

ФайлЧто делает
scripts/check_project.pyPre-flight check: project.yaml, DB registration, clips count, voices, API keys, ffmpeg
scripts/api_keys.pyРезолвит API-ключи из project/api_keys.db или env (общий между скиллами)
scripts/schema.pySchema source-of-truth (v8). Копия одинакова во всех скиллах

Таблицы БД, которые трогает (опосредованно через sub-скиллы)

ТаблицаЧерез какой скилл
projectsRead (для резолва)
briefcopywriter
generated_textscopywriter
voiceover_historyvoiceover
clips / video_clipsdirector
videosdirector

Конфиг из project.yaml

Orchestrator сам ничего из yaml кроме project resolution не использует — но передаёт куски всем sub-скиллам. Ключевые блоки, на которые он опирается:

language: "ru"                    # → captions, voiceover
service_directions: [...]         # → copywriter (creative_ref пути)

veo:                              # → clipgen
  demographics: ...
voiceover:                        # → voiceover
  model: "eleven_multilingual_v2"
  speed: 1.2
captions:                         # → captions
  style: "karaoke"
remotion:                         # → motionfx
  brand: {...}
director:                         # → director
  default_format: "9:16"
  music_ducking: true
final_output_dir: "..."           # → копия финала за пределы проекта

Output / Delivery

В конце orchestrator выдаёт summary со списком всех файлов:

Production complete:

Video 1 (storytelling, 18s):
  - variant_a: /path/to/video1_variant_a.mp4
  - variant_b: /path/to/video1_variant_b.mp4

Video 2 (direct_offer, 12s):
  - variant_a: /path/to/video2_variant_a.mp4
  - variant_b: /path/to/video2_variant_b.mp4

Total: 4 video files
Voices used: Rachel (1x), Bella (1x)
Clips used: #3, #5, #7, #8, #12, #15

Gotchas и tips

НИКОГДА не передавай --music в assemble.py в voiceover-пайплайне. Sidechain ducking в assemble делает музыку неслышной поверх нормализованного голоса. В voiceover-pipeline музыка ВСЕГДА накладывается отдельно через overlay_music.py после captions. --music в assemble оставлено только для textover (без голоса — нечем ducking-ать).
Audio post-processing ОБЯЗАТЕЛЕН. Сырое ElevenLabs-аудио имеет долгие паузы и непостоянную громкость. audio_process.py убирает их (~5 сек экономии на 30-сек ролике), нормализует до -16 LUFS, чистит низы/верха EQ. Использовать processed-файл для всех последующих шагов, не оригинал.
Hook duration измерять ДО сборки. Whisper-замер первого предложения = первая сцена в монтаже. Если зашить произвольное значение (например 3 сек) — hook обрежется посредине фразы, и анимация text-overlay не сойдётся со звуком.
render_final.py = два шага в одном. Раньше hook overlay и captions рендерились двумя проходами Remotion. Теперь — один pass, плюс общий Whisper-кэш. В 2 раза быстрее, дешевле, и одна транскрипция переиспользуется между запусками.
Legacy fallback. Старые hook_overlay.py и remotion_captions.py работают standalone — полезно для отладки hook-пресета без перерендера captions. Orchestrator же использует render_final.py по дефолту.
Skill paths резолвятся как siblings. Все скиллы лежат в одной папке skills/. Если orchestrator в /path/to/skills/video-orchestrator, то copywriter — в /path/to/skills/video-copywriter. Относительно своего пути.

Место в пайплайне

project-setup clipgen / analyzer orchestrator copywriter voiceover director captions music reviewer

Orchestrator = «зонтик» над всеми остальными. Юзер видит его как точку входа в production. Под капотом — координация и preflight.

Когда использовать orchestrator, а когда — sub-скиллы напрямую: orchestrator — для production-batch'ей («сделай 3 ролика»). Sub-скиллы напрямую — для ручных правок («перегенери только captions», «замени hook»).