Every YouTube field for the Quiet CPU Coolers package is drafted and sitting at
ready_for_review. Content readiness is complete. The only question left is the
route: ChannelHelm can now push the video for you via the Direct YouTube Data API
(once the brand is connected), hand Shorts to Zernio, or you can paste fields into
YouTube Studio by hand. This page maps each asset to its status and shows the one switch that ships it.
✓ All YouTube content is generated and approval-ready.
✓ Direct upload is built — connect the brand's YouTube OAuth and set youtube_dispatch_target='youtube_direct' to auto-publish.
→ Not yet connected on this brand: until then, approving routes to manual (you paste into Studio).
The gauge scores two independent dimensions. Content readiness (are all the required assets present?) is at 100%. Dispatch readiness (is an automated route configured?) waits on the brand's OAuth connection.
Content is fully ready; only the route is unconfigured on this brand. The Direct path requires GOOGLE_OAUTH_CLIENT_ID/SECRET in /settings and a per-brand connect.
The Direct upload bundles youtube_title_set (the trigger) with youtube_description, youtube_chapters, youtube_tags, and the top thumbnail_concept (an AI-generated image, with frame-extract fallback). All sit at ready_for_review — one approve away from approved, then dispatched, then published.
Solid amber = where each asset is now (ready_for_review). Dashed = the enum it still has to traverse. On the Direct path, approving youtube_title_set carries its siblings to dispatched automatically.
6 long-form YouTube assets + thumbnails + clean transcript, plus social drafts — all at ready_for_review from Codex CLI (gpt-5.5).
title_set · description · chapters · tags
AI-generated images · plain + headline variants — both ranked (frame-extract fallback if no image provider)
short_clip_plan not yet rendered · ships via Zernio
linkedin · x_post · x_thread · article_brief · newsletter
worker uploads via Data API v3 once connected
youtube_oauth empty · target = manual
The brand's youtube_dispatch_target decides. Full comparison on the publish options page.
ChannelHelm uploads original.mp4 straight to YouTube. Privacy defaults to private; the per-package picker also offers public / unlisted / schedule.
GOOGLE_OAUTH_CLIENT_ID/SECRET in /settings (one client, all brands)./brands/[id] → Connect YouTube → consent → token saved encrypted.youtube_direct, then approve — the worker does the rest.The only v1 path for Shorts. After clip_render, a rendered_short_clip goes to TikTok + Instagram + YouTube Shorts in one createPost.
ZERNIO_API_KEY, connect networks, paste each acc_… on the brand.CLOUDFLARE_TUNNEL_HOSTNAME + MEDIA_URL_SECRET).privacy='schedule' + publish_at → Zernio scheduledFor.Always available, zero setup. Copy each field, upload the MP4 yourself. The dispatch is recorded for audit but makes no API call.
studio.youtube.com; paste title / description / tags.dispatched (no published webhook).Scores are model-judged hook strength (0–100). The Direct upload uses the title at selectedIndex from the youtube_title_set payload — open the Studio to swap.
On the Direct path these fields go to videos.insert automatically. On the manual path, this is exactly what you paste into YouTube Studio.
thumbnails.set on the Direct path. With no image provider configured, this falls back to frame extraction at the top hook timestamp.Paste GOOGLE_OAUTH_CLIENT_ID/SECRET in /settings, then /brands/[id] → Connect YouTube → consent. The refresh token saves encrypted on brands.youtube_oauth. Set youtube_dispatch_target='youtube_direct'.
/packages/pkg_01KSHR025HW9EXD2VN094Y6TDP — pick the top title (or override the selectedIndex), and choose visibility in the per-package picker.
youtube_title_setThat single approve enqueues a dispatch job. The worker bundles youtube_description / youtube_chapters / youtube_tags + the top thumbnail, then uploads — flipping all the siblings to dispatched in the same transaction.
Refresh → access token → videos.insert (resumable, streamed from disk) → thumbnails.set. The YouTube URL is mirrored onto packages.intelligence.published.youtube and the red ▶ youtu.be/… chip lights up.
Approve the short_clip_plan → clip_render produces rendered_short_clip → approving that dispatches to TikTok + Instagram + YouTube Shorts in one Zernio call. Direct Shorts is deferred to v2.
DB says packages.status = 'analyzed' but every asset is ready_for_review. The
markReadyForReviewIfComplete lifecycle bumper didn't fire — probably because the worker got
killed during a pnpm dev:all restart cycle while the last generate_asset was completing.
Effect: the dashboard filters may not list this package under “ready” yet. Fix: one-line SQL or a 5-line lifecycle-resync. Say the word.
The description contains the literal string {{brand.name}} instead of “Thorsten Meyer AI”.
The prompt's mustache placeholder wasn't substituted at generate-time.
Effect: the upload would carry “subscribe to {{brand.name}}”. Fix: patch
workers/lib/generate.ts (brand interpolation) + regenerate that one asset before dispatching.
The Studio is where you approve and pick visibility. Connect the brand once and the next approve uploads itself — or compare all three routes first.