AI Presenter Video Skill for Hermes Agent: Full Guide
Make a verified AI presenter video from script + image.
Written by Neura Market from the official Hermes Agent documentation for Ai Presenter Video. Commands, paths, and version numbers are reproduced from the source unchanged.
Read the official documentationThe AI Presenter Video skill turns a topic or a finished script plus one authorized adult presenter image into a publish-ready presenter-led video. It handles the whole chain: locked narration, avatar generation with lip-sync checks, captions, deterministic editing, loudness-normalized master and share encodes, and acceptance reports. Reach for it when you want a talking-head video you can actually ship, not a demo clip, and when you are willing to do the review steps it enforces.
What it does
The skill is a workflow, not a single command. It creates a job directory with a job.json state file, walks that job through intake, manual input review, narration lock, presenter generation, editing, and delivery, and keeps you from skipping ahead. Every stage leaves evidence behind: QA reports, provider request bodies and task IDs, decode checks, and a contact sheet you are expected to look at.
It is provider-neutral by design. The source maps abstract capabilities onto whatever the session actually has: FAL video and image models through image_generate and the video-gen plugin, speech through text_to_speech, word-timestamp ASR through the whisper/STT tooling or faster-whisper in a venv, and ffmpeg for everything deterministic. The bundled scripts themselves are deterministic: no network calls, no credentials.
You can use it for a brand-new video or to continue, revise, caption, repair lip-sync on, or re-export an existing job. Resuming is a first-class path: read job.json and the QA reports, then pick up from the earliest unfinished state. Accepted work is never regenerated.
Before you start
This is an optional skill, installed on demand, at optional-skills/creative/ai-presenter-video. Version 1.0.0, MIT licensed, authored by cclank and ported by Hermes Agent. Platforms listed are linux and macos.
Practical prerequisites implied by the source:
- ffmpeg with ffprobe.
preflight.pyrequires ffprobe, so on a bare machine install ffmpeg first. - bash, jq, and awk for
finalize_delivery.sh. - A presenter image you have the rights to use, of an adult, that you have actually looked at.
- Generation capabilities in the session if you want remote avatar or voice work: FAL image-to-video families (Kling, Wan, MiniMax H3 and similar) through the configured video tooling, or an avatar/lipsync endpoint you have access to, plus
text_to_speechfor narration. - A budget conversation. Remote avatar and TTS generation is billable. Before the first paid call, state the uploaded assets, requested seconds, known cost, pilot size, and retry ceiling, and get explicit approval.
One Hermes-specific detail matters from the first command. Upstream hardcoded its own agent's skills path; in Hermes the loader expands ${HERMES_SKILL_DIR} to the installed directory of this skill, so commands reference that token directly:
SKILL_DIR="${HERMES_SKILL_DIR}"
Shell variables do not survive between tool calls. Re-paste that assignment, or the expanded path, in every terminal call that needs it.
Start or resume a job
A new job is created with init_job.py. The minimum is a job directory, a presenter image, and either a topic or a script:
python3 "$SKILL_DIR/scripts/init_job.py" \
--job-dir ~/Videos/my-presenter-video \
--presenter-image /path/to/presenter.png \
--topic "explain context engineering in one minute" \
--duration 60 --aspect 9:16 \
--rights-confirmed --adult-presenter-confirmed
Swap --topic for --script when you already have a finished script file. Other flags the source lists: --voice-sample, --supporting-media, --width, --height, --fps, --watermark, --cta.
The two consent flags on that command are not decoration. They set booleans under the input object of job.json, and preflight will keep blocking until the required ones are true. If you hand-edit the file, target input.*, not the job root: editing at the root silently does nothing and preflight keeps blocking.
For an existing job, do not re-run init. Read job.json plus the QA reports and resume from the earliest unfinished state.
Manual input review
Before any generation, you look at the presenter image with vision_analyze and listen to any voice sample. Then you record what you found by setting the manual_input_review booleans in job.json:
python3 - <<'PY'
import json
p = "~/Videos/my-presenter-video/job.json" # expand ~ or use an absolute path
import os; p = os.path.expanduser(p)
j = json.load(open(p))
j["manual_input_review"].update(image_viewed=True, single_clear_face=True,
image_has_no_unwanted_text=True)
json.dump(j, open(p, "w"), indent=2)
PY
Then run the gate:
python3 "$SKILL_DIR/scripts/preflight.py" ~/Videos/my-presenter-video/job.json
Proceed only when the report says ok: true. Do remote generation only when remote_ready: true. The distinction matters: preflight.py separates errors, which block everything, from remote_blockers, which block only remote generation. Local script and audio work can continue while remote is blocked.
One behaviour to plan for: preflight updates job.json in place to record the report path. Re-read the file after running it rather than editing a stale copy.
Lock content and audio
Read references/generation.md for this stage. The script becomes full narration through text_to_speech, the narration is verified against the script with word-timestamp ASR, and real durations are recorded. The locked audio is the master clock for everything downstream, which is why the operating rules forbid presenter generation, caption timing, or final scene boundaries before it is locked.
Plan and generate the presenter
Also covered in references/generation.md. Generate a short, low-cost pilot first. Only after the pilot passes identity and mouth-timing review do you run the full generation. Visual QA is done with vision_analyze on the contact sheet and sampled frames, checking identity, mouth timing, hands, blinking, and continuity; numeric checks come from the scripts' ffprobe output.
Keep provider request bodies and task IDs, minus credentials and expiring URLs. If work is interrupted, poll before resubmitting so you do not pay twice. And stop after three rejected paid candidates, then summarize the failure mode instead of burning more budget.
Edit
Read references/editing.md. The timeline is deterministic and driven by the locked audio. Captions and keyword callouts come only after audio and media are final. If the hyperframes skill is installed, the editing reference has a HyperFrames section that maps onto it; otherwise ffmpeg filtergraphs do the compositing.
Verify and deliver
Read references/qa-recovery.md, render, then run the finalizer:
bash "$SKILL_DIR/scripts/finalize_delivery.sh" \
~/Videos/my-presenter-video/renders/rendered.mp4 \
~/Videos/my-presenter-video/outputs my-video
The finalizer preserves aspect ratio, runs two-pass loudness normalization (program around −16 LUFS), produces master and share encodes, decode-verifies both, writes a delivery report JSON, and emits a nine-frame contact sheet. Inspect that contact sheet with vision_analyze before you claim the job is done. The source is explicit that completion is not claimed until the final files fully decode and the contact sheet or full playback has been reviewed.
Operating rules
The source calls these non-negotiable, and they are the part most likely to save you from a bad outcome:
- Confirm image rights, adult status, remote-upload approval, and voice-cloning authorization before the relevant remote action. Never upload the presenter image to a remote provider before
remote_upload_approvedis true injob.json. - Never infer or clone a real person's voice from an image. Use an authorized sample or a stock TTS voice.
- Lock the complete narration before presenter generation, caption timing, or final scene boundaries.
- Mute video sources in the final composition; only the approved narration and intentional mix tracks carry audio.
- Preserve provider request bodies and task IDs, minus credentials and expiring URLs, and poll interrupted work before resubmitting.
- Stop after three rejected paid candidates and summarize the failure mode.
- Do not claim completion until the final files fully decode and the contact sheet or full playback has been reviewed.
The consent flags all live under input in job.json: rights_confirmed, adult_presenter_confirmed, remote_upload_approved, and voice_clone_approved. manual_input_review.* sits at the root.
Defaults for minimal input
When you give the skill almost nothing, it assumes 9:16 at 1080×1920 and 30fps. Topic-derived videos target 45 to 75 seconds. It uses a stock voice when there is no authorized sample, a presenter-led layout with a hook, two to four beats, and a close, and it adds no music or CTA unless you ask. Language is inferred from the request.
When not to use it
If you want a quick clip with no review overhead, this skill is heavier than you need: the manual input review, preflight gate, pilot, and contact-sheet inspection are all mandatory steps. If you have no authorized adult presenter image, or cannot get remote-upload approval, remote generation stays blocked and only the local script and audio stages are available. If your video has no presenter at all, the avatar and lip-sync machinery is wasted work.
Limits and gotchas
preflight.pyrequires ffprobe. Install ffmpeg on a bare box first.- Consent booleans set by init flags land under
input.*. Editing them at the job-json root silently does nothing and preflight keeps blocking. finalize_delivery.shneeds bash, jq, awk, and a fully decodable input. A truncated render fails the decode check by design.- Long avatar clips drift. Prefer one continuous presenter source sliced on the audio timeline over many regenerated chapter clips; identity drift across regenerations is described as the number one visual-QA failure.
- FAL i2v endpoints cap duration, typically 5 to 15 seconds. Plan chapter-level presenter segments accordingly and reuse the pilot's seed and parameters for consistency where the endpoint supports it.
- Shell variables do not persist between tool calls, so the
SKILL_DIRassignment has to be repeated. - Preflight rewrites
job.jsonin place, so re-read it after running.
The source records a hands-on validation from August 2026: init_job.py produced a job.json with the correct state machine; preflight.py blocked on unreviewed inputs, flipped to ok: true after the review booleans, and kept remote_ready: false until input.remote_upload_approved; and finalize_delivery.sh on a synthetic 5s 1080×1920 render produced decode-verified master (631kbit/s) and share encodes, a delivery-report JSON, and a 9-frame contact sheet, exit 0.
What pairs with it
The source lists three related skills. hyperframes is the compositor option for the editing stage. kanban-video-orchestrator is the neighbouring video workflow skill. comfyui covers image and video generation through ComfyUI when that is your provider. The upstream project lives at cclank/lanshu-create-ai-presenter-video under MIT, and the upstream body is kept substantively verbatim in references/.