Na prática: o playbook
Seis fluxos reais de ponta a ponta com o alembic — cada um com os comandos exatos (todos da lista canônica do CLAUDE.md, nada inventado), a saída esperada, o que observar e um passo "Experimente". Comece offline e em $0: tudo aqui roda hermético, sem gateway e sem custo. Cada cenário aponta para a lição que explica por que funciona assim.
- Planejar um escopo, rodá-lo pelos cinco gates e inspecionar a run (
plan→run→runs list→tui/tail). - Rodar o funil noturno offline e ler o estado da pipeline (
distill --offline→status). - Resumir uma run que quebrou sem perder trabalho (
--resume/replay). - Operar o gate humano T4: propor, aprovar e rejeitar unidades parqueadas.
- Escrever uma missão com
units[]+proof[]e disparar a run. - Usar os comandos de capacidade offline:
doctor --client-stack,course,memory,context-pack.
run-<hash> (ex.: run-a1b2c3d4) porque o Alembic deriva o id de um hash do conteúdo do escopo — o seu hash será diferente, e isso é esperado.Montador de comando
Explica o comando montado: Lição 17 · A pipeline de gates · Lição 27 · Tiers, custo & orçamento
alembic runEscolha goal, plano, tier e flags — o comando real se monta ao vivo. Cada peça é um flag canônico do USAGE (apps/cli/src/index.ts); nada é inventado.
tier: 'T2' em h.mission()), não na linha de comando — por isso o seletor de tier acima só mostra o que você teria no plano e não vira flag. A linha de comando controla como a run é executada (offline, cache, gates extras), não quem roda cada unidade.
1 · Scope → run → gates → inspect
Explicado em: Lição 17 · A pipeline de gates · Lição 19 · O swarm · Lição 28 · Determinismo & replay
O fluxo central do Alembic: você descreve um escopo em linguagem natural, o plan materializa GOAL.md + alembic.plan.ts + um contrato, o run executa pelos gates, e você inspeciona o resultado — lista de runs, TUI ou stream de eventos.
plan escreve um diretório com o GOAL, o plano e o contrato.$ alembic plan "Implementar um serviço HTTP mínimo" # plan: .alembic/plans/implementar-um-servico-http-minimo # html: .alembic/plans/implementar-um-servico-http-minimo/plan.html # goal: .alembic/plans/implementar-um-servico-http-minimo/GOAL.md # contract: .alembic/plans/implementar-um-servico-http-minimo/validation-contract.md # script: .alembic/plans/implementar-um-servico-http-minimo/alembic.plan.ts # skill: .alembic/plans/implementar-um-servico-http-minimo/skill.md
--offline usa o adapter determinístico $0; --yes auto-aprova o gate de plano/publicação para rodar sem prompt.$ alembic run --goal GOAL.md --plan alembic.plan.ts --offline --yes # [scope ] gate: ok # [task:u1 ] task: running # [task:u1 ] proof: pnpm -r typecheck — exit 0 # [task:u1 ] proof: pnpm -w test — exit 0 # [task:u1 ] task: done # [validator ] gate: complete # [publish ] gate: parked (curso gerado; gist/Pages é gated) # run-a1b2c3d4 finished
--data-dir (default .alembic).$ alembic runs list # runs under .alembic: # run-a1b2c3d4 [finished] 2026-06-27T18:04:11.027Z
tail -f.$ alembic tui run-a1b2c3d4 # ┌──────────── Alembic run run-a1b2c3d4 — finished ────────────┐ # │ goal: Implementar um serviço HTTP mínimo │ # │ events: 7 | parked: 0 │ # ├────────────────────────────────────────────────────────────┤ # │ [task:u1 ] task: done │ # │ [validator ] gate: complete │ # └────────────────────────────────────────────────────────────┘ $ alembic tail run-a1b2c3d4 -f # [task:u1 ] task: running # [task:u1 ] task: done # [validator ] gate: complete # (segue transmitindo novos eventos até Ctrl-C)
run-a1b2c3d4 é determinístico: vem de um hash do escopo (runIdFor), então rodar o mesmo GOAL+plano dá o mesmo id e reusa o mesmo diretório. O gate publish aparece como parked, não falho — gerar o curso é offline, mas publicar em gist/Pages é gated. Cada proof[] vira uma linha com exit 0; um exit não-zero falha a run closed.
--offline (precisa do gateway cliproxyapi em 127.0.0.1:8317 + ALEMBIC_CLIPROXY_TOKEN). Se você não tem o gateway, vai ver fetch failed — exatamente o sintoma documentado no troubleshooting. Volte a pôr --offline e confirme que o id da run é o mesmo de antes (mesmo escopo → mesmo hash).
2 · O funil noturno offline ($0)
Explicado em: Lição 15 · O funil · Lição 01 · O motor · Lição 26 · Proveniência & segurança
O funil é o ETL de quatro tiers (T0 grátis → T1 ~$0 → T2 metered → T3 council+verifier) que transforma um corpus cru em Learnings. Em --offline ele roda hermético e em $0: nenhuma chamada de rede, nenhum custo — o jeito de exercitar a pipeline inteira com segurança.
$ alembic distill ./corpus --offline # distill: discover -> validate -> design -> plan -> build -> review # [T0 discover ] 42 source(s) scanned # [T1 validate ] 38 kept, 4 routed to residue # [T3 review ] verified-GO: 12 learning(s) sedimented # distill: complete (offline, $0)
status reporta o tier-default de autonomia, as fases do funil e a contagem dos stores append-only.$ alembic status # status: default tier T4 # phases: discover -> validate -> design -> plan -> build -> review -> ship # stores (.alembic): 38 opportunity, 12 learnings
opportunity e learnings são os stores append-only: o funil nunca apaga, só acrescenta. Por isso o gate de T3 só conta como "sedimentado" o que passou pelo verified-GO (council + verifier).
alembic distill ./corpus --offline --dry-run: ele percorre todos os tiers mas não escreve nada nos stores. Depois rode alembic status de novo e confirme que as contagens não mudaram — é assim que você testa o funil sem sujar o estado.
3 · Resumir uma run que quebrou
Explicado em: Lição 28 · Determinismo & replay · Lição 19 · O swarm · Lição 04 · O loop fechado
Uma run que caiu no meio não precisa recomeçar do zero. Como tudo é gravado em events.jsonl + cache, você pode resumir o mesmo diretório de run, ou reexecutar a partir do journal. --no-cache força reexecutar os passos de agent()/swarm() em vez de reusar o cache — útil quando a falha foi um resultado cacheado ruim.
[failed] ou [running] na lista.$ alembic runs list # runs under .alembic: # run-a1b2c3d4 [failed] 2026-06-27T18:22:50.114Z # run-9f8e7d6c [finished] 2026-06-27T18:04:11.027Z
--resume reusa .alembic/runs/<run-id> e valida goal/plano/contrato contra o meta.json gravado; --no-cache ignora o cache de agent()/swarm().$ alembic run --goal GOAL.md --plan alembic.plan.ts --resume run-a1b2c3d4 --no-cache --yes # resume: run-a1b2c3d4 (goal/plan/contract validados contra meta.json) # [task:u1 ] task: cached -> done # [task:u2 ] task: running (refeita — --no-cache) # [task:u2 ] task: done # run-a1b2c3d4 finished
replay reexecuta a run a partir de events.jsonl + cache — uma reprodução determinística do que aconteceu.$ alembic replay run-a1b2c3d4 # replay: run-a1b2c3d4 from events.jsonl (+ cache) # [task:u1 ] task: done # [task:u2 ] task: done # replay: complete
--resume valida antes de retomar: se você editar o GOAL ou o plano e tentar resumir o mesmo id, a validação contra meta.json falha — você não pode "resumir" um escopo diferente por acidente. replay é diferente de resume: resume continua a run; replay reproduz a partir do journal. As unidades já feitas voltam como cached -> done (a menos que --no-cache).
alembic replay <run-id> nele. Compare a saída do replay com a do tail original — as duas devem bater evento a evento. É a prova viva da invariante de determinismo (Lição 28): mesma entrada, mesmo run-dir, mesmo resultado.
4 · O gate humano T4
Explicado em: Lição 10 · ClarifyGateway (gate T4) · Lição 17 · A pipeline de gates · Lição 24 · A trilha de ADRs
Unidades em tier T4 não executam sozinhas: elas ficam parqueadas, esperando um humano. O fluxo é propose (reabre as tarefas T4 parqueadas como uma proposta) → approve ou reject cada unidade pelo seu id. Toda decisão é gravada num ledger append-only (approvals.jsonl / rejections.jsonl).
parked > 0 na TUI.$ alembic tui run-77aa11bb # ┌──────────── Alembic run run-77aa11bb — finished ────────────┐ # │ events: 9 | parked: 1 │ # ├────────────────────────────────────────────────────────────┤ # │ [task:u3 ] task: parked (tier-t4) │ # └────────────────────────────────────────────────────────────┘
propose reabre as unidades T4 como uma proposal run para revisão.$ alembic propose run-77aa11bb # propose: 1 parked T4 task(s) reopened from run-77aa11bb # proposed-u3 (tier-t4) "Original reason: tier-t4" # proposal run: run-c4d5e6f7
$ alembic approve run-77aa11bb --task-id u3 # approved task 'u3' in run run-77aa11bb (-> approvals.jsonl) $ alembic reject run-77aa11bb --task-id u3 # rejected task 'u3' in run run-77aa11bb (-> rejections.jsonl)
approve/reject uma tarefa que não está parqueada, o comando falha closed: task 'u3' is not parked in run .... O gate T4 é a fronteira humana do sistema — é onde uma ação irreversível ou de alto risco espera um sim explícito. Aprovar não apaga a rejeição nem vice-versa: ambos são append-only, então o histórico de decisões fica auditável.
alembic propose <run-id> — você verá run <id> has no parked T4 tasks, o erro fail-closed esperado. Depois, escreva uma missão com uma unidade em tier: 'T4' (próximo cenário) e veja-a parquear de verdade.
5 · Escrever uma missão com units[] + proof[]
Explicado em: Lição 22 · Lab: construa um subsistema · Lição 16 · As quatro invariantes · Lição 05 · Ports & injeção
Uma missão é declarada dentro do alembic.plan.ts com h.mission(). Cada unidade tem um id, título, descrição, milestone, skill, tier e — o ponto central — um array proof[]. Cada string de proof[] vira uma tarefa bash -c que depende da unidade; exit não-zero falha a run closed.
Este é o snippet canônico do CLAUDE.md (use exatamente esta forma de API):
// alembic.plan.ts const result = await h.mission({ title: 'mission title', tier: 'T2', units: [ { id: 'u1', title: 'Implement feature X', description: 'Detailed description for the worker.', milestoneId: 'm1', skillName: 'coder', fulfills: ['FR-1'], tier: 'T2', proof: ['pnpm -r typecheck', 'pnpm -w test'], }, ], milestones: [ { id: 'm1', title: 'Milestone one' }, ], });
alembic.plan.ts (ao lado de um GOAL.md). Lembre: o VM de plano rejeita Date.now(), new Date() e Math.random() — o plano precisa ser determinístico.proof[] roda da raiz do repo, depois da unidade; o resultado é persistido em units/<id>/proof-results.jsonl.$ alembic run --goal GOAL.md --plan alembic.plan.ts --offline --yes # [scope ] gate: ok # [task:u1 ] task: running (skill: coder, tier T2) # [task:u1 ] task: done # [task:u1-proof-0] proof: pnpm -r typecheck — exit 0 # [task:u1-proof-1] proof: pnpm -w test — exit 0 # [validator ] gate: complete (milestone m1) # run-b2c3d4e5 finished (proofs -> units/u1/proof-results.jsonl)
proof[] vira uma tarefa própria (u1-proof-0, u1-proof-1) que depende da unidade u1 — por isso elas só rodam depois que u1 termina. Um exit não-zero em qualquer proof falha a run: é o Proof Gate fechando. O tier: 'T2' na unidade roteia para o modelo T2 mais barato por padrão; trocar para 'T4' faria a unidade parquear (cenário 4).
'exit 1') e rode de novo: a run deve falhar closed na tarefa de proof, e alembic runs list deve mostrá-la como [failed]. Depois conserte o proof e use o cenário 3 (--resume) para retomar.
6 · Comandos de capacidade
Explicado em: Lição 27 · Tiers, custo & orçamento · Lição 07 · Memória · Lição 18 · Council & Verifier
Além das runs, o alembic expõe comandos de capacidade — cada um offline e determinístico por padrão, com --online como opt-in para um backend real. Quatro que valem ter na ponta dos dedos:
doctor --client-stack — valida o shape do MODEL_REGISTRY + coerência dos adapters, offline e em $0, sem rede. É o seu pre-flight de sanidade.$ alembic doctor --client-stack # doctor --client-stack (offline, $0, no network) # MODEL_REGISTRY: 11 model(s), shape OK # adapters: cliproxyapi coherent (every modelId mapped) # result: PASS
course — monta um curso visual-teach byte-stable a partir de um corpus theme-scored (offline $0). Gera índice + páginas de lição.$ alembic course ./corpus --max-lessons 3 # course: Local-LLM infra — a visual-teach course # theme: local_models_infra, lessons: 3 # index: .alembic/courses/local_models_infra/index.html # 01-modelo-mental: O modelo mental # 02-memoria: Matemática de memória # 03-quantizacao: Quantização & qualidade
memory — multi-store append-only (episodic | semantic | procedural | decision | transcript). add grava um registro JSON; list consulta.$ alembic memory decision add --agent cli --record '{"text":"escolhemos Q4_K_M"}' # memory decision: appended dec-0001 (agent cli) # .alembic/memory/decision.jsonl $ alembic memory decision list --limit 5 # memory decision: 1 record(s) under .alembic/memory/decision.jsonl # dec-0001 [agent cli] at 2026-06-27T18:40:02.551Z
context-pack — monta um pacote de contexto em 8 camadas (L0–L7) a partir de arquivos, com brief, papel e orçamento de tokens.$ alembic context-pack README.md CLAUDE.md --brief "onboarding" --role validator --budget 8000 # context-pack: 8 layers (L0..L7), role=validator, budget=8000 tok # L0 brief: "onboarding" # L1..L7: 2 file(s) packed within budget
--online explicitamente. O course é byte-stable: o mesmo corpus gera bytes idênticos, sem relógio nem RNG no artefato (por isso ele é reprodutível e versionável). O memory é append-only como tudo no Alembic: nunca apaga, sempre acrescenta.
alembic doctor --client-stack agora — é seguro, não toca a rede. Depois rode alembic memory semantic add --record '{"text":"meu primeiro fato"}' seguido de alembic memory semantic list e veja o registro voltar. Tudo fica em .alembic/, que você pode apagar à vontade.
Mapa para as lições
Cada cenário acima é a prática; a teoria por trás vive nas lições. Use esta tabela para ir do "como faço" ao "por que é assim".
| Cenário | Comando-chave | Lição que explica |
|---|---|---|
| 1 · Scope → run → inspect | plan · run · tui/tail | 17 · gates · 19 · swarm |
| 2 · Funil offline | distill --offline · status | 15 · o funil · 01 · o motor |
| 3 · Resumir uma run | --resume · replay | 28 · determinismo & replay |
| 4 · Gate humano T4 | propose · approve/reject | 10 · ClarifyGateway · 24 · ADRs |
| 5 · Missão units[]+proof[] | h.mission() · run | 22 · lab subsistema · 16 · invariantes |
| 6 · Capacidades | doctor · course · memory · context-pack | 27 · tiers & custo · 07 · memória |
--online (capacidades) ou tire --offline (runs) — com o gateway cliproxyapi de pé. O Alembic é fail-closed por design: ele prefere parar e te perguntar a gastar ou agir sozinho.