Curso · Na prática: o playbook
Alembic · visual-teach · hands-on

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.

Objetivos — o que você vai conseguir fazer
  • Planejar um escopo, rodá-lo pelos cinco gates e inspecionar a run (planrunruns listtui/tail).
  • Rodar o funil noturno offline e ler o estado da pipeline (distill --offlinestatus).
  • 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.
Convenção de leitura. Nos blocos de comando, o cifrão $ é o seu prompt — não o digite. As linhas em cinza começando com # são a saída esperada (ou um comentário), não comandos. Os IDs de run aparecem como 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

Monte seu alembic run

Escolha 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.

Comando montado

        
O que observar
Tier ≠ flag. O tier da missão mora no plano (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

offline · $0o caminho feliz

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.

Cenário 1 — do prompt ao stream de eventos
1
Gere o escopo. O 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
2
Rode pelo escopo. --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
3
Liste o que foi persistido. Toda run vira um diretório append-only sob --data-dir (default .alembic).
$ alembic runs list
# runs under .alembic:
#   run-a1b2c3d4 [finished] 2026-06-27T18:04:11.027Z
4
Inspecione. Abra a TUI para um quadro vivo, ou siga o stream bruto de eventos com 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)
O que observar
O id 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.
Experimente
Repita o passo 2 sem --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)

offline · hermético$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.

Cenário 2 — destilar um corpus e ler o estado
1
Destile um corpus offline. Aponte para uma pasta (aqui, um diretório de notas) e deixe o funil percorrer os tiers sem tocar a rede.
$ 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)
2
Leia o estado da pipeline. O 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
O que observar
O tier-default é T4 — o nível mais conservador, que pára para o humano. Isso é deliberado (ADR): autonomia é opt-in, não o padrão. As contagens de 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).
Experimente
Rode 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

recuperaçãocrash-safe

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.

Cenário 3 — retomar de onde parou
1
Descubra o id da run. Uma run que quebrou aparece como [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
2
Resuma o mesmo diretório. --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
3
Ou reexecute do journal. 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
O que observar
--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).
Experimente
Rode o cenário 1 de novo, depois rode 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

T4 · gate humanoapprove / reject

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).

Cenário 4 — operar o gate humano
1
Veja a run com tarefas parqueadas. Uma run com unidades T4 mostra parked > 0 na TUI.
$ alembic tui run-77aa11bb
# ┌──────────── Alembic run run-77aa11bb — finished ────────────┐
# │ events: 9 | parked: 1                                       │
# ├────────────────────────────────────────────────────────────┤
# │ [task:u3       ] task: parked (tier-t4)                     │
# └────────────────────────────────────────────────────────────┘
2
Proponha as tarefas parqueadas. 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
3
Decida. Aprove (ou rejeite) a unidade pelo seu id. A decisão é gravada no ledger da run.
$ 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)
O que observar
Se você tentar 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.
Experimente
Numa run sem tarefas T4, rode 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[]

alembic.plan.tsh.mission()

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' },
  ],
});
Cenário 5 — declarar e disparar a missão
1
Salve o snippet acima como o seu 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.
2
Dispare a run pelo escopo. Cada 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)
O que observar
Cada string de 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).
Experimente
Mude um proof para um comando que falha (ex.: '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

offline · determinístico$0

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:

Cenário 6 — quatro capacidades offline
1
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
2
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
3
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
4
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
O que observar
Todos esses comandos são offline por padrão — você só paga (e só toca a rede) se passar --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.
Experimente
Rode 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árioComando-chaveLição que explica
1 · Scope → run → inspectplan · run · tui/tail17 · gates · 19 · swarm
2 · Funil offlinedistill --offline · status15 · o funil · 01 · o motor
3 · Resumir uma run--resume · replay28 · determinismo & replay
4 · Gate humano T4propose · approve/reject10 · ClarifyGateway · 24 · ADRs
5 · Missão units[]+proof[]h.mission() · run22 · lab subsistema · 16 · invariantes
6 · Capacidadesdoctor · course · memory · context-pack27 · tiers & custo · 07 · memória
A regra de ouro deste playbook
Comece sempre offline e em $0. Todo comando aqui roda hermético: sem gateway, sem token, sem custo. Quando funcionar offline, aí sim adicione --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.
Estes seis fluxos são o caminho prático pelo motor. Para o porquê de cada decisão — as quatro invariantes, os cinco gates, o loop fechado e a trilha de ADRs — siga para as trinta lições.