The bot writes the scripts and STOPS. You record the avatars in HeyGen; when you’re done, open the gate and it downloads, assembles the 9:16 reels, and delivers them to each channel.

This is the repo for domain of the flow /promoavatar of the inemaccbot. There isn’t a single line of TypeScript here — only the flow.json, the prompts, and the chat help. A new workflow is an entry in the bot’s registry plus a repo like this one.
There are 12: pessoacomum · jovens · profissionais · mulheres · empreendedores · tecnicos · 40mais · 60mais · educadores · criadores · recolocacao · familia. Each has its own channel and hook.
The bot stops after the text (before spending on the avatar) and after the download (before spending on the render). Disagreeing with a script at the gate costs a rewritten text, not 12 avatars recorded by hand.
flow.json, prompts, and options are frozen when the workflow is created. Editing applies to FUTURE ones — not even /refazer gets the change.
Four phases and two gates. The gates are the "pausa_apos": true of the phases texto e baixar in the flow.json — the pipeline stops there on its own and only proceeds when you approve.
One script per audience, recorded in textos/A<N>/<publico>.md. The chat sends you each script along with the video’s exact TITLE. Gate 1 right after.
Normally you, in the HeyGen studio. There are 5 routes for this phase — the table below.
Finds the video in HeyGen by title and downloads the MP4 — with the caption burned in if the studio recorded it with one, clean if not. 90-minute window. Gate 2 afterward.
Build the 9:16 reel (an impactful cover with the audience’s trigger) and delivery directly into that audience’s channel folder. There is no separate publishing phase.
The four automated ones are phases with the key opcional in the flow.json. The fifth is the absence of all of them.
No flags are enabled. You record in HeyGen and the bot has no idea how — it just waits for the /aprovar.
Phase estudio (opcional: estudio). The bot opens/prepares the studio; you finish.
Phase gerar (opcional: api). The BOT generates — using HeyGen’s prepaid wallet, ~US$ 1 per minute.
Phase gerar-creditos (opcional: creditos). Same generation, consuming credits.
Phase navega-avatar (opcional: navega). LLM agent cloning the TEMPLATE-AVATAR. The most expensive route: ~17.8k tokens per audience, ~214k in workflow 12.
O title. For any route, the video must be named A<N>-<publico>-v1. On the manual route, this is 100% your responsibility.
Documented in chat: | api e | estudio. The flags for creditos e navega exist as a phase in the flow.json but aren’t in the HELP.md — confirm before using.
Are stored in templates/. All 1080×1920, background #0E1116, amber accent #F5A623.
Top: 704px image + headline. Middle: 608px avatar (audio). Base: 608px text panel (hook). The high-impact cover — the original format.
Same, but the base becomes the explainer video of that speech, muted and on a loop. Use when the explainer exists as a video.
Half and half: 960px image on top, 960px avatar on the bottom. No third track. Good for myth vs. reality and comparisons, where the image carries the contrast.
The image fills the frame; the avatar goes into a crop in the top-right. The footer is prohibited: the network interface covers the bottom corner, and the avatar would not appear.
Phase 1 writes the line Formato escolhido: in each <publico>.md (the prompt’s ZERO STEP), and the templates/mapa.json translate. In the real A#19, this gave 9 different formats for 12 audiences — a real variation, with no one deciding anything at render time.
# precedence (resolved by preparar.py)
--template explícito
› template do ALVO no flow.json
› mapa.json
› template da raiz do flow.json
Each track declares a fonte: imagens, avatar, texto or explicativo. A headline goes at the top; the hook goes in the base panel. Layout with base and hook missing = black base — it was A#23, with hook in 0 of 8 images. That’s why the prompt says to write hook always, even in layouts without a base.
This repo doesn’t run anything on its own — the bot reads it. What you need is the bot running, a HeyGen account, and the channel folders.
The bot runs the flow, with this repo declared in config/fluxos.json.
# in the authorized chat /fluxos /promoavatar help
This is where you record the avatars, during the break between phases 1 and 2. The download matches by the video's exact name.
# the title is the contract A<N>-<publico>-v1 # e.g.: A8-mulheres-v1
The audience’s channel becomes a folder based on a derived rule — the path isn’t written down anywhere.
# create a new channel mkdir -p ~/projetos/yt-pub-lives33/imports/videos
All commands are typed in the Telegram chat with the authorized bot.
| sombra prints phase × audience × queue × task and doesn’t queue anything. Running all 12 audiences means 12 avatars recorded by hand — normally, you filter.
/promoavatar Não comece aprendendo ferramentas | sombra
All 12 go through without filtering. To test cheaply, use just one audience. The | e o -- coexist—but a field entered without either one is REJECTED; it doesn’t silently become a topic.
/promoavatar <assunto> # the 12 audiences /promoavatar <assunto> | alvos=mulheres # cheap for testing /promoavatar <assunto> --alvo=jovens --alvo=40mais /promoavatar <assunto> | legenda # default is WITHOUT caption
An open-ended topic (“is this good or bad?”) made the agent explain both sides and end lukewarm — and nobody comments on a fence-sitter. Now the prompt tells it to take a clear side and say which one in the summary. The position you specify takes precedence over its own, so writing your own is still the best approach.
# best: your position + a concrete fact + the question # what you want in the comments
The bot sends each script in the chat and STOPS. This is where disagreeing is cheap: /refazer costs one text, not a render.
/status A#7 # phase × audience, and the titles /refazer A#7 mulheres # just the audience that didn’t turn out well
In the studio, the video must be named exactly A<N>-<publico>-v1. The download matches by exact string equality: a different name means the video is never found, and the phase expires in 90 minutes. The chat sends you the title ready to use precisely so you don’t have to type it from memory.
A7-mulheres-v1 A7-jovens-v1 # the avatar caption is decided HERE: record with it, and the reel # it comes with it — and there’s no way to remove it afterward. In that case, # create the flow WITHOUT | caption, or you’ll get two.
“I’m done with my part.” The bot then downloads the videos, assembles the reels, and delivers them to each channel.
/aprovar A#7 # synonyms: /pronto, /aprovado, /ok
If an audience fails, redo only that one—its attempts are reset. Canceling applies to the pipeline: what has already been created in the studio stays there.
/status A#7 /refazer A#7 mulheres /cancelar A#7 [publico]
The rule: decisions about the audience or campaign belong in this repo; brand visual identity belongs in the skill. The skill is global — changing it affects EVERY reel, including those triggered directly in chat.
The channel and hook for each audience, how the scripts are written, what this pipeline asks of the reel, the closing CTA clip, and help from the chat.
flow.json # targets.<audience>.channel / .trigger prompts/fase1-texto.md # how the scripts are written cta/cta-9x16.mp4 # replace the file HELP.md # /promoavatar help
How the reel is ASSEMBLED (colors, fonts, positions, SFX) is handled by the global skill; queues, timeouts, model, and effort are handled by the bot.
# skill (global — changes the entire brand) ~/.claude/skills/reel-edita-inema/SKILL.md # bot inemaccbot/prompts/reel.md inemaccbot/config/skills.json
Improve the reel, from cheapest to most expensive: replace the clip from cta/ → adjust the entrega of the flow.json → and only then edit the skill.
The domain says for whom (mulheres has "canal": "lives4"); the bot knows where — always ~/projetos/yt-pub-<canal>/imports/videos. Never put a path in the flow.json.
Who decides the avatar’s caption is the studio: the download grabs the subtitled version when available, and the clean version when it isn’t. The option | legenda is another one — it's the one our editor draws. Turning both on makes two; and burned-in captions are framed for 16:9, with no way to remove them afterward.
The four things you’ll most want to change. They all follow the same constraint: what matters is what existed when the flow was created — editing applies to FUTURE ones, and not even /refazer gets the change.
File: prompts/fase1-texto.md. It is the entire document that phase 1 delivers to the agent — FIXED CONTEXT, STEP ZERO, HOOK WORKSHOP, the 16 WRITING RULES, and the output contract.
Two pitfalls: the 11 formats from STEP ZERO are keys of the templates/mapa.json — renamed it here, rename it there. And the five variables injected by the bot must not disappear:
{{input}} # the topic
{{publicos}} # the flow’s REAL targets
{{pasta}} # where to record (absolute)
{{ref}} {{saida}}
The skill inemaclub-textos provides the structure of the file; this prompt provides the rules and overrides the skill. Change the structure in the skill—and it applies to everyone.
a) change what a layout looks like → edit templates/<nome>.json. Three rules:
y + altura of the tracks have to close 1920 (y is absolute positioning; they don't stack by themselves — a missing strip means a black strip). The fonte is what feeds the strip: imagens · avatar · texto (o hook) · explicativo. E escurecer is the veil beneath the headline: too low, and the text disappears against the light parts of the photo.
b) change which format goes into which layout → templates/mapa.json. The keys exist with and without accents, on purpose:
"mito versus realidade": "diptico", "comparação": "diptico", "comparacao": "diptico"
A format outside the map falls back to the root default — don’t invent a layout. c) To lock in an audience’s layout, use the field template within the target.
File: flow.json, key alvos.
"empreendedores": {
"canal": "lives1",
"gatilho": "Transforme IA em redução de custos…",
"template": "diptico" # optional
}
O gatilho is that audience's pain point (prompt rule 2 says to use it). Adding means one more entry; removing means delete it. To run just a few without changing anything, use --alvo= during creation.
The key is a contract, not a label: it becomes the file textos/A<N>/<publico>.md, the title A<N>-<publico>-v1, o --alvo of the reel and the seed-key of the images. Lowercase, no accents, no spaces, and without a hyphen — that's why pessoa-comum became pessoacomum.
There’s no path written down anywhere: the destination is derived from the canal of the audience.
<canal> → ~/projetos/yt-pub-<canal>/imports/videos
To change the channel = edit alvos.<publico>.canal. Creating a new channel = creating the folder, that’s all:
mkdir -p ~/projetos/yt-pub-lives33/imports/videos
Two audiences can share the same channel. Changing the rule (the base folder, the imports/videos) isn’t here — é o destinos.ts of the bot, and changes all flows. For a one-off reel outside the flow, use montar-reel.py --saida <caminho>.
This repo is domain: it declares the pipeline. Whoever runs é o inemaccbot. Looking here for something that belongs there is the most common waste of time — the list below is exactly what no is in this repo.
/promoavatar, /status, /aprovar, /refazer, /cancelar and the | e -- belong to the bot. Here, only the HELP.md, which is the HELP TEXT — not its code.
Queues (texto, io, navegador, render), retries, timeouts, freezing during creation, and the very concept of a gate. The flow.json only declares; the bot is the one that follows it (inemaccbot/config/skills.json).
heygen.*heygen.gerar, heygen.estudio, heygen.baixar are names of functions that live in the bot (inemaccbot/src/fila/tarefas/heygen.ts) — including the escolherUrl, which decides between the captioned and clean MP4.
state/artefatos/fluxos/A<N>/ is in the BOT repo, not here. That’s where the downloaded avatars land.
~/projetos/yt-pub-<canal>/imports/videos is a rule derived by the bot. The path isn't written anywhere — only the channel name exists here.
Colors, fonts, positions, silence trimming, and SFX are handled by the global skill ~/.claude/skills/reel-edita-inema/SKILL.md. Changing that affects EVERY reel for the brand, including those triggered directly in chat.
The rule of thumb: if the answer changes the behavior of all the flows, not from here. If only promoavatar changes, it’s from here.
Phase 3 calls scripts/montar-reel.py. You can run it directly, outside the bot — useful for redoing a reel without spending a workflow.
--avatar # required: the HeyGen MP4 --ws # required: the reel workspace --alvo # audience; becomes the image seed-key --textos # the <audience>.md (## IMAGES section) --template # layout override (takes precedence over everything) --flow --mapa # where to resolve the template and map --qualidade # high (default) · standard · draft --cta --sem-cta # the closing clip --pular-preparo # reuses the --ws setup --saida # MP4 destination
preparar.py has the same ones, plus --explicativo, --sem-imagens, --sem-transcricao e --sem-montar.
# standard reel — layout comes from the map python3 scripts/montar-reel.py \ --avatar A34-jovens-v1.mp4 \ --ws /tmp/ws-A34-jovens --alvo jovens \ --textos textos/A34/jovens.md --flow flow.json # cheap draft, just to check the framing ... --qualidade draft --sem-cta # force the layout, ignoring the map ... --template imagem-plena # change the CTA without regenerating the image ... --pular-preparo --saida saida/A34-jovens.mp4