Curso · produto
Alembic — Casos de uso ponta a ponta
Três jornadas ponta-a-ponta
Cada lição anterior abriu um bloco do motor; esta é o capstone. Três walkthroughs reais — (a) o fluxo da holding (corpus → distill → BUSINESS SIGNALS → uma venture), (b) uma campanha de cliente (descoberta → brief → campanha dry-run), e (c) contratar um AI Employee — mostram que os mesmos comandos do CLI alembic, encadeados pela disciplina offline-default + --online gated, fazem o motor virar produto. Nada de novo: só composição. Tudo verificável contra REVIEW.md e os pacotes que você já leu.
Os três casos compartilham uma régua: cada passo tem um output observável, e qualquer cruzamento para gasto real é marcado em vermelho como founder-gated. Você pode rodar todas as etapas brancas (offline, $0, determinístico) num laptop sem internet. As etapas vermelhas precisam de chaves, créditos ou aprovação explícita — e por construção o CLI nunca cruza esse limite sem flag duplo.
Caso (a) — o fluxo da holding
Meta: partir de uma pasta de conhecimento bruto (transcripts, bookmarks, repos clonados) e chegar em duas coisas operacionais — um store de LEARNINGS citáveis e um store de BUSINESS SIGNALS que viram candidatos a venture. É o porquê do Alembic existir: como diz o REVIEW.md, "o motor é interno; as ventures que rodam sobre ele é que são o produto para fora". O laço completo:
1. Confira o motor
$ alembic doctor --client-stack
[OK] model-registry: 11 model(s) validated
summary: 2 ok, 0 warn, 0 fail
doctor --client-stack valida o MODEL_REGISTRY de packages/contracts/src/registry.ts e a coerência dos adapters — sem rede, sem custo. Se o motor não passa aqui, nada à frente faz sentido rodar. Saída completa coberta em overview.
2. Destile o corpus
$ alembic distill ~/Documents/Resources --offline
distill: ~/Documents/Resources
T0: 1284 scored, 102 residue, 18 excluded
T1: 612 extracted, 4 pii-blocked
T2: 178 shortlisted, 12 budget-blocked
T3: 41 verified
emitted: 41 opportunity, 612 learnings
cost: $0
Esses números são o formato real de renderDistill em commands.ts — exatamente as cinco linhas que o funil imprime quando termina. As contagens acima são ilustrativas (o seu corpus terá outras), mas o shape é fixo: T0 (scored / residue / excluded), T1 (extracted / pii-blocked), T2 (shortlisted / budget-blocked), T3 (verified), e o consolidado de opportunity + learnings emitidos. Pacotes envolvidos: @alembic/etl (o funil em si), @alembic/ingestion (varre a árvore, aplica isExcluded), @alembic/contracts (o FunnelReport). Detalhes em funnel.
--offline primeiro. A flag default-on faz cada estágio do funil escolher o adapter LOCAL determinístico. O resultado é spend-safe ($0 garantido) e reproduzível (mesmo corpus → mesmo manifest). Você rodar distill ao vivo (sem --offline) é opt-in: passa pelo preflightLiveProvider (linha 290 de commands.ts) e falha-fechado se o gateway não responder. A entrada gated da ingestão real do wiki — o "run real ~330GB" que REVIEW.md marca como 🔴 founder-gated — é exatamente este flip, em escala.
3. Veja o saldo dos stores
$ alembic status
status: default tier T4 · phases: discover -> validate -> design -> plan -> build -> review -> ship · stores: 41 opportunity, 612 learnings
runStatus conta os dois stores append-only via readOpportunityRecords e readLearnings (de @alembic/etl). Stores ausentes lêem zero — o comando nunca quebra. O "default tier T4" é o lembrete de que toda fase chega no humano por padrão (ADR-0004). As phases são literalmente o factoryPhaseSchema.options de @alembic/contracts.
4. Pegue um BUSINESS SIGNAL e vire uma venture
Esta é a transição que o REVIEW.md chama de "propósito do motor": um signal escolhido manualmente vira um escopo, e o escopo vira uma missão. O caminho proven do mês:
# Passo 4.1 — Forge a partir de uma pergunta-âncora derivada do signal
$ alembic forge "fábrica de documentos jurídicos personalizados para escritórios de previdência"
scope: /tmp/alembic-forge-… (GOAL.md + alembic.plan.ts + validation-contract.md)
# Passo 4.2 — Rode a missão sob o pipeline de gates
$ alembic run --goal GOAL.md --plan alembic.plan.ts --yes
run-id: r-… (Scope · Council · Proof · Validator · Publish)
alembic forge materializa o escopo (front-end de 7 passos coberto em factory-forge-course). alembic run compila o alembic.plan.ts via @alembic/vm (que rejeita Date.now() / Math.random() — determinismo é hard), dispara o swarm (swarm-harness), e cada unit.proof[] vira um task que falha-fechado se o exit code for não-zero. Tarefas T4 param e esperam alembic approve --task-id <id> — o portão humano. Foi exatamente assim que a 1ª venture jurídica (a "Previdência Factory") foi construída num repo irmão (REVIEW.md § "cross-repo").
O que cada passo prova
doctorprova que o registry de modelos está coerente — pré-requisito de qualquer cruzamento online.distillprova que o corpus passa pelos 4 tiers do funil sem PII vazada e sem estourar budget; produz dois stores citáveis.statusprova que os stores ficaram materializados (e quantificáveis) — auditável por outro agente sem rerun.forge+runprovam que um signal vira código com gates, não com fé: cada milestone só fecha quando o Proof Gate e o Validator Gate assinam.
Caso (b) — uma campanha de cliente (C.D Advocacia)
Meta: de uma requisição mínima ({cliente, ask}) até um manifest de campanha versionado, com cost preview, em uma única invocação --dry-run $0. Geração real (com créditos do Higgsfield) só com dois flags simultâneos. O REVIEW.md documenta esta fluxo como "D1 → D4" (#91–#94, Fase 6). Pacote pivot: @alembic/marketing-factory — todo o detalhe está em marketing-factory.
1. Escreva a requisição mínima
$ cat > cd-request.json <<'JSON'
{
"client": { "name": "C.D Advocacia", "website": "https://cd.adv.br" },
"ask": "vídeo vertical cinematográfico em pt para reels"
}
JSON
Esse é o formato exato do REQUEST usado nos testes de packages/marketing-factory/src/discover.test.ts — discoverClientBrief precisa só desses dois campos. O resto (industry, audience, competitors, viralityHypotheses) é descoberto: offline fica honestamente vazio; --online chama o seam de pesquisa (Bright Data) para preencher.
2. Discover — brief offline ($0)
$ alembic marketing discover cd-request.json
marketing discover: C.D Advocacia
brief: /tmp/cd-brief.json
video: cinematic 9:16 (pt)
provenance: offline-request
runMarketingDiscover em commands.ts:2511 chama discoverClientBrief sem o seam de pesquisa (porque sem --online ele fica como undefined) e devolve um ClientBrief validado. O parseAsk deriva video.aspect = 9:16, video.type = cinematic, video.language = pt diretamente das palavras do ask — determinístico. provenance.source = offline-request é a honestidade que ADR-0009 exige: tudo que não foi observado fica vazio, nunca fabricado.
3. Campaign — one-shot dry-run ($0)
$ alembic marketing campaign cd-request.json --out cd-campaign.json
marketing campaign: C.D Advocacia (dry-run, $0)
result: cd-campaign.json
video: cinematic 9:16 (pt)
model: glm-5.2 creatives: 1 kept: 1
provenance: offline-request dryRun: true
validation plan: aspect 9:16, transcript true
cost (if real): 36 credits
runMarketingCampaign (commands.ts:2890) é o one-shot da Fase 6: ele encadeia discoverClientBrief → briefToSignal + briefToFactoryOptions → runMarketingFactory (offline, com fakeHiggsfieldCli) → validationPlan → costEstimate. Tudo numa chamada, sem cliente Higgsfield real, sem rede. O bloco cost (if real) é o preview que torna o passo seguinte uma decisão consciente.
4. Geração real — gated por DOIS flags
# Apenas --approve OU apenas --yes → continua dry-run ($0). Sem efeito.
$ alembic marketing campaign cd-request.json --approve
# A ÚNICA combinação que cruza para o Higgsfield real:
$ alembic marketing campaign cd-request.json --online --approve --yes
Olhe a linha 2900 de commands.ts: const paid = args.approve && args.yes;. Não é convenção — é estrutural. Quando paid é false, o CLI instancia fakeHiggsfieldCli; quando é true, createHiggsfieldCli({ binary: 'higgsfield' }). Não há caminho de código que passe um flag só e gaste crédito. Isso é o que REVIEW.md resume como "spend-safe por construção".
O que cada passo prova
discoverprova que a parte determinística do brief (formato de vídeo, idioma) sai da própria requisição — sem rede, sem custo.campaign --dry-runprova que todo o pipeline (brief → signal → factory → validation plan → cost preview) roda offline, com manifest auditável.- O par
--approve --yesprova que o gasto real é consentimento explícito duplo; nenhum flag isolado escapa. - O
validation planresultante é o input domarketing validatesobre o mp4 final — gate de pronúncia e formato (a memóriamarketing-factory-supercomputer-campaignmostra que esse gate já pegou todos os 6 vídeos reais da C.D, na primeira execução).
Caso (c) — contratar e rodar um AI Employee
Meta: definir um employee em JSON, inspecionar como ele seria executado (sem custo), rodar um turno como preview ($0), e só então cruzar para --online com escrita de memória. Todo o ciclo de vida em uma única superfície de CLI. Pacote pivot: packages/hermes/src/employee/ (lição cheia em AI Employee).
1. Defina o employee em JSON
$ cat > ~/.alembic/employees/iris.json <<'JSON'
{
"id": "iris",
"soul": {
"name": "Iris",
"role": "customer support specialist",
"coreValues": ["empathy", "precision"],
"modelPreferences": { "primary": "claude-opus-4-8" }
},
"skills": ["issue-triage", "meeting-notes"],
"memory": { "agentId": "iris", "stores": ["episodic", "semantic"] },
"connectors": ["gmail", "slack"],
"schedule": [{ "task": "daily inbox sweep", "cron": "0 9 * * *" }]
}
JSON
Esse é o employeeDefinitionSchema verbatim de packages/hermes/src/employee/employee.ts — id + soul embutido + skills (ids opacos) + binding de memória (5 stores possíveis) + connectors (nomes em A1) + schedule (cron opaco). O dir default é ~/.alembic/employees (--dir sobrescreve).
2. Listar e descrever (read-only, $0)
$ alembic employee list
iris Iris (customer support specialist) skills:2 connectors:2
$ alembic employee connectors iris
employee: iris connectors (offline — no adapters wired)
- gmail: unwired (no adapter)
- slack: unwired (no adapter)
note: real adapters founder-gated
$ alembic employee schedule iris
employee: iris schedule → @alembic/automation manifests
- emp-iris-0 [PAUSED] cron "0 9 * * *" model claude-opus-4-8
task: daily inbox sweep
Três comandos read-only, $0, sem rede. connectors é honest-unwired por design (offlineConnectorProvider devolve undefined para todo id) — adapters OAuth reais ficam fora do seam e são founder-gated. schedule traduz cada entrada para um manifest @alembic/automation via employeeToAutomations; PAUSED é o default — o founder ativa quando o runner estiver pronto.
3. Explain — o mapa de 10 passos
$ alembic employee explain iris --goal "triage today's inbox"
# Execution chain — iris
**Ground rule:** Derived only from this employee's observable definition + the
engine's real components. Inference is tagged `inferred`; true internals not
inspectable are marked `unknown`; nothing is fabricated.
… 10 passos, cada um com `observed` / `inferred` / `unknown`
Ledgers: inferred:2 unknown:2 (connector A3 / scheduler runner A4 não wired;
conteúdo dos stores desconhecido até serem lidos)
explainEmployeeExecution é puro: dado o EmployeeDefinition + o goal, ele deriva os 10 passos canônicos (msg→task, context-asm, planning, tool-use, verify, output, mem-update, report, next-loop, recover) e tagueia cada um. Apenas planning e memory-update ficam como observed porque o modelo primário e os stores bound são fatos da definição; o resto é inferred porque a execução ainda não aconteceu. Detalhe completo na lição AI Employee.
4. Run — dry-run preview ($0)
$ alembic employee run iris --goal "draft a polite reply to a refund request"
employee: iris (dry-run preview — no model called)
model: claude-opus-4-8
--- system (would be sent) ---
You are Iris, customer support specialist.
## Core Values
- empathy
- precision
## Skills
- issue-triage
- meeting-notes
…
Sem flag, runEmployeeRunOffline chama buildEmployeeRunInput (puro, sem clock, sem RNG, sem IO) e imprime o system + user que seria enviado. Nada de modelo. Este é o ponto de auditoria do prompt antes do gasto. O system é montado por assembleSystemPrompt: renderSoulPrompt(soul) primeiro, ## Skills e ## Connectors só se não-vazios.
5. Cruzar para online — com memória write-back
$ alembic employee run iris --goal "triage the top 5 emails from today" --online
… (resposta real do modelo claude-opus-4-8) …
[memory:writeback] episodic ← writeback-iris-2026-06-28T12:34:56Z
episode: "triage the top 5 emails from today"
context: "(truncated to 500 chars from turn.text)"
Com --online, runEmployeeTurnOnline resolve o ModelAdapter real, faz best-effort compose de memória (degrada para '' se falhar — nunca quebra o turno), chama adapter.run(input), e em sucesso passa para recordEmployeeTurn — o write-back A3b (PR #102). A escrita só acontece se o employee binda episodic; o episode é o goal verbatim, o context é um excerto truncado em 500 chars do turn.text real, o at vem do opts.now injetado (nunca Date.now()), o id é writeback-{id}-{at} (nunca randomUUID). Nada inventado — só o turno real.
O que cada passo prova
employee list / connectors / scheduleprovam o shape da definição sem custo — útil pra revisão de uma proposta de employee antes de qualquer turno.employee explainprova a cadeia de inferência — cada caveat aparece estruturalmente, então auditar o employee não exige ler código.employee run(sem flag) prova o prompt exato que seria enviado — auditável byte-a-byte, $0.employee run --onlineprova o ciclo completo brief once, remembers: o employee lê memória + persiste de volta no store bound. É o loop que faz "hire once, remembers forever" funcionar — opt-in, observável, idempotente peloatdeterminístico.
distill --offline é default; tirar a flag exige o gateway respondendo + preflight. Em (b), marketing campaign é dry-run default; gasto real exige dois flags simultâneos (--approve --yes). Em (c), employee run é dry-run preview default; modelo real + write-back de memória exigem --online. O motor nunca cruza um boundary financeiro ou de rede sem o usuário ter digitado o flag. Esse é o invariante que torna o Alembic seguro para rodar AFK, e o que faz a lição (a) ser literalmente reprodutível num laptop sem internet.
Como funciona por dentro — a costura entre os três casos
Os três casos compartilham mais do que parece. A coluna vertebral é o Result<T,Error> de @alembic/contracts: todo comando devolve um Result, todo erro vira valor (não exceção), e o CLI converte err em exit code não-zero. Por isso você pode encadear os três num plan module determinístico — o motor garante que falha de qualquer estágio propaga limpo, sem mascarar.
O store de BUSINESS SIGNALS do caso (a) e a requisição do caso (b) são tipos diferentes (opportunityRecordsSchema vs. {client, ask}) — não há fluxo automático. O elo é humano: você lê um signal interessante, escreve uma requisição. Isso é deliberado (REVIEW.md § A.3): nenhuma escolha de venture é automática; o humano fica no caminho crítico. O caso (c) é o ponto onde o humano vira recorrente: depois de hire, o employee assume a parte repetitiva (triagem, replies, draft de copy) e devolve memória que alimenta o próximo turno.
Os três casos também respeitam a mesma direção de dependência da camada-3 do overview: o distill vive no Engine (@alembic/etl); o marketing campaign e o employee run vivem nos Products on the engine. Nenhum dos dois últimos pode importar o motor inteiro — eles importam contratos. É por isso que trocar o adapter Higgsfield por outro vendor de vídeo, ou trocar o backend do employee de claude-opus-4-8 para um modelo local, não exige tocar o Engine.
Como você usaria isso amanhã
Em sequência, sem ambiguidade — você consegue rodar tudo abaixo num laptop sem internet, hoje:
# 1. Confirma o motor
alembic doctor --client-stack
# 2. Destila o que você já tem (não precisa do wiki real — qualquer pasta)
alembic distill ./minha-pasta-de-conhecimento --offline
alembic status
# 3. Faz um brief de cliente fictício e roda dry-run da campanha
echo '{"client":{"name":"Meu Cliente","website":"https://ex.com"},"ask":"vídeo 9:16 em pt"}' > req.json
alembic marketing discover req.json
alembic marketing campaign req.json --out preview.json
# 4. Define um employee de exemplo e roda preview
mkdir -p ~/.alembic/employees
# … escreva ~/.alembic/employees/iris.json conforme o caso (c) acima …
alembic employee list
alembic employee explain iris --goal "triage today's inbox"
alembic employee run iris --goal "draft a polite reply"
Cruzar para online (real $$, real OAuth, real MLX) é só trocar a flag final, com o flag duplo onde aplicável. O motor nunca decide ir por você.
Auto-verificação
Por que o passo (a.4) — "signal → venture" — é manual, e não um alembic auto-venture?
Porque o BUSINESS SIGNAL é um candidato, não uma decisão de negócio. O REVIEW.md coloca essa escolha como "founder-gated" deliberada — a portfolio doctrine (ADR-0016) pede que toda oportunidade seja considerada, mas a alocação de WIP (2 slots) e o veto de tasta são humanos. O motor entrega o signal limpo (deduplicado, citado, com provenance) e o forge + run + os gates entregam a execução. O se fica no humano. Automatizar isso violaria a regra "T4 default" do overview.
O que acontece se você roda alembic marketing campaign req.json --approve (só um flag)?
Nada de novo: continua dry-run, $0. Em commands.ts:2900, const paid = args.approve && args.yes; — só com os dois a expressão é true, e só então createHiggsfieldCli({ binary: 'higgsfield' }) substitui fakeHiggsfieldCli. --approve sozinho passa pelo branch fakeHiggsfieldCli exatamente como sem flag nenhum. É a invariante "single flag never reaches a real binary" citada no comentário sobre "generation lock" no próprio código. Spend-safety estrutural, não convencional.
No caso (c), por que employee run --online escreve em episodic mas não em semantic nem em procedural?
Duas razões. Primeiro, o binding: recordEmployeeTurn só escreve no store episodic se o employee bindar episodic (a propriedade memory.stores contém "episodic"). Iris binda ["episodic", "semantic"], então a escrita passa. Segundo, o contrato: write-back A3b escreve um episódio honesto — o goal verbatim + um excerto truncado do turn.text real. Episodic é o store que essa forma respeita; semantic e procedural têm contratos diferentes (fatos resumidos, procedimentos derivados) e portanto requerem um composer separado, que não é parte do A3b. Nenhum learning é inventado — só o turno real, no store que aceita esse formato.
Você acaba de ver: os três fluxos que tornam o Alembic um produto, e a régua que conecta os três (offline-default, --online gated). Para mergulhar de novo em qualquer peça: overview, funnel, capabilities, swarm-harness, AI Employee, marketing factory, factory / forge / course.