Vídeo com IA: Claude Code, Codex e ElevenLabs · Capítulo 10 de 25 · 27 min
Paralelizar cenas com subagentes sem estourar o limite das APIs
Rode três cenas em paralelo com subagentes e o Agent SDK e espace as chamadas com backoff para que um erro 429 não derrube nem encareça o lote inteiro.
Este capítulo faz parte do curso gratuito Vídeo com IA: Claude Code, Codex e ElevenLabs.
Gerar as cenas de um vídeo uma depois da outra desperdiça tempo quando elas não dependem entre si: a abertura não precisa esperar o preparo, e o fechamento não precisa esperar nenhuma das duas. Disparar tudo de uma vez também cobra seu preço. Um serviço de voz ou de vídeo responde com o erro 429, o aviso de que você passou do limite de pedidos, e um laço de repetição mal escrito multiplica a conta em vez de resolver.
Nesta aula você divide o trabalho entre subagentes, especialistas com ficha própria que recebem só o briefing da cena e devolvem o resultado ao agente diretor. Você escreve o especialista em arquivo, dispara três cenas em paralelo pelo Agent SDK em TypeScript e em Python, fixa profundidade, concorrência e teto de gasto, e monta um despachante que espaça as chamadas e faz só a cena recusada esperar.
Com isso o lote fica previsível. O tempo cai porque três tarefas correm juntas, e o custo não dispara porque cada limite está escrito no código, e não na esperança de que a API aguente.

Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Separar cenas independentes e fixar os limites
Pense no subagente como um assistente de produção com crachá: ele recebe a tarefa, trabalha numa janela de contexto separada (a memória de trabalho daquela conversa, que não se mistura com a do diretor) e devolve só o resultado. O diretor é a sessão principal, e ela precisa da ferramenta Agent para delegar. No Claude Code, cada especialista é um arquivo .md em .claude/agents/, que vale para o projeto, ou em ~/.claude/agents/, que vale para todos os seus projetos. O passo a passo de iniciante está no curso de configuração, em dividir tarefas grandes entre Claudes ajudantes.
Para rodar a mesma delegação de dentro de um programa, use o Agent SDK, a biblioteca que coloca o motor do Claude Code no seu código: o laço de trabalho, as ferramentas, a gestão de contexto, os hooks, os subagentes e o MCP. Ele existe em Python (claude_agent_sdk) e em TypeScript (@anthropic-ai/claude-agent-sdk), e a visão geral está na aula sobre o Claude Agent SDK do curso de agentes. Quem paga cada execução depende de como o SDK se autentica, e a seção antes da bancada mostra as três fontes.
Antes de delegar, confira se as cenas são de fato independentes. Abertura, preparo e fechamento podem ser escritos em paralelo depois que o roteiro e a duração de cada um estão aprovados, como no desenho do pipeline. A montagem final continua em sequência, porque todas as cenas acabam no mesmo arquivo. Três controles limitam a operação, e os valores do exercício são escolhas didáticas, não recomendação universal.
Os três limites da delegação e o valor usado no exercício
| Controle | Padrão documentado | No exercício |
|---|---|---|
| Profundidade (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH) | 3 níveis | 1 nível |
| Concorrência (CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS) | 20 ao mesmo tempo | 3 ao mesmo tempo |
| Teto do SDK (maxBudgetUsd ou max_budget_usd) | Sem limite | US$ 3 no total |
O maxBudgetUsd conta só a chamada atual; numa sessão retomada, o total_cost_usd soma também o gasto anterior. Para dezenas ou centenas de agentes, a documentação indica a ferramenta Workflow, no SDK TypeScript v0.3.149 ou mais novo, com 16 agentes simultâneos por padrão (CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS). Em 12/10/2026, o SDK vigente é a 0.3.296 em TypeScript e a 0.2.165 em Python. Não é preciso neste exercício.
Fonte: Claude Agent SDK, página de subagentes, em 09/10/2026; changelogs do SDK e documentação de workflows, em 12/10/2026.
Comece pelo arquivo do especialista. O cabeçalho entre as linhas --- funciona como crachá: name é o nome que o diretor chama, description diz quando usar, tools lista o que ele pode tocar e model escolhe o modelo (opus, sonnet, haiku, fable ou inherit, que herda o do diretor). Liste as ferramentas de forma explícita, para que o especialista não receba mais do que a cena pede. Um único arquivo atende as três cenas, porque o briefing muda e a ficha continua a mesma.
---
name: cenarista
description: Escreve a especificação JSON de UMA cena curta de vídeo a partir do briefing recebido. Use para abertura, preparo ou fechamento quando roteiro e duração já estiverem aprovados.
tools: Read
model: sonnet
---
Você é cenarista de vídeo em português do Brasil, com acentuação completa.
Entrada: o briefing de uma cena (id, duração em segundos e objetivo) e,
se existir, o arquivo roteiro/roteiro.md, que você pode ler.
Saída: somente um objeto JSON, sem cercas Markdown, com os campos
id (o mesmo do briefing)
duracao_s (número inteiro, igual ao briefing)
texto_tela (até 6 palavras)
descricao_visual (até 40 palavras, o que a câmera mostra)
Regras:
- Não invente medidas, temperaturas nem instruções de segurança alimentar.
- Não gere mídia, não chame serviços externos e não delegue a outro agente.
- Não escreva arquivos: quem grava o resultado é o diretor.
- Se o briefing estiver incompleto, devolva {"erro": "motivo"} e pare.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Disparar as três cenas pelo Agent SDK
A bancada abaixo roda na raiz video-ia, instala o SDK nas duas linguagens e grava os limites do exercício como variáveis de ambiente. Ela pressupõe Node.js, Python e a chave da API configurados como na bancada da aula 3. Registre a versão instalada do SDK: o comportamento de eventos e de erros muda entre versões, e o seu log precisa dizer qual rodou.
#!/usr/bin/env bash
# Prepara a bancada da aula 10 na raiz video-ia (macOS, Linux ou WSL).
set -euo pipefail
# O catálogo da aula 01 prova que você está na pasta certa.
test -f config/catalogo.json || { echo "Entre na pasta video-ia antes de continuar." >&2; exit 1; }
mkdir -p .claude/agents scripts
# TypeScript: SDK oficial, executor tsx e tipos do Node.
test -f package.json || npm init -y
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev typescript tsx @types/node
npm ls @anthropic-ai/claude-agent-sdk # anote a versão instalada no README do projeto
# Python: o mesmo SDK, em ambiente virtual próprio.
python3 -m venv .venv
. .venv/bin/activate
pip install claude-agent-sdk
pip show claude-agent-sdk | head -2 # anote a versão também
# Limites do exercício: até 3 especialistas ao mesmo tempo, um nível só.
export CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=3
export CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1
# Chave da API só no ambiente deste terminal, nunca no chat nem no git.
if [ -z "${ANTHROPIC_API_KEY:-}" ]; then
read -r -s -p "Chave Anthropic: " ANTHROPIC_API_KEY
printf '\n'
export ANTHROPIC_API_KEY
fi
echo "Pronto. Salve .claude/agents/cenarista.md, scripts/pipeline-cenas.ts e scripts/pipeline_cenas.py."
O mesmo diretor com três especialistas, em duas linguagens
TypeScript
Salve como scripts/pipeline-cenas.ts e execute na raiz com npx tsx scripts/pipeline-cenas.ts. Os especialistas vão na opção agents. A opção tools deixa o diretor só com a ferramenta Agent, e allowedTools apenas aprova essa ferramenta sem perguntar. O próprio SDK já repete sozinho pedidos recusados ao modelo, até 14 requisições por chamada desde a versão 2.1.286; a segunda tentativa do script só entra quando a execução termina com erro 429 mesmo assim.
// scripts/pipeline-cenas.ts: o diretor delega três cenas a especialistas, em paralelo.
// Produz especificações JSON; não gera mídia. Execute na raiz video-ia: npx tsx scripts/pipeline-cenas.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
const TETO_TOTAL_USD = 3; // política do exercício, somando todas as tentativas
const MAX_TENTATIVAS = 2; // a segunda só acontece se a primeira morrer por limite (429)
const ESPERA_BASE_MS = 5_000;
const PEDIDO = [
"Prepare três cenas independentes de 5 segundos para um vídeo de receita em pt-BR:",
"abertura, preparo e fechamento.",
"Delegue cada cena ao especialista de mesmo nome, em paralelo.",
"Cada especialista devolve JSON com id, duracao_s, texto_tela e descricao_visual.",
"Não crie outros agentes. Reúna as três respostas num array JSON sem reescrevê-las.",
"Se algum especialista falhar, diga qual e pare.",
].join(" ");
// Um especialista por cena; sem ferramentas, ele só pensa e devolve texto.
const especialista = (cena: string, modelo: "sonnet" | "haiku") => ({
description: `Cria a cena ${cena} de cinco segundos.`,
prompt:
`Retorne apenas o JSON da cena ${cena}: id "${cena}", duracao_s 5, ` +
"texto_tela (até 6 palavras) e descricao_visual (até 40 palavras). " +
"Não invente medidas culinárias. Não use ferramentas nem delegue.",
tools: [] as string[],
model: modelo,
maxTurns: 3,
});
type Desfecho = "ok" | "limite" | "erro";
async function executarUmaVez(tentativa: number): Promise<Desfecho> {
const inicio = Date.now();
let desfecho: Desfecho = "erro";
try {
for await (const msg of query({
prompt: PEDIDO,
options: {
model: "claude-opus-5-5",
tools: ["Agent"], // disponibilidade: o diretor só enxerga a ferramenta Agent
allowedTools: ["Agent"], // permissão: aprova a delegação sem perguntar
maxBudgetUsd: TETO_TOTAL_USD / MAX_TENTATIVAS, // US$ 1,50 por tentativa
env: {
...process.env,
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS: "3",
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH: "1",
},
agents: {
abertura: especialista("abertura", "sonnet"),
preparo: especialista("preparo", "sonnet"),
fechamento: especialista("fechamento", "haiku"),
},
},
})) {
// Registra tipo e tempo de cada evento, sem imprimir prompt nem credencial.
const s = ((Date.now() - inicio) / 1000).toFixed(1);
console.log(`[tentativa ${tentativa} | ${s}s] evento: ${msg.type}`);
if (msg.type === "rate_limit_event") {
console.log("Aviso de limite da sessão:", msg.rate_limit_info.status);
}
if (msg.type === "result") {
console.log("Estado:", msg.subtype, "| erro:", msg.is_error, "| custo informado (US$):", msg.total_cost_usd);
if (msg.subtype === "success" && !msg.is_error) {
console.log(msg.result);
desfecho = "ok";
} else if (msg.subtype === "success" && msg.api_error_status === 429) {
desfecho = "limite"; // a última chamada ao modelo terminou em 429
}
// Sem return: o laço segue até o fim para a exceção posterior chegar ao catch.
}
}
} catch (erro) {
// Depois de um resultado de erro, o query() de mensagem única lança de propósito.
console.warn("query() encerrou com erro:", erro instanceof Error ? erro.message : String(erro));
}
return desfecho;
}
async function main(): Promise<void> {
if (!process.env.ANTHROPIC_API_KEY) throw new Error("Defina ANTHROPIC_API_KEY no ambiente.");
for (let tentativa = 1; tentativa <= MAX_TENTATIVAS; tentativa++) {
const desfecho = await executarUmaVez(tentativa);
if (desfecho === "ok") return;
// Qualquer outro desfecho para na hora: repetir às cegas só multiplica a conta.
if (desfecho === "erro" || tentativa === MAX_TENTATIVAS) {
throw new Error(`Execução sem resultado válido na tentativa ${tentativa}.`);
}
const espera = ESPERA_BASE_MS * 2 ** (tentativa - 1) + Math.random() * 1_000;
console.warn(`Limite de requisições; nova tentativa em ${(espera / 1000).toFixed(1)} s.`);
await new Promise((r) => setTimeout(r, espera));
}
}
main().catch((erro) => {
console.error("Execução interrompida:", erro instanceof Error ? erro.message : String(erro));
process.exitCode = 1;
});
Python
Salve como scripts/pipeline_cenas.py e execute na raiz com python3 scripts/pipeline_cenas.py, com o ambiente virtual ativo. Os nomes mudam para o padrão do Python (allowed_tools, max_budget_usd), e cada especialista é um AgentDefinition. Quando a execução termina em erro, o query() de mensagem única levanta uma exceção depois de entregar o resultado, por isso o laço lê o resultado primeiro e trata a exceção em seguida.
"""scripts/pipeline_cenas.py: o diretor delega três cenas a especialistas, em paralelo.
Produz especificações JSON; não gera mídia. Execute na raiz video-ia: python3 scripts/pipeline_cenas.py
"""
import asyncio
import os
import random
from claude_agent_sdk import (
AgentDefinition,
ClaudeAgentOptions,
RateLimitEvent,
ResultMessage,
query,
)
TETO_TOTAL_USD = 3.0 # política do exercício, somando todas as tentativas
MAX_TENTATIVAS = 2 # a segunda só acontece se a primeira morrer por limite (429)
ESPERA_BASE_S = 5.0
PEDIDO = (
"Prepare três cenas independentes de 5 segundos para um vídeo de receita em pt-BR: "
"abertura, preparo e fechamento. Delegue cada cena ao especialista de mesmo nome, "
"em paralelo. Cada especialista devolve JSON com id, duracao_s, texto_tela e "
"descricao_visual. Não crie outros agentes. Reúna as três respostas num array JSON "
"sem reescrevê-las. Se algum especialista falhar, diga qual e pare."
)
def especialista(cena: str, modelo: str) -> AgentDefinition:
"""Um especialista por cena; sem ferramentas, ele só pensa e devolve texto."""
return AgentDefinition(
description=f"Cria a cena {cena} de cinco segundos.",
prompt=(
f'Retorne apenas o JSON da cena {cena}: id "{cena}", duracao_s 5, '
"texto_tela (até 6 palavras) e descricao_visual (até 40 palavras). "
"Não invente medidas culinárias. Não use ferramentas nem delegue."
),
tools=[],
model=modelo,
)
def opcoes() -> ClaudeAgentOptions:
return ClaudeAgentOptions(
model="claude-opus-5-5",
tools=["Agent"], # disponibilidade: o diretor só enxerga a ferramenta Agent
allowed_tools=["Agent"], # permissão: aprova a delegação sem perguntar
max_budget_usd=TETO_TOTAL_USD / MAX_TENTATIVAS, # US$ 1,50 por tentativa
env={
"CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS": "3",
"CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "1",
},
agents={
"abertura": especialista("abertura", "sonnet"),
"preparo": especialista("preparo", "sonnet"),
"fechamento": especialista("fechamento", "haiku"),
},
)
async def executar_uma_vez(tentativa: int) -> str:
"""Devolve "ok", "limite" (a execução terminou em 429) ou "erro"."""
desfecho = "erro"
try:
async for msg in query(prompt=PEDIDO, options=opcoes()):
print(f"[tentativa {tentativa}] evento: {type(msg).__name__}")
if isinstance(msg, RateLimitEvent):
print("Aviso de limite da sessão:", msg.rate_limit_info.status)
if isinstance(msg, ResultMessage):
print("Estado:", msg.subtype, "| erro:", msg.is_error,
"| custo informado (US$):", msg.total_cost_usd)
if msg.subtype == "success" and not msg.is_error:
print(msg.result)
desfecho = "ok"
elif msg.subtype == "success" and msg.api_error_status == 429:
desfecho = "limite" # a última chamada ao modelo terminou em 429
# Sem return: o laço segue até o fim para a exceção posterior aparecer.
except Exception as erro:
# Depois de um resultado de erro, o query() de mensagem única levanta de propósito.
print(f"query() encerrou com erro: {erro}")
return desfecho
async def main() -> None:
if not os.environ.get("ANTHROPIC_API_KEY"):
raise SystemExit("Defina ANTHROPIC_API_KEY no ambiente.")
for tentativa in range(1, MAX_TENTATIVAS + 1):
desfecho = await executar_uma_vez(tentativa)
if desfecho == "ok":
return
# Qualquer outro desfecho para na hora: repetir às cegas só multiplica a conta.
if desfecho == "erro" or tentativa == MAX_TENTATIVAS:
raise SystemExit(f"Execução sem resultado válido na tentativa {tentativa}.")
espera = ESPERA_BASE_S * 2 ** (tentativa - 1) + random.uniform(0, 1)
print(f"Limite de requisições; nova tentativa em {espera:.1f} s.")
await asyncio.sleep(espera)
if __name__ == "__main__":
asyncio.run(main())
Leia o log antes de comemorar. Cada evento aparece com o tempo decorrido, e o último traz o estado, o custo informado pelo SDK e o array com as três cenas. Se o tempo total parece curto, isso ainda não prova paralelismo: procure na sessão os três especialistas chamados. Repare também na diferença entre duas listas parecidas. allowedTools só aprova sem perguntar: as ferramentas que ficam de fora continuam disponíveis e passam pelo fluxo de permissão. Quem tira ferramentas do alcance é tools, que deixa no contexto só as ferramentas nativas listadas, ou disallowedTools, que bloqueia pelo nome. Nenhuma delas é caixa de areia do sistema operacional, e tools não remove ferramentas de servidores MCP. Aqui a proteção vem do diretor com tools igual a Agent, dos especialistas com tools vazio e de um pedido que não envolve shell nem geração de mídia. Um 429 dentro de um especialista também não derruba a execução do diretor: ele volta como falha daquele especialista, e o pedido manda o diretor dizer qual falhou e parar. Se surgir pedido de ferramenta inesperado, não aprove.
Espaçar as chamadas e esperar quando vier 429
O limite de 3 especialistas controla a concorrência, quantos trabalhos estão ativos ao mesmo tempo, como o número de caixas abertos num supermercado. Ele não controla a taxa, quantos pedidos começam por segundo ou por minuto, como os clientes que passam pela porta. O serviço de voz ou de vídeo conta a taxa (o RPM de cada conta), e três trabalhadores rápidos podem disparar dez pedidos num segundo. O curso de APIs explica a lógica do outro lado do balcão em limite de requisições e controle de vazão.
Quando o serviço recusa com 429 (a leitura desse erro está na bancada da aula 3), só a cena recusada espera e tenta de novo, com o backoff que a aula de orquestração detalha; as outras seguem ocupando as vagas. O teto do SDK também não serve de limite de cobrança da fal, da Replicate ou da ElevenLabs: cada fornecedor tem a própria cota por conta, e ela entra no seu registro antes de ligar a geração real.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Despachante, custo e vídeo longo
Semáforo sozinho contra despachante completo
Semáforo sozinho contra despachante completo
Só o semáforo de 3 vagas
Coluna a evitar
- Três trabalhos ativos, mas sem espaço entre os inícios
- Um 429 faz a cena repetir na hora e levar outro 429
- Repetir a execução inteira refaz as cenas que já tinham dado certo
- Timeout de geração paga vira um segundo pedido cobrado
Semáforo, espaçador e backoff
Coluna recomendada
- Até 3 ativos e pelo menos 0,5 s entre dois inícios
- A cena recusada espera um intervalo crescente fora da vaga
- Só a cena afetada repete; as outras seguem
- Timeout de geração paga consulta o job antes de qualquer novo pedido
O despachante abaixo aplica as duas ideias. Ele é inteiramente local e usa um serviço de mentira, que recusa o preparo na primeira tentativa pedindo 1 s de espera. Ele não representa o que o SDK faz por dentro com as chamadas ao modelo. É o molde do código que você vai pôr na frente de qualquer serviço externo pago. Fila persistente, cache e retomada ficam para a aula de orquestração.
"""scripts/despachar_cenas.py: limita a concorrência, espaça os inícios e espera em 429.
Simula um serviço externo (voz, imagem ou vídeo) sem gastar crédito.
Execute na raiz video-ia: python3 scripts/despachar_cenas.py
"""
import asyncio
import random
import time
CONCORRENCIA = 3 # trabalhos ativos ao mesmo tempo (política do exercício)
INTERVALO_S = 0.5 # espaço mínimo entre dois inícios (política do exercício, não cota)
MAX_TENTATIVAS = 4
ESPERA_BASE_S = 1.0
ESPERA_MAX_S = 20.0
INICIO = time.monotonic()
# Falhas de mentira para o teste: (cena, tentativa) -> espera pedida pelo serviço, em s.
FALHAS_SIMULADAS = {("preparo", 1): 1.0}
class Erro429(Exception):
"""Resposta Too Many Requests; retry_after é a espera que o serviço pediu, se pediu."""
def __init__(self, retry_after=None):
super().__init__("429 Too Many Requests")
self.retry_after = retry_after
class Espacador:
"""Garante INTERVALO_S entre dois inícios, venham de qual cena vierem."""
def __init__(self, intervalo):
self.intervalo = intervalo
self.proxima = 0.0
self.lock = asyncio.Lock()
async def esperar(self):
async with self.lock:
agora = time.monotonic()
if self.proxima > agora:
await asyncio.sleep(self.proxima - agora)
self.proxima = time.monotonic() + self.intervalo
def espera_backoff(tentativa, retry_after):
"""Obedece ao retry_after do serviço; sem ele, dobra a espera e soma um sorteio."""
if retry_after is not None:
return float(retry_after)
base = min(ESPERA_MAX_S, ESPERA_BASE_S * 2 ** (tentativa - 1))
return base + random.uniform(0, base / 2) # jitter: as cenas não voltam juntas
def agora():
return f"{time.monotonic() - INICIO:5.2f}s"
async def chamar_servico(cena, tentativa):
"""Troque este corpo pela chamada real quando a cota da sua conta estiver anotada.
Um 429 recusa o pedido antes do trabalho e pode ser repetido. Um timeout depois
de enviar uma geração paga deixa dúvida: consulte o job conhecido antes de repetir.
"""
print(f"{agora()} início {cena} (tentativa {tentativa})")
await asyncio.sleep(1.2) # duração simulada do trabalho
if (cena, tentativa) in FALHAS_SIMULADAS:
raise Erro429(retry_after=FALHAS_SIMULADAS[(cena, tentativa)])
return {"cena": cena, "arquivo": f"storyboard/cenas/{cena}.json", "tentativas": tentativa}
async def executar(cena, semaforo, espacador, estado):
for tentativa in range(1, MAX_TENTATIVAS + 1):
try:
async with semaforo: # vaga entre as CONCORRENCIA disponíveis
await espacador.esperar() # e o espaço mínimo entre inícios
estado["ativos"] += 1
estado["pico"] = max(estado["pico"], estado["ativos"])
try:
return await chamar_servico(cena, tentativa)
finally:
estado["ativos"] -= 1
except Erro429 as erro:
if tentativa == MAX_TENTATIVAS:
raise
espera = espera_backoff(tentativa, erro.retry_after)
# A espera acontece fora do semáforo: a vaga fica livre para outra cena.
print(f"{agora()} 429 {cena}: aguardando {espera:.1f}s")
await asyncio.sleep(espera)
async def main():
semaforo = asyncio.Semaphore(CONCORRENCIA)
espacador = Espacador(INTERVALO_S)
estado = {"ativos": 0, "pico": 0}
cenas = ["abertura", "preparo", "fechamento"]
resultados = await asyncio.gather(
*(executar(c, semaforo, espacador, estado) for c in cenas),
return_exceptions=True, # uma cena com falha não derruba as outras
)
for cena, r in zip(cenas, resultados):
print(f"{cena:<11} {'erro: ' + str(r) if isinstance(r, Exception) else 'ok'}")
assert estado["pico"] <= CONCORRENCIA, "concorrência acima do limite"
print("Pico simultâneo:", estado["pico"])
if __name__ == "__main__":
asyncio.run(main())
Troque o cenarista para o Haiku 5.5 e meça
O briefing de uma cena tem poucos milhares de tokens, e o cenarista não precisa do raciocínio do diretor. O Haiku 5.5, lançado em 07/10/2026, custa US$ 0,10 por milhão de tokens de entrada e US$ 0,50 de saída até 100 mil tokens de prompt, um vigésimo do Sonnet 5.5, e é o primeiro Haiku com effort, o nível de esforço de raciocínio. Desde a versão 2.1.293, o alias haiku aponta para ele, e desde a 2.1.292, de 06/10/2026, a ferramenta Agent aceita effort por chamada: o diretor pode mandar cada cena com esforço baixo.
Grave a variante abaixo ao lado do cenarista, rode as três cenas com ela e compare, no resultado final do SDK, o campo modelUsage, que separa tokens e custo por modelo. Fica pronto quando os três JSON passam na mesma validação da versão Sonnet e o custo por cena cai. Se uma cena voltar fora do formato duas vezes, devolva só essa cena ao Sonnet, em vez de subir o esforço de todas.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
---
name: cenarista-haiku
description: Versão barata do cenarista para cenas curtas com briefing completo. Use quando roteiro e duração já estiverem aprovados.
tools: Read
model: haiku
effort: low
---
Mesma entrada, mesma entrega e mesmas regras do cenarista, em português do Brasil
com acentuação completa: devolva só o objeto JSON com id, duracao_s, texto_tela
(até 6 palavras) e descricao_visual (até 40 palavras).
- Não invente medidas, não gere mídia, não escreva arquivos e não delegue.
- Se o briefing estiver incompleto, devolva {"erro": "motivo"} e pare.
Saiba quem paga a bancada do SDK
A conta muda conforme a forma de entrar. Logado pela assinatura, o SDK e o claude -p consomem os limites do seu plano: a Central de Ajuda da Anthropic, atualizada em 07/10/2026, informa que a mudança anunciada em 15/06 para esse uso foi pausada. Com a chave de uma organização vinculada a um plano Max ou Team, a execução sai dos créditos mensais de API incluídos desde 07/10/2026: US$ 100 no Max 5x, US$ 200 no Max 20x, US$ 20 por assento Standard e US$ 100 por assento Premium no Team, com teto de US$ 500. Com uma chave avulsa, sai da carteira da organização, por token.
Os créditos cobrem Messages API, Batches, Agent SDK e claude -p com a chave vinculada; não cobrem o Claude Code interativo, extensões de IDE, o app Desktop nem Bedrock, Vertex e Foundry. Eles não acumulam de um mês para o outro e exigem 7 dias no plano. Antes de rodar a bancada, confira no Console se a chave do terminal é a da organização vinculada. Deu certo quando o consumo do teste sai dos créditos, e não da carteira.
Se a figura ultrapassar a área visível, deslize para os lados. Pelo teclado, foque a figura e use as setas.
Leve o desenho para um vídeo longo, capítulo por capítulo
O mesmo desenho escala de cenas para capítulos. No curso Vibe Viral, do Vibehub, um vídeo falado com gráficos de 29:37 virou 14:52 com um agente por capítulo em paralelo, um auditor independente por capítulo e um piloto dos 3 primeiros minutos antes do resto; um vídeo de 25 minutos levou cerca de 5 horas de máquina. Faça o piloto primeiro: se ritmo ou legenda não passam nele, nenhum capítulo começa. O auditor recebe o capítulo pronto e a ficha de edição, nunca a conversa do editor, para não herdar os mesmos pontos cegos. Quando um ajuste mexe num capítulo só, renderize só ele e junte de novo.
- Etapa 1 de 5: Corte global
retakes e pausas saem antes de tudo
- Etapa 2 de 5: Piloto de 3 minutos
aprovado antes de qualquer capítulo
- Etapa 3 de 5: Um editor por capítulo
em paralelo, com a mesma ficha
- Etapa 4 de 5: Um auditor por capítulo
separado de quem editou
- Etapa 5 de 5: Render só do que mudou
e junção final em sequência
No laboratório a seguir, quatro agentes trabalham em raias, um principal e três de trabalho, trocando mensagens numa linha do tempo. Repare na diferença entre o tempo de parede, do início ao fim da cena, e a soma das barras: é exatamente o ganho do paralelismo, e também o motivo pelo qual vários agentes juntos pressionam o mesmo serviço.
Ver agentes em paralelo trocando mensagens numa linha do tempo
Reproduza a cena, percorra o tempo pelo controle e compare o tempo de parede com a soma das barras de cada agente.
Demonstração de quatro agentes em raias, um principal e três de trabalho, numa linha do tempo com barras de execução por agente e mensagens que passam de raia em raia, inclusive uma revisão que devolve um trecho. A leitura compara o tempo de parede com a soma das barras, o mesmo raciocínio que separa concorrência de taxa no despachante de cenas desta aula.
A demonstração interativa carrega quando este trecho entra na tela.
Testar a delegação e decidir quando reduzir o paralelismo
Quatro situações pedem decisão. Se duas tarefas escrevem no mesmo arquivo, separe as saídas ou rode essa etapa em sequência. Se aparecer 429, reduza a pressão (menos vagas ou mais espaço entre inícios) e obedeça à espera que o serviço informar. Se um timeout acontecer depois de enviar uma geração paga, consulte o job conhecido antes de criar outro. Se o custo encostar no teto, interrompa e peça decisão a uma pessoa, em vez de trocar de modelo em silêncio.
Na Cozinha da Rafa, canal de receitas de Recife com três vídeos por semana, abertura, preparo e fechamento do bolo de rolo saem em paralelo pelo cenarista, cada um no próprio JSON. A montagem do longo 16:9 e dos cortes 9:16 continua sequencial, depois que a Rafa aprova as três cenas, para que um agente não altere o arquivo do outro.
Rodar três cenas em paralelo com limites escritos
Rode tudo na raiz video-ia. Só o passo 6 roda sem chave, porque é local.
Passo 1: Escreva o especialista em .claude/agents/cenarista.md
Cabeçalho com name, description, tools: Read e model: sonnet; corpo com o formato JSON e as proibições.
Deu certo quando: O Claude Code mostra o cenarista entre os subagentes do projeto numa sessão nova.
Erro comum: Deixar ferramentas de escrita ou shell no especialista que só precisa ler o roteiro.
Passo 2: Confirme que as três cenas não dependem uma da outra
Deu certo quando: Cada especialista consegue trabalhar apenas com o próprio briefing.
Erro comum: Delegar cenas antes de roteiro e duração estarem aprovados.
Passo 3: Fixe profundidade 1, concorrência 3 e teto de US$ 3
Deu certo quando: Os três valores aparecem escritos no código e no ambiente.
Erro comum: Deixar o padrão de 20 subagentes simultâneos sem avaliar a necessidade.
Passo 4: Execute o script do SDK uma vez, em TypeScript ou Python
Deu certo quando: O último evento traz estado, custo informado e um array com as três cenas.
Erro comum: Rodar de novo a execução inteira porque uma resposta demorou.
Passo 5: Inspecione a delegação efetiva no log
Deu certo quando: Os três especialistas aparecem chamados na mesma sessão.
Erro comum: Deduzir paralelismo só porque o tempo total pareceu curto.
Passo 6: Rode o despachante local e leia o 429 simulado
python3 scripts/despachar_cenas.py, sem chave e sem custo.
Deu certo quando: Inícios a 0,5 s ou mais um do outro, pico de 3 ativos e só o preparo repetindo.
Erro comum: Confundir o semáforo de concorrência com um limitador de RPM.
Passo 7: Registre o limite real de cada fornecedor antes de ligar geração paga
Deu certo quando: Fornecedor, conta, unidade do limite e cota anotados no README do projeto.
Erro comum: Levar o intervalo didático de 0,5 s para produção como se fosse oficial.
No fim você tem: Três especificações de cena em JSON, custo do SDK registrado, despachante aprovado e as cotas externas marcadas como pendentes até serem anotadas.
Guia prático: ficha completa do subagente e guarda na saída
O cenarista da aula usa quatro campos do cabeçalho. A ficha aceita mais: skills pré-carregadas, servidor MCP só daquele especialista, teto de turnos, execução em segundo plano e cópia isolada do repositório. Aqui você cria um pesquisador de modelos que é o único a enxergar a fal e põe um hook que confere o JSON de cada cena quando o cenarista termina e, se vier fora do formato, devolve a correção ao próprio especialista.
Funções, casos de uso e aplicações
Funções
Campos da ficha do subagente e o hook de saída
| Função ou recurso | O que faz | Quando usar | Desde |
|---|---|---|---|
| skills | Injeta o conteúdo inteiro das skills listadas quando o subagente começa | Cenarista que já nasce com a ficha modelo-receita-16x9 da aula 08 | 08/10/2026 (v2.1.295, no máximo 32 skills, cada uma uma vez) |
| mcpServers | Servidor MCP por referência ou definição própria, só para aquele subagente | Deixar a fal só com o pesquisador de modelos; não funciona em subagente de plugin | Em vigor em 12/10/2026 |
| maxTurns | Teto de turnos; a saída volta marcada como parcial e pode ser retomada | Pesquisa que tende a se estender: quatro turnos bastam para buscar e cotar | Em vigor em 12/10/2026 |
| background e Ctrl+B | Mantém o subagente em segundo plano; os pedidos de permissão aparecem na sessão principal com o nome dele | Cotar modelos enquanto você revisa o storyboard | Em vigor em 12/10/2026 |
| isolation: worktree | Roda numa cópia temporária do repositório git, apagada se nada mudar | Especialista que edita composicoes/ sem pisar no arquivo de outro | Em vigor em 12/10/2026 |
| Hook SubagentStop com matcher pelo nome | Roda quando o subagente termina; saída 2 manda o stderr de volta como próxima instrução e ele continua | Conferir o JSON do cenarista antes de o diretor receber | Em vigor em 12/10/2026 |
| autoCompactWindow | Faz o subagente resumir a conversa antes da janela da sessão principal | Revisor de capítulo longo que lê muitos quadros | 09/10/2026 (v2.1.296) |
O campo omitClaudeMd: true, da v2.1.271, deixa o subagente sem os CLAUDE.md; e CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL, de 09/10/2026, põe todos os agentes da ferramenta Workflow num modelo só, sem mudar os outros subagentes.
Fonte: Claude Code Docs, Create custom subagents e Hooks reference; changelog v2.1.295 e v2.1.296; 12/10/2026
Casos de uso
Diretor de uma produtora de Reels para uma rede de academias em Recife
Marketing digital, vídeos curtos
Dor
Com a fal ligada na sessão principal, o diretor às vezes propunha gerar cenas enquanto só deveria dividir o roteiro, e a pergunta de permissão aparecia no meio da revisão.
Solução
Ele tirou a fal da sessão principal e criou o pesquisador-de-modelos com mcpServers apontando para ela, ferramentas só de consulta, quatro turnos e execução em segundo plano.
Resultado
O que observar: nas próximas cinco produções, se alguma proposta de geração saiu do diretor e se as cotações chegaram antes do fim da revisão do storyboard.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Editora de um curso preparatório online de Brasília que produz 20 aulas curtas por mês
Educação, aulas em vídeo
Dor
Uma em cada dez cenas voltava do cenarista com texto antes do JSON, e o script de montagem quebrava no meio do lote.
Solução
Ela ligou o hook SubagentStop com o nome do cenarista: quando a saída não é JSON com os quatro campos, o hook devolve a correção ao especialista, uma vez só, antes de o diretor receber.
Resultado
O que observar: ao fim do mês, quantas montagens quebraram por formato e quantas vezes o hook pediu correção, lendo o registro do lote.
Cenário construído para fins didáticos. Números não correspondem a cliente específico.
Na prática
As duas peças rodam no projeto video-ia. O pesquisador referencia o servidor fal do .mcp.json da aula 09 e só lista as ferramentas de consulta em tools, então gerar fica fora do alcance dele. Tire fal do enabledMcpjsonServers do settings.json se quiser a sessão principal sem a fal. O hook confere a última mensagem do cenarista e, para não entrar em laço, deixa passar a segunda tentativa: o campo stop_hook_active chega verdadeiro quando o subagente já foi devolvido uma vez.
---
name: pesquisador-de-modelos
description: Pesquisa e cota modelos de vídeo na fal para uma cena aprovada. Use quando a cena precisa de b-roll gerado e ainda não há modelo escolhido.
tools: Read, mcp__fal__search_models, mcp__fal__get_model_schema, mcp__fal__get_pricing
mcpServers:
- fal
model: haiku
effort: low
maxTurns: 4
background: true
color: orange
---
Você cota modelos para UMA cena, em português do Brasil com acentuação completa.
Entrada: storyboard/cenas/<cena>.json, que você pode ler.
Saída: tabela com fornecedor, ID exato do modelo, duração, preço e unidade de cobrança,
no máximo cinco linhas, chamando get_pricing uma vez com todos os IDs.
- Não gere mídia e não peça para gerar: quem decide é a pessoa.
- Descarte preview com data de saída anunciada.
- Se faltar preço, escreva [conferir]."""Hook SubagentStop do cenarista. Saída 2 devolve o stderr ao subagente como próxima instrução."""
import json
import sys
CAMPOS = {"id", "duracao_s", "texto_tela", "descricao_visual"}
dados = json.load(sys.stdin)
if dados.get("stop_hook_active"):
sys.exit(0) # já foi devolvido uma vez: deixa o diretor decidir, sem laço
texto = (dados.get("last_assistant_message") or "").strip()
try:
cena = json.loads(texto)
except ValueError:
print("Devolva só o objeto JSON da cena, sem texto em volta nem cercas Markdown.", file=sys.stderr)
sys.exit(2)
if isinstance(cena, dict) and "erro" in cena:
sys.exit(0) # o próprio contrato permite devolver {"erro": "motivo"}
faltando = CAMPOS - set(cena) if isinstance(cena, dict) else CAMPOS
if faltando:
print(f"Faltam os campos {sorted(faltando)}. Devolva o JSON completo.", file=sys.stderr)
sys.exit(2)
if len(str(cena["texto_tela"]).split()) > 6:
print("texto_tela passou de 6 palavras. Encurte e devolva o JSON.", file=sys.stderr)
sys.exit(2)
sys.exit(0){
"hooks": {
"SubagentStop": [
{
"matcher": "cenarista|cenarista-haiku",
"hooks": [
{
"type": "command",
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/validar_cena.py\"",
"timeout": 10
}
]
}
]
}
}Ligar o pesquisador e a guarda de saída
Passo 1: Teste o hook sem o agente
echo '{"last_assistant_message":"Aqui está: {}"}' | python3 .claude/hooks/validar_cena.py; echo $?
Deu certo quando: A saída é 2 e a mensagem pede só o objeto JSON.
Erro comum: Testar só com JSON correto e não ver o caminho de correção.
Passo 2: Rode as três cenas como na aula
Deu certo quando: Cada arquivo de storyboard/cenas/ é JSON válido com os quatro campos.
Erro comum: Esquecer o matcher da versão Haiku e deixar a variante sem guarda.
Passo 3: Chame o pesquisador para a cena de preparo
Peça: use o pesquisador-de-modelos para cotar b-roll da cena preparo.
Deu certo quando: Ele roda em segundo plano, devolve a tabela e nenhum job aparece na conta da fal.
Erro comum: Aprovar na sessão principal um pedido de ferramenta que não está na lista dele.
Passo 4: Confira os limites no /agents
Deu certo quando: O pesquisador mostra modelo haiku, quatro turnos e só as ferramentas de consulta.
Erro comum: Digitar um campo com erro, que o Claude Code ignora em silêncio; rode claude --debug para ver o aviso.
No fim você tem: Fal restrita ao pesquisador, cenas conferidas na saída e o diretor livre de pedidos de geração.
Armadilhas
Cada especialista com o mínimo que a tarefa pede
O campo omitido herda tudo da sessão principal, então ferramentas, servidores e turnos devem estar escritos na ficha.
- Sem tools, o subagente herda todas as ferramentas disponíveis.
- Campo com nome errado é ignorado sem erro: confira no claude --debug.
- isolation: worktree exige repositório git; sem commit, a cópia não tem os arquivos novos.
- Hook SubagentStop sem stop_hook_active pode devolver o subagente sem fim.
- Em plugin, mcpServers, hooks e permissionMode da ficha não valem.
O teste: Peça ao pesquisador para gerar a cena: ele deve recusar porque run_model não está na ficha.
alexandrecaramaschi.com/educacao/frontends-com-vibecoding
Rode a delegação e o despachante nesta ordem e guarde os dois logs em logs/. Está pronto quando existem três arquivos de cena válidos, o custo informado pelo SDK está anotado com a fonte que pagou (assinatura, créditos mensais ou carteira), a comparação entre Sonnet e Haiku está registrada, o despachante mostra no máximo três trabalhos ativos com inícios espaçados, e cada fornecedor externo tem a cota da sua conta registrada ou marcada como pendente.
Seu caderno neste capítulo
Abrir o caderno completoSelecione um trecho do capítulo para destacar ou anotar. Nos vídeos e áudios, use Anotar este momento. No teclado, selecione com Shift e as setas e use Alt+Shift+D para destacar ou Alt+Shift+N para anotar.
Salvo neste navegador. Entre na sua conta para levar o caderno a outros aparelhos.
Entre na sua conta para compartilhar o que aprendeu e convidar alguém para estudar com você.
Conexões deste capítulo
Veja o que estudar antes e para onde seguir depois, explore os conceitos e compare abordagens em outros cursos. Sugestões marcadas como “sugerido pelo grafo” vêm dos assuntos em comum, não do índice do curso.
Estude antes
- CursoClaude Code CLI: Programação com IA
- Primeiro Workflow no n8nsugerido pelo grafoApresenta o conceito “Workflow”, usado em “Paralelizar cenas com subagentes sem estourar o limite das APIs”.
- Agent Mode: a IA que executa sob supervisãosugerido pelo grafoApresenta o conceito “Agent”, usado em “Paralelizar cenas com subagentes sem estourar o limite das APIs”.
- CursoAstra profundosugerido pelo grafoA quinta parte do Astra planeja o vídeo e edita o material bruto com o modelo dirigindo a ferramenta. O curso de vídeo com IA aprofunda esse trabalho com Claude Code, Codex e ElevenLabs, do roteiro à publicação. O grafo já sugeria esta ordem pela regra de entrada da trilha; com a ordem anterior curada, ela passa a ser declarada (Etapa 4, wave 3).
Depois, siga para
- Claude Agent SDKsugerido pelo grafoApresenta o conceito “SDK”, usado em “Claude Agent SDK”.
- Monitoramento e observabilidadesugerido pelo grafoApresenta o conceito “SDK”, usado em “Monitoramento e observabilidade”.
- Guardrails e segurançasugerido pelo grafoApresenta o conceito “SDK”, usado em “Guardrails e segurança”.
- MCP (Model Context Protocol)sugerido pelo grafoApresenta o conceito “SDK”, usado em “MCP (Model Context Protocol)”.
Conceitos deste capítulo
O mesmo assunto em outros cursos
- Bastidores: Como Este Portal Foi ConstruídoAgentes em worktrees: produção em paraleloExaminar conexões de Agentes em worktrees: produção em paralelo
- Agentes de IA Autônomos: Do Conceito à ProduçãoClaude Agent SDKExaminar conexões de Claude Agent SDK
- Frontends com VibecodingEspecificar, medir e produzir as cenas da máquinaExaminar conexões de Especificar, medir e produzir as cenas da máquina
- Skills de IA com Vibecoding e TerminalOrquestração Persistente: OpenClaw e Agentes que Vivem 24/7Examinar conexões de Orquestração Persistente: OpenClaw e Agentes que Vivem 24/7
Voltar ao capítulo anterior: Conectar fal, Replicate e ElevenLabs por MCP com permissões mínimas
Leve uma ideia para a prática
Escolha uma atividade no painel e volte a este curso quando quiser.
Atividades e evolução ficam reunidas no painel da sua conta.
Laboratórios ao vivo deste curso
Cada laboratório monta a biblioteca real dentro da aula, com controles para você mexer e o código do exemplo para copiar. O texto de reserva descreve a demonstração para quem lê sem JavaScript. O link abre o capítulo já no ponto do laboratório.
MediaRecorder, Canvas 2D e Long Animation Frames (plataforma)
Grave a cena em tempo real e veja os quadros que se perdem
Suba as partículas, force um bloqueio de 300 ms e grave seis segundos; compare com o render quadro a quadro desta aula.
Pacote
Abrir no capítuloMontar vídeo em HTML com HyperFrames e escolher entre ele e o Remotionsem pacoteMotion
Ver agentes em paralelo trocando mensagens numa linha do tempo
Reproduza a cena, percorra o tempo pelo controle e compare o tempo de parede com a soma das barras de cada agente.
Pacote
Abrir no capítuloParalelizar cenas com subagentes sem estourar o limite das APIsmotionReact (sem dependência extra), com as APIs do Veo e do fal.ai
Prompt de vídeo em cinco camadas, pronto para a API
Escolha plano, câmera, luz, ação e áudio e copie o prompt e o JSON para o Veo ou para o fal.ai.
Pacote
Abrir no capítuloEscrever prompt de vídeo em cinco camadas e manter o personagem consistentereactReact (sem dependência extra), com o comando para o FFmpeg
Corte o vídeo apagando palavras da transcrição
Aperte as palavras para removê-las, ligue a remoção de pausas e copie o comando FFmpeg e a legenda SRT gerados.
Pacote
Abrir no capítuloRemover pausas e reenquadrar o vídeo de 16:9 para 9:16 com legenda por palavrareactReact (sem dependência extra)
Quanto custa cada etapa do seu pipeline de vídeo
Troque a ferramenta de cada etapa e o percentual de b-roll e veja qual etapa pesa no custo por minuto e por vídeo.
Pacote
Abrir no capítuloOrquestrar o pipeline com etapas idempotentes e teto de gastoreact
Capítulos vizinhos em Vídeo com IA: Claude Code, Codex e ElevenLabs
- 08Instalar e invocar skills de vídeo no Claude Code
- 09Conectar fal, Replicate e ElevenLabs por MCP com permissões mínimas
- 10Paralelizar cenas com subagentes sem estourar o limite das APIs
- 11Revisar quadros com a visão do Claude e uma rubrica escrita
- 12Configurar o Codex com GPT-6 Astra num sandbox que pede aprovação