Gerenciar workbooks com git
Você pode extrair o conteúdo de um workbook como arquivos no seu repositório, passar tudo por diff, review e PR no git, e escrever de volta. Os transforms escritos pelo agente do chat aparecem no mesmo lugar, então a prática de “revisar o SQL escrito pela IA antes de confirmar” funciona sem adaptação.
d2b pull --workbook WB # → transforms/ sheets/ charts/ + d2b.jsond2b pull --data customers # also track a small base table as data/customers.csv (export = branch)git add -A && git commit -m "pull from D2B"# ... edit transforms/*.sql|py, sheets/*.json, data/*.csvd2b push --dry-run # what would be sent (only files that changed)d2b push --commit "$(git rev-parse --short HEAD)" # apply the changes → pin the git sha as a named versiongit commit -am "d2b push" # push updates d2b.json (sync hashes) — commit it too| Diretório | Conteúdo | pull | push |
|---|---|---|---|
transforms/ | Transforms SQL / Python (hierarquia permitida, como agg/monthly.sql) | ✅ | ✅ Só o que mudou é re-executado via POST /transforms (contabilizado como operação de dados). Em ordem de dependência (do upstream para baixo) |
sheets/ | Sheets de exibição {"blocks": [...]} | ✅ | ✅ PUT /sheets/{name} |
charts/ | Config + recipe dos charts (a tool e os parâmetros usados na geração) | ✅ | ❌ Somente leitura — um chart é regenerado a partir do recipe; corrigir o config à mão não permite regenerar. Para histórico e conferência |
data/ | CSV das tabelas base com opt-in via --data (com __d2b_row_id) | ✅ export = branch | ✅ 3-way merge célula a célula no servidor, chaveado por row ID. Células alteradas dos dois lados vão para a fila de conflicts do workbook (o valor do D2B permanece) |
--data só se aplica a tabelas base (cujas linhas são a própria fonte de verdade). A saída estruturada do mode=auto é derivada (saída de um transform) e não pode ser ramificada — para levar as linhas de uma tabela pelo git, ingira com --mode staged, revise o parse spec e materialize (isso produz uma tabela base), ou crie-a via API de linhas.
O d2b.json é o manifesto. A entrada de um transform é {name, artifact_name, args, layer, hash} (ao adicionar um transform novo, escreva o arquivo e essa entrada). O hash é o digest do último sync (= a base do merge) e a CLI o mantém — faça commit do d2b.json depois do push.
Ao escrever uma entrada nova à mão, omita hash (omitir — ou null — dá no mesmo): o primeiro push o atribui e grava de volta.
{ "workbook_id": "…", "transforms": { "agg/monthly.sql": { "name": "agg/monthly", "artifact_name": "product_sales", "args": {"src": "sales"}, "layer": null, "hash": "…" } }, "sheets": {"summary.json": {"name": "summary", "hash": "…"}}, "charts": {"trend.json": {"name": "trend", "readonly": true, "hash": "…"}}, "data": {"customers.csv": {"table": "customers", "branch_id": "…", "hash": "…"}}}Sincronizar um workspace inteiro
Seção intitulada “Sincronizar um workspace inteiro”Centenas ou milhares de pastas de trabalho são tratadas como um repositório = um workspace. O d2b.json da raiz (o livro-razão) fixa o workspace, e cada pasta de trabalho fica em workbooks/<título>--<8 primeiros caracteres do id>/ com o layout acima, incluindo o próprio d2b.json.
d2b pull --workspace WS # primeira vez: grava o livro-razão e traz todas as pastas de trabalho do workspace (em paralelo, --jobs N)d2b pull # depois: a partir do livro-razão; uma pasta nova aparece sozinhad2b pull --prune # remove os diretórios das pastas que saíram do workspace (a remoção aparece no diff)d2b status --strict # exit 2 quando livro-razão, diretórios e servidor divergem (torne-o verificação obrigatória no CI)d2b push --commit "$(git rev-parse --short HEAD)" # só as pastas de trabalho alteradas são enviadas- O pertencimento é um fato do servidor:
pulllista todas as pastas de trabalho do workspace e nunca grava um diretório que o livro-razão não conheça. Outro workspace não pode ser trazido para o mesmo repositório — não há opção para forçar. - O diretório de uma pasta de trabalho é fixado no primeiro pull; mudar o título não o move. O id está no nome do diretório e na primeira linha de cada arquivo de transformação,
-- d2b ws=… wb=… transform=…(a linha nunca é enviada ao servidor nem conta como alteração). pushnão envia nada quando encontra um diretório desconhecido do livro-razão, um arquivo cujo cabeçalho nomeia outra pasta de trabalho ou um manifesto vinculado a outroworkbook_id.- Dê ao CI um PAT fixado ao workspace (
workspace_idemPOST /api/control/account/keys, ouresource: "workspace:<id>"emPOST /api/v1/me/tokens): mesmo mal configurado, o servidor responde 403 para qualquer outro workspace. A credencial ded2b loginalcança a conta inteira e não é a chave certa para o CI. data/(linhas) continua sendo opt-in por pasta de trabalho (d2b pull --data TABLEdentro deworkbooks/<dir>/).
Um diretório sem livro-razão mantém o comportamento de pasta única descrito acima.
Regras de conflito
Seção intitulada “Regras de conflito”- Arquivos de texto (transforms / sheets / charts) nunca são sobrescritos em silêncio (o mesmo contrato do lock otimista da API de linhas): se os dois lados mudaram desde o último sync, tanto pull quanto push são recusados e os arquivos afetados são retornados em JSON. A direção de
--forcedepende do comando: push--forceimpõe o seu lado local; pull--forceadota o lado do servidor (descartando suas edições locais) data/é diferente: edições simultâneas não são recusadas, porque o 3-way merge do servidor arbitra célula a célula. Depois do push, o CSV é baixado de novo com o resultado do merge e um novo branch é aberto (as mudanças do lado do D2B também descem para o local). Tabelas derivadas não aceitam branch (400). Limite de merge: 100,000 linhas — para tabelas pequenas, como masters e tabelas de correspondência- Arquivos apagados localmente não apagam nada no servidor (só entram no relatório em
deleted_locally). Com--prune, as tabelas de saída dos transforms e as sheets são excluídas (excluir tabelas de saída exigeworkbooks:delete). Emdata/, só o rastreamento é removido — a tabela não é apagada - As chaves de
d2b.jsondevem ser caminhos relativos normalizados dentro do próprio diretório da seção: caminhos absolutos,.., unidades do Windows e caminhos não normalizados são recusados tanto no pull quanto no push. Um arquivo sincronizado que seja um link simbólico (transforms/*.sql|pye afins) também é recusado — nada é lido nem escrito através de um link (um link para um arquivo que a seção nunca lê é simplesmente ignorado)
Automatizar a ida e volta com GitHub Actions
Seção intitulada “Automatizar a ida e volta com GitHub Actions”Sem GitHub App e sem configuração de integração no lado do D2B: só com a CLI, a ida e volta entre o repositório e o workbook se fecha.
d2b github-workflow > .github/workflows/d2b.yml# Secrets: D2B_API_KEY (a workbooks:write PAT). Variables: D2B_BASE_URL- Merge na
main(com mudanças nos arquivos sincronizados) →d2b push --commit <sha>→ commit automático dod2b.jsonatualizado - Agendado (padrão: a cada 1 hora) e manual →
d2b pull→ se houver diff, abre um PR (branchd2b/pull). É o fluxo em que uma pessoa revisa e faz merge do que o agente mudou no lado do workbook
No SDK, a mesma superfície é client.transforms.list(wb) / client.sheets.list(wb) / client.charts.list(wb) / client.export.branch(wb, [table]) / client.tables.merge(...).