H3 Hermes Prompt Director
An agent writes, critiques, and re-drafts your H3 prompt
- video
- frames
- audio
- subject_1_image
- subject_2_image
- subject_3_image
- subject_4_image
- subject_5_image
- subject_6_image
- h3_prompt
- duration_seconds
- fps
- analysis_json
- h3_checkpoint_hint
- ref_image_1
- ref_image_2
- ref_image_3
- ref_image_4
- ref_image_5
- ref_image_6
- ref_video
- ref_video_audio
- ref_audio
- width
- height
- length
- label_map
The two other H3 prompt nodes in this pack get a VLM to write a prompt. This one goes a step further: it uses Hermes Agent to research, draft, critique, and select a MiniMax H3 prompt, while TrentNodes keeps timing and format validation local. In plain terms - an agentic loop where the prompt is drafted, then reviewed against the H3 spec, then revised, instead of written once and repaired.
The division of labor is the interesting part. The agent gets to do the open-ended thinking (what should this shot actually be, what current H3 guidance says), and the node owns the things that must not be left to judgment: timing, format, validation. The README calls that "secure Ref2VA video/frames with optional audio" plus all Base modes, with untouched reference pass-throughs.
How it works
Required inputs set the job: h3_mode (ref, or the four base modes base_T2VA/base_I2VA/base_FL2VA/base_L2VA), subjects (the typed escape hatch), target_description (what the target video should show), quality_mode (fast/balanced/hero - a bounded Hermes candidate/review budget), and research_policy (never/when_uncertain/always - when Hermes may look up current H3 guidance).
It talks to a Hermes API, which is a real infra requirement: hermes_base_url defaults to http://127.0.0.1:8642 (a root-only plain-HTTP loopback URL), with hermes_provider and hermes_model for route selection. timeout_seconds (default 900) is a hard wall-clock limit, and poll_interval_seconds controls polling. This is not a node you run without a Hermes server standing by.
The subject-row system matches the Ultimate Cowboy node - kinds, names, descriptions, with subject_N_image slots that are <Picture N>. video_role (subject_source / structure_reference / edit_source / continuation_source) decides what the wired video is for, which is what determines the task type - wiring alone can't imply it. audio_role does the same for audio (none / reuse / reference). And cut_times accepts any Cut Detective output as ground truth for the [Shot N] times.
The validation story
Dialogue must reach a <d> block verbatim or the run retries once. constraint_notes get folded in as positive assertions because H3 has no negative field and the official format ends at non_diegetic_music. strict_duration rejects durations outside H3's official 4-15 second range. cleanup_policy handles the staged images the agent needs (delete_on_success / retain_24h / retain).
Outputs mirror the Ultimate node's honest wiring: h3_prompt, duration_seconds, fps, analysis_json, h3_checkpoint_hint, the six ref_image_N pass-throughs, ref_video/ref_video_audio/ref_audio, width/height/length on H3's grid, and label_map. Same "nothing is wired twice" guarantee - the assets you plug in come back out for the sampler.
Gotchas
- This is the heaviest of the three H3 nodes: it needs a running Hermes agent endpoint, not just an API key. Budget setup time accordingly, and mind
timeout_seconds- agentic loops can run long. snap_duration_to_h3_grid(on by default) means thelengthoutput is what H3 actually produces, not what you asked for.quality_modeherois a bounded but big budget - fine for one important prompt, slow for iteration.
Install
One of ~69 nodes in TrentNodes:
# ComfyUI Manager: search "Trent Nodes"
# or:
cd ComfyUI/custom_nodes
git clone https://github.com/TrentHunter82/TrentNodes.git
cd TrentNodes && pip install -r requirements.txt
The node ships with the pack; the Hermes server is the external dependency you'll need running on loopback. Choose between this and the two prompt nodes by how much agentic review your prompt actually needs - for most shots, the Auto Generator's validate-and-repair loop is the lighter-weight answer, and this is the one for prompts worth deliberating over.
Inputs (57)
| Name | Type | Default | Description |
|---|---|---|---|
| h3_mode | COMBO | base_T2VA | Supports secure staged Ref2VA video/frames with optional audio, plus all four Base modes: text-only T2VA, first-frame I2VA, first/last-frame FL2VA, and last-frame L2VA. |
| subjects | STRING | EXTRA subjects, typed. The rows below are the normal way in; this is the escape hatch for what a row cannot say - a seventh subject, or one that cites two pictures at once. One line each: <kind> [name] [@Picture N ...] -- <features> Kinds: character, environment, animal, object, wardrobe, interface, effect, style, action, expression, pose. Typed lines are numbered AFTER the filled rows. Ignored in the base_* modes, which have no reference labels at all. | |
| target_description | STRING | the courier ducks under a roller shutter | What the target video should show. |
| quality_mode | COMBO | balanced | Bounded Hermes candidate/review budget. |
| research_policy | COMBO | when_uncertain | When Hermes may research current H3 guidance. |
| videoopt | VIDEO | Source clip. Preferred input; carries its fps. | |
| framesopt | IMAGE | Alternative to video: an IMAGE batch. Set fps to match. | |
| fpsopt | FLOAT | 24.001–240 | Frame rate of the frames input. |
| audioopt | AUDIO | The clip's track, for a provider that can hear it (gemini). Becomes <Audio 1>. | |
| video_roleopt | COMBO | subject_source | What the wired video is FOR - this is what decides the task type, and wiring alone cannot imply it. subject_source: it just shows a subject, so it is cited inside that subject's line and gets no entry. structure_reference: its camera, cuts and rhythm are followed. edit_source: the target IS this video, edited. continuation_source: the target continues from where it ends. |
| audio_roleopt | COMBO | none | What the wired audio is FOR. reuse: the signal is copied into the target (adds 'audio reuse'). reference: only its timbre, style or beat is followed, not the signal (adds 'audio reference'). |
| cut_timesopt | STRING | Wire any Cut Detective output here. The shot list becomes ground truth for the [Shot N] times. A count mismatch is only an error when a video is being edited - otherwise the target's structure is not bound to the reference's. In base mode there is no source clip, so this reads as the shot structure you are asking for: more than one entry is what lets FL2VA write more than one shot. | |
| dialogueopt | STRING | Exact spoken words. They must reach a <d> block verbatim, or the run retries once. | |
| constraint_notesopt | STRING | Things that must not change. Folded into the prompt as positive assertions, because H3 has no negative field and the official format ends at non_diegetic_music - nothing may follow it. | |
| duration_overrideopt | FLOAT | 0.000–600 | 0 = use the clip's own duration. In a base mode with no clip this IS the target length: it reaches the instruction line as S.SS, and leaving it at 0 makes the node guess 5 seconds and warn. |
| max_frames_to_analyzeopt | INT | 82–16 | Keyframes sampled from the clip for the VLM. |
| seedopt | INT | 00–2147483647 | Passed to providers that support seeding. |
| subject_1_imageopt | IMAGE | Reference image for line 1 of the subjects field. This slot IS <Picture 1> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| subject_2_imageopt | IMAGE | Reference image for line 2 of the subjects field. This slot IS <Picture 2> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| subject_3_imageopt | IMAGE | Reference image for line 3 of the subjects field. This slot IS <Picture 3> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| subject_4_imageopt | IMAGE | Reference image for line 4 of the subjects field. This slot IS <Picture 4> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| subject_5_imageopt | IMAGE | Reference image for line 5 of the subjects field. This slot IS <Picture 5> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| subject_6_imageopt | IMAGE | Reference image for line 6 of the subjects field. This slot IS <Picture 6> - the numbers always match, so wire them in order from slot 1. In a base_* mode there are no subjects: slot 1 is the anchor frame, and slot 2 is FL2VA's last frame. | |
| base_picture_roleopt | COMBO | first_frame | Base mode only: whether a single wired picture is the FIRST frame or the LAST one. Nothing in the pixels says which, so it has to be declared. h3_mode already declares it too (base_I2VA is first, base_L2VA is last); this is the cross-check, and a disagreement warns and follows h3_mode. |
| fl2va_normalize_picture_tagsopt | BOOLEAN | false | base_FL2VA only. MiniMax's guide writes bare 'Picture 1' and 'Shot 1' for FL2VA, with no brackets, while I2VA and L2VA bracket both - in the instruction line AND in the body of its own worked example. Off reproduces that. On rewrites them to <Picture 1> and [Shot 1]. No validator can tell which generates a better video, so this exists to be A/B'd; the setting is recorded in analysis_json. |
| snap_duration_to_h3_gridopt | BOOLEAN | true | H3 renders whole frames on a 17k+5 grid at 24 fps, so it rounds a length UP: ask for 2.00 seconds and you get 2.33. On, the prompt states the length H3 really produces, and the length output matches it. Off keeps the requested number, so the prompt claims a shorter video than the one H3 makes. Both numbers are recorded in analysis_json. |
| subject_rowsopt | INT | 20–6 | How many subject rows to show. It only controls the node face: a row with anything typed in it is always used, and the count grows on its own when you wire an image or fill the last row. Up to 6. |
| subject_1_kindopt | COMBO | character | What subject_1_image / row 1 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_1_nameopt | STRING | Optional name for row 1, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_1_descriptionopt | STRING | What row 1 looks like: the features the target video must keep. Type here and this row becomes <Subject 1>, and subject_1_image becomes <Picture 1>. An empty row is not a subject. | |
| subject_2_kindopt | COMBO | environment | What subject_2_image / row 2 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_2_nameopt | STRING | Optional name for row 2, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_2_descriptionopt | STRING | What row 2 looks like: the features the target video must keep. Type here and this row becomes <Subject 2>, and subject_2_image becomes <Picture 2>. An empty row is not a subject. | |
| subject_3_kindopt | COMBO | character | What subject_3_image / row 3 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_3_nameopt | STRING | Optional name for row 3, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_3_descriptionopt | STRING | What row 3 looks like: the features the target video must keep. Type here and this row becomes <Subject 3>, and subject_3_image becomes <Picture 3>. An empty row is not a subject. | |
| subject_4_kindopt | COMBO | character | What subject_4_image / row 4 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_4_nameopt | STRING | Optional name for row 4, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_4_descriptionopt | STRING | What row 4 looks like: the features the target video must keep. Type here and this row becomes <Subject 4>, and subject_4_image becomes <Picture 4>. An empty row is not a subject. | |
| subject_5_kindopt | COMBO | character | What subject_5_image / row 5 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_5_nameopt | STRING | Optional name for row 5, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_5_descriptionopt | STRING | What row 5 looks like: the features the target video must keep. Type here and this row becomes <Subject 5>, and subject_5_image becomes <Picture 5>. An empty row is not a subject. | |
| subject_6_kindopt | COMBO | character | What subject_6_image / row 6 IS. character and environment are the two everyone needs; the rest are the guide's other reusable kinds. The kind picks the features the prompt asks for - a character gets face, hair and garments, an environment gets surfaces and light, a style gets grain and grade. |
| subject_6_nameopt | STRING | Optional name for row 6, e.g. 'Aria Voss' or 'the loading bay'. Blank is fine - MiniMax's own example names nobody. | |
| subject_6_descriptionopt | STRING | What row 6 looks like: the features the target video must keep. Type here and this row becomes <Subject 6>, and subject_6_image becomes <Picture 6>. An empty row is not a subject. | |
| music_videoopt | BOOLEAN | false | Write the prompt as a music video. non_diegetic_music becomes the lead audio section instead of 'N/A', overall_soundscape thins to what is audible under the track, cuts are described as landing on the beat, and performance to camera becomes the action. Put the sung words in lyrics and the track in music_description. |
| music_sourceopt | COMBO | auto | Where the music comes from. auto: the song is declared as <Audio 1> when audio is connected, on the assumption that the same file reaches H3. generate_score: H3 invents the track. reuse_audio_1: the track reaches H3 as <Audio 1> even with nothing wired here. Declaring the reuse is what adds 'audio reuse' to the task type. |
| lyricsopt | STRING | Exact sung words, in their original language. They must reach a <d>[Language] ...</d> block in the shot where they are heard, or the run retries once. Blank means the mouth moves to the music with no intelligible words - H3 invents nonsense syllables if you ask for singing without giving it any. | |
| music_descriptionopt | STRING | The track, for non_diegetic_music: genre, instrumentation, tempo or BPM, and how it develops. Example: 'downtempo synthwave, ~92 BPM, analog pad and gated drums, the filter opens into the chorus at the second cut'. Blank lets the model infer it from the attached audio, or from the visuals if there is none. | |
| visible_textopt | STRING | One exact visible-text literal per line. Whitespace on nonblank lines is preserved. | |
| hermes_base_urlopt | STRING | http://127.0.0.1:8642 | Root-only plain-HTTP loopback Hermes API URL. |
| timeout_secondsopt | INT | 90030–3600 | Hard wall-clock limit; timeout requests run stop. |
| poll_interval_secondsopt | FLOAT | 1.000.05–10 | Runs API polling interval. |
| strict_durationopt | BOOLEAN | false | Reject durations outside H3's official 4 to 15 second range. When off, warn and preserve V1-compatible output. |
| cleanup_policyopt | COMBO | delete_on_success | Cleanup/retention policy for this request's staged images. |
| hermes_provideropt | STRING | Optional Hermes route provider; blank uses gateway default. | |
| hermes_modelopt | STRING | Optional Hermes route model; blank uses gateway default. |
Outputs (18)
| Name | Type | Description |
|---|---|---|
| h3_prompt | STRING | The H3 prompt. |
| duration_seconds | FLOAT | Target duration. With snap_duration_to_h3_grid on this is the length H3 really produces, not the length asked for. |
| fps | INT | Frame rate of the source clip, rounded. |
| analysis_json | STRING | Everything the run decided, including both durations. |
| h3_checkpoint_hint | STRING | Which H3 checkpoint this prompt is written for. |
| ref_image_1 | IMAGE | Whatever you plugged into subject_1_image, untouched. Wire it to the sampler's ref_image_1 socket. A gap stays a gap: the prompt says <Picture 1> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_image_2 | IMAGE | Whatever you plugged into subject_2_image, untouched. Wire it to the sampler's ref_image_2 socket. A gap stays a gap: the prompt says <Picture 2> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_image_3 | IMAGE | Whatever you plugged into subject_3_image, untouched. Wire it to the sampler's ref_image_3 socket. A gap stays a gap: the prompt says <Picture 3> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_image_4 | IMAGE | Whatever you plugged into subject_4_image, untouched. Wire it to the sampler's ref_image_4 socket. A gap stays a gap: the prompt says <Picture 4> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_image_5 | IMAGE | Whatever you plugged into subject_5_image, untouched. Wire it to the sampler's ref_image_5 socket. A gap stays a gap: the prompt says <Picture 5> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_image_6 | IMAGE | Whatever you plugged into subject_6_image, untouched. Wire it to the sampler's ref_image_6 socket. A gap stays a gap: the prompt says <Picture 6> for this slot, so compacting it here is exactly the mismatch this node exists to stop. |
| ref_video | IMAGE | The clip as IMAGE frames, which is what the sampler's ref_video_ socket takes. Empty in base mode, which has no <Video 1>. |
| ref_video_audio | AUDIO | The wired audio, for when the clip's own track is reused. Connect this OR ref_audio, not both. Empty in base mode. |
| ref_audio | AUDIO | The same audio again, for when only its timbre or beat is referenced. Connect this OR ref_video_audio, not both. |
| width | INT | Sampler width: the video's framing if there is one, else the first wired picture's, on H3's canvas grid. |
| height | INT | Sampler height, from the same source as width. |
| length | INT | Frame count on H3's 17k+5 grid. Wire it to the sampler's length. |
| label_map | STRING | What each <Picture i> / <Video k> / <Audio j> tag will refer to once the sampler numbers them. Read it against the prompt. |