# Hubfluencer (video generation)

This project can generate finished videos with **Hubfluencer** via its MCP server (`@hubfluencer/mcp`). The user buys credits and creates an access token in the Hubfluencer app; you spend those credits to produce a post-ready MP4.

> This is a paste-ready fallback. Codex's preferred format is an Agent Skill at `~/.codex/skills/hubfluencer-create/SKILL.md`. Use this `AGENTS.md` section for always-on, project-shared guidance (Codex concatenates `AGENTS.md` from the repo root down to the cwd, plus your global `~/.codex/AGENTS.md`).

## When the user asks for a video

Use the `hubfluencer` MCP tools. The user wanting "an ad / short / TikTok clip / social video for X" is your trigger.

### Token rules

- The token comes from `HUBFLUENCER_API_TOKEN`, or from `~/.hubfluencer/credentials.json` if the user ran `npx -y @hubfluencer/mcp login`.
- **Never invent a token. Never echo a token in your output.** If none is configured, tell the user to create one in the app (Settings → Access tokens, "Generate videos" scope) or to run `npx -y @hubfluencer/mcp login`, then stop.

### Simple path (default)

Call `make_video({ prompt, save_path })` — it creates the project, starts generation, polls to completion, and downloads the MP4. `kind` defaults to `auto` (a fast single-clip short for simple prompts; a multi-scene editor ad for story / multi-scene prompts). Override only when the user is explicit: `kind: "short"` or `kind: "editor"`. An editor ad is built from **8-second AI scenes** (≈ `scene_count × 8s`).

If `make_video` returns `terminal: false`, the render is still running — call `wait_for_completion({ slug, kind })` again (reuse the returned `slug` and `kind`). A few minutes per render is normal.

**Brand a short, don't ship it bare:** pass `headline` (on-screen TITLE, ≤160), `subheadline` (≤200), and a `music_vibe` (Upbeat/Cinematic/Minimal/Luxury/Playful/Jazz) / `theme` (none/realistic/cinematic/…14) to `make_video` or `create_short` — these are SHORTS fields (`theme` is shared; the others are ignored for editor). For the user's own product image / brand logo / closing card, use the granular path (one-shot can't attach files).

### Granular path (control / recovery)

`get_credits` → `create_short` | `create_editor_ad` → `generate_short` | `autopilot` → `wait_for_completion({ slug, kind })` → `download_result`. Also available: `get_status`, `list_voices`, `list_projects`.

### Granular editor control (author every step, no autopilot)

`create_editor_draft` (0cr, no autopilot) → `generate_scenario` (1 assist) | `set_scenario` (free) → `get_editor` (**review**) → `set_scene_count` (1..20) → `set_segment_prompt` per scene (1..2000) → `generate_segment` / `generate_all_segments` (sequential, continuity preserved; 5cr/scene) → `set_narration_script` (≤12000, free) | `generate_narration` (1 assist) + music `description` (≤1200) → `generate_voice { voice_id }` (3cr, voice_id required) + `generate_music` (5cr) → `render` (0cr) → `wait_for_completion({ slug, kind: "editor" })` → `download_result`.

### Bring your own media (local uploads, 0cr)

**Editor:** `upload_video { slug, file_path, add_to_timeline? }` — uploads a local clip and waits until it is processed (`status: ready`); with `add_to_timeline` (default) it also appends it as a finished scene. Otherwise `add_segment_from_upload { slug, upload_id }`, or `use_asset_for_segment { slug, segment_id, upload_id }` (also takes `source_segment_id` to reuse a finished scene). Images: `set_product { slug, file_path, description? }` (then `set_product_placement { slug, mode: "throughout"|"end" }`), `set_closing_image`, `set_logo`. **Short:** `set_short_product { slug, file_path, description? }` (product image) and `set_short_poster { slug, file_path }` (end-card still) — no logo overlay on shorts. Video mp4/mov/webm/mkv ≤500 MB/≤5 min; image jpeg/png ≤20 MB. **Only upload files the user explicitly gave you.**

### AI assists

Helper calls that write content draw from a **free daily quota of 20** per account (separate from credits). Check `get_ai_assists`; buy more with `unlock_ai_assists` (1 credit → +10).

- Consume 1 assist: `generate_scenario`, `enhance_prompt`, `suggest_next_scene`, `suggest_music_prompt`, `generate_narration` (its "free" summary means free of credits, NOT quota).
- Free writes: `set_scenario`, `set_segment_prompt`, `set_narration_script`, add/reorder, `apply_scenario`, `render`.
- **429 ai_assist_quota_exceeded** = out of assists (unlock once or write it yourself); **402 credits_insufficient** = out of credits. Never loop.

### Credits

- Create a draft / `create_editor_draft` = 0 credits.
- Render a short = 15 credits.
- Editor: segment 5, regenerate 4, batch per-segment (≥3) 4, voice 3, music 5, render 0 (charges only ungenerated scenes); unlock AI assists 1 credit → +10.
- Multi-scene editor ads (autopilot) cost more — preflight the cost before rendering.
- Check the balance with `get_credits`.

### Result URLs

Result URLs are presigned and expire in about 24 hours — not permalinks. Download promptly and give the user the local file path.

### Failure handling

- **402 credits_insufficient** → report required vs. available credits and stop. Do not loop.
- **429 ai_assist_quota_exceeded** → daily AI-assist quota used up (not a credit problem); unlock once or write the content yourself. Never loop.
- **409 already running** → keep polling; do not start a new generation.
- **403 insufficient_scope** → the token lacks `video:generate`; ask the user to create a "Generate videos"-scoped token.
- Long waits are normal.

### Out of scope: publishing

Publishing to TikTok / Instagram requires a human-linked social account. Do not auto-publish. Return the finished MP4 path plus a ready-to-paste caption so the user can post it.
