Skip to content

Fan-out Protocol

The standard procedure for shipping a validated workflow from one test account to all target accounts. Run this in order — do not skip or reorder steps.

When to fan out

A workflow is ready to fan out when it has been:

  1. Validated on the test account — typically 3 of 4 acceptable generations per prompt
  2. Visually QA passed — no AI-tell issues (extra fingers, melted faces, garbled limbs) across the test account's outputs
  3. Approved by the user for the test account specifically

If any of these are missing, keep iterating on the test account before fanning out.

The 8-step sequence

Step 1: Duplicate the workflow tab

One tab per target account. If the test was on Account A and you want to ship to Accounts B, C, D, E, duplicate Account A's tab 4 times and rename each duplicate to the target account.

Step 2: Reassign node IDs so every node in the file is globally unique

After duplication, every cloned tab will have the same node IDs as the source. Walk each non-source tab and give every node a fresh ID that does not collide with any other ID in the file.

Also rewrite every edge's source / target in that tab to the new IDs so internal wiring stays intact.

Standard scheme: per-tab integer offset. For tab index N (0 = source, 1, 2, 3...), add N * 100000 to every node ID and link reference in that tab. Deterministic, preserves ordering for diffs, makes the source tab a contiguous lookup.

Why globally unique IDs matter

Sheet-sync scripts, variant patchers, and the Generation Runner all key off node.id. Duplicate IDs across tabs force every tool to disambiguate by (tab, id) pairs, which is fragile — a wrong tab lookup silently edits the wrong node. Globally unique IDs make node.id a real primary key.

Verify before saving: len({n.id for tab in tabs for n in tab.nodes}) == total_node_count.

Step 3: Rename all nodes in each tab

Match the target avatar. Prefix node titles with the account code (e.g., "V4 Scene pre — Symptom Hook""Account-B Scene pre — Symptom Hook"). This is mechanical but catches orphaned references to the old account name.

Step 4: Swap the avatar character reference sheet

Set each account's character reference R2 URL on the avatar Media node in that tab. Pull the URLs from the avatar reference registry.

Step 5: Walk the per-avatar checklist

Apply each CUSTOMIZED item to the new tab's prompts (wardrobe, hand details, accessories, voice characteristics). Do NOT touch anything flagged STANDARD.

The checklist comes from the variant-creation phase (see Variants & Versioning). It has two columns:

STANDARD (do not change) CUSTOMIZED PER AVATAR (swap per account)
Base scene composition Avatar character reference sheet (R2 URL)
Camera angle, lighting direction Avatar name in node titles
Aesthetic / color palette Wardrobe / clothing description
Compliance rules Hand / watch / accessories detail
Product reference images Voice characteristics in Veo prompts
Script beats and story arc Dialogue wording and language (see Step 6)
Timing / word budgets Any account-specific setting or prop overrides

Beats are STANDARD; wording is CUSTOMIZED

The story structure — what each scene does, in what order, with what arc — stays the same across tabs. But the actual words coming out of each avatar's mouth get adapted in the next step. Two avatars hit the same beat saying very different things.

Step 6: Adapt dialogue to the avatar's archetype

Every avatar has an archetype — Amish/Mennonite farmer, Holistic Healer, Naturopathic Professional, Beauty creator, etc. The archetype defines:

  • Word choice — vocabulary, slang, formality, expressions the archetype would naturally use
  • Language — English vs Spanish (vs other), and the regional/cultural register inside that language
  • Persona references"my mom" vs "one of my patients" vs "my sister" vs "my grandmother" — whichever fits the archetype's life
  • Cultural register — a holistic healer says "the body heals itself when you give it the right tools"; a farmer says "this is what worked for my granddad"; a clinician says "in my practice we've seen..."
  • Energy and cadence — warm/grounded vs clinical/measured vs casual/relatable

The beats stay the same. The words don't.

What to do:

  1. Identify each tab's avatar archetype — read reference/accounts.md for the canonical archetype per account.
  2. Walk every dialogue Prompt node / dynamic dialogue row in the tab. For each line, ask: "Would this avatar actually say it this way?"
  3. Rewrite the wording to fit. Keep the beat (what the line does in the script — hook / problem / solution / proof / CTA) intact. Change vocabulary, sentence structure, persona references, and cultural register.
  4. Translate if the tab is in a different language. ES-2 / ES-3 tabs need Spanish dialogue, not English with a Spanish accent. Pass the dialogue + archetype + cultural context to the Script Writer in Mode 2 (translation).
  5. Re-apply previously-set per-avatar persona pivots. If a prior variant set EN-1 to say "one of my patients" instead of "my mom", that pivot needs to be reapplied on top of the new archetype dialogue — fan-out can clobber it. Check the variant checklist for documented per-account swaps.

Dialogue drift = silent fail

If you fan out a workflow and ship every account the same wording, the audience can tell. Native speakers of a different language reading machine-translated English will tune out. A holistic-healer avatar saying farmer phrases reads as fake. The dialogue-archetype mismatch is one of the most common silent-quality failures in fan-out — make this step explicit and don't skip it because the test-account dialogue "sounds fine."

Example — same beat, different archetypes:

Beat: Hook — symptom recognition

Avatar archetype Dialogue wording
Amish/Mennonite farmer (EN-1) "My grandpap used to swear by this when his knees acted up — and we work on our feet from sunup to sundown."
Holistic Healer (EN-3) "Most people don't realize their body's been screaming at them for years. Three signs your liver is asking for help."
Naturopathic Professional (EN-2) "In my practice I see this pattern weekly — and the bloodwork tells the same story every time."
Spanish Holistic Healer (ES-2) "Tu cuerpo lleva años pidiéndote ayuda y tú no lo escuchas. Esto es lo que pasa con el hígado."

Same scene number. Same beat. Completely different lines.

Step 7: Verify STANDARD items are byte-identical across tabs

After fan-out, run a quick diff of Prompt node text for anything in the STANDARD column. The diff should return empty. Any drift here is a bug.

Remember: dialogue Prompts and Dynamic dialogue rows are now CUSTOMIZED (per Step 6) — exclude those from the diff. STANDARD diff covers scene composition prompts, image template prompts, video template structure, and other shared structural content.

A quick check:

import json
data = json.load(open(p))
tabs = data['tabs']
source_tab = tabs[0]
for n in source_tab['graphData']['nodes']:
    if n.get('type') == 'nanobanana/Prompt' and not is_customized(n):
        source_text = n['properties']['text']
        for tab in tabs[1:]:
            matching = find_corresponding_node(tab, n)
            assert matching['properties']['text'] == source_text, \
                f"STANDARD drift in {tab['name']} on node {matching['id']}"

is_customized(n) returns True for dialogue Prompts/Dynamic nodes and any node flagged on the CUSTOMIZED side of the variant checklist for that workflow.

Step 8: Run a single test generation per tab

Not a full workflow run — a single test generation (one node, one row) per tab to sanity-check the avatar swap before committing to full production runs.

If the test gen looks right (correct face, correct wardrobe, no obvious drift), proceed to the full Generation Runner pass for that tab.

The "if I want to change a STANDARD item" rule

If during fan-out you find yourself wanting to change a STANDARD item because it "reads better" for one account, stop. Either:

  • (a) Promote that change to STANDARD and apply it to all tabs uniformly, or
  • (b) Move it to the CUSTOMIZED list and document why this account needs the override.

Never silently diverge a single tab from the standard. Silent divergence makes the workflow impossible to maintain — future variant patches assume STANDARD items are shared, and silent drift breaks that assumption.

After fan-out

The fan-out itself bumps the version (it's a "meaningful change" under the versioning rules).

Specifically:

  • During testing: V0-N → V0-N+1 (fan-out is still part of the testing phase)
  • After approval: when the user explicitly approves the fan-out AND all accounts ship clean → graduate to V1

Record the fan-out in the version registry with a history note like "fan-out to Accounts B, C, D, E" — be specific, not vague.

File layout reminder

A multi-account workflow lives in one .nbflow file with multiple tabs, NOT split into per-account files.

  • File: {workflow}-{version}.nbflow (e.g. XYZG1-V0-3.nbflow)
  • Tabs: one per account, naming = account code (e.g. "Account A", "Account B")
  • Order: test account first, fan-out accounts after

If you find yourself splitting into per-account files, you're working against the system — the single-file pattern is the source of truth and what the Generation Runner, sheet sync, and variant patcher all assume.