Pular para o conteúdo

Backup, exportação e importação

Tudo o que o Control Center consegue copiar, entregar ou adotar, e a forma exata de cada artefato. Para de fato fazer um backup, veja Fazer backup e restaurar; para entender por que a persistência está dividida assim, veja Espaços de trabalho e isolamento.

Existem três artefatos de cópia de banco de dados, com escopos e políticas de exclusão diferentes.

Artefato Escrito por Forma Cobre
Snapshot da instalação server.backupNow Um diretório com carimbo de data/hora Todos os bancos de dados da instalação
Backup do espaço de trabalho pipeline Workspace backup Diretório com carimbo de data/hora e um .db O banco de dados de um espaço de trabalho
Exportação do espaço de trabalho workspace.export Um arquivo .db único O banco de dados de um espaço de trabalho

Todos são gravados com VACUUM INTO do SQLite, que é seguro em relação a um banco de dados WAL em uso: ele faz uma transação de leitura, produz uma cópia desfragmentada e transacionalmente consistente e nunca exige parar o servidor.

<dataDir>/backups/2026-07-28T09-12-33-000Z/
manifest.json
global.db
<workspaceId>/workspace.db one directory per workspace

O layout espelha exatamente o diretório de dados em uso, e é isso que faz restaurar uma instalação ser uma cópia de volta, e não uma tradução. O nome do diretório é o carimbo de data/hora UTC com : e . substituídos por -, então é seguro para sistemas de arquivos no Windows e ordena cronologicamente como uma string simples.

Os backups agendados de espaços de trabalho ficam separados em <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db. Eles não incluem manifesto nem global.db e não são snapshots da instalação. A etapa de retenção do pipeline semanal remove apenas backups do próprio espaço de trabalho mais antigos que a idade configurada (30 dias por padrão); snapshots da instalação criados manualmente nunca são rotacionados por essa etapa. server.listBackups lista apenas snapshots da instalação, inclusive os incompletos.

Campo Tipo Significado
version int Versão do formato do manifesto. Atualmente 1
created_at ISO-8601 UTC Quando o snapshot foi tirado
global.file string Sempre global.db
global.schema_version int Versão do esquema de GlobalDatabase no momento da captura
global.bytes int Tamanho do global.db gravado
workspace_schema_version int Versão do esquema de WorkspaceDatabase compartilhada por todo arquivo de espaço de trabalho
workspaces[] array Uma entrada por espaço de trabalho capturado
workspaces[].workspace_id string O espaço de trabalho que este arquivo contém
workspaces[].file string Caminho relativo à raiz do snapshot, <workspaceId>/workspace.db
workspaces[].bytes int Tamanho desse arquivo
skipped_workspaces[] array of string Espaços de trabalho que o backup não conseguiu capturar

Um espaço de trabalho é ignorado quando está registrado, mas nunca foi gravado (então ainda não existe arquivo), ou quando o VACUUM INTO dele falhou. De qualquer forma o snapshot ainda é concluído e o manifesto nomeia o que está faltando.

server.listBackups informa um sinalizador complete por snapshot. Ele é falso quando o manifesto está ausente ou não pode ser interpretado, quando falta o global.db ou quando o manifesto nomeia um arquivo de espaço de trabalho que não está no disco.

Um snapshot incompleto ainda é listado, porque um snapshot que o operador não consegue ver é um snapshot que ele acredita ter. Quando o manifesto não pode ser lido, a listagem recorre ao próprio layout e informa os arquivos <workspaceId>/workspace.db que encontrar — eles continuam podendo ser adotados individualmente por workspace.import, ainda que o snapshot como um todo não consiga restaurar uma instalação.

Os dois artefatos são apenas bancos de dados. Um diretório de espaço de trabalho contém mais do que o banco de dados dele, e nada do restante viaja:

Caminho Em um snapshot? Em uma exportação de espaço de trabalho?
global.db Sim Não
<workspaceId>/workspace.db Sim Sim (ele é o arquivo)
<workspaceId>/blobs/ Não Não
<workspaceId>/skills/ Não Não
<workspaceId>/agents/ Não Não
<workspaceId>/chat_credentials/ Não Não
<workspaceId>/spaces/<spaceId>/ Não Não
<workspaceId>/pr_clones/ Não Não
secrets.json Não Não
models/ Não Não
meetings/<meetingId>/ Não Não
rigs/ Não Não

Parte disso é descartável — spaces/ contém worktrees copy-on-write que são reprovisionados a partir dos repos, pr_clones/ é um cache, models/ é baixado de novo, rigs/ é estado da máquina. Parte não é: blobs/ contém imagens coladas para as quais linhas do banco de dados apontam, skills/ e agents/ contêm os arquivos com que um agente roda, e secrets.json contém todas as chaves de emparelhamento, credenciais de provedor e configurações de SSO da instalação. Veja Fazer backup e restaurar para cobrir o restante.

Os RPCs de backup da instalação e a exportação/importação de espaço de trabalho são exclusivos de fullClient: um telefone emparelhado não consegue acioná-los. Todos eles estão totalmente ausentes — não recusados, mas estruturalmente inexistentes — em um servidor sem porta de backup configurada, como o servidor de demonstração.

Op Tipo Escopo Função mínima Argumentos Retorna
server.backupNow mutate Instalação proprietário da instalação nenhum {ok, path}
server.listBackups read Instalação proprietário da instalação nenhum {backups: [...]}
server.deleteBackup mutate Instalação proprietário da instalação name {ok}
workspace.export read Espaço de trabalho admin nenhum {ok, path}
workspace.import mutate Espaço de trabalho owner source_path {ok, workspace_id}
workspace.delete mutate Instalação* owner id linha do registro marcada como excluída
  • workspace.delete não tem escopo porque a linha que ele marca vive no registro global; o handler dele verifica a associação do chamador ao espaço de trabalho nomeado e exige owner.

path em toda resposta é um caminho no host do servidor.

Do mais recente para o mais antigo, ordenado pelo nome do diretório (que é o carimbo de data/hora, então a ordem se mantém mesmo para um snapshot cujo manifesto não pôde ser lido).

{
"backups": [
{
"path": "/…/backups/2026-07-28T09-12-33-000Z",
"name": "2026-07-28T09-12-33-000Z",
"created_at": "2026-07-28T09:12:33.000Z",
"bytes": 481203712,
"complete": true,
"workspaces": [
{
"workspace_id": "w_9f2c…",
"path": "/…/backups/2026-07-28T09-12-33-000Z/w_9f2c…/workspace.db",
"bytes": 190840832
}
],
"skipped_workspace_ids": []
}
]
}

created_at é omitido quando o manifesto não pôde ser lido. O bytes do nível superior é o tamanho real em disco do diretório inteiro, e não a soma do próprio manifesto — a pergunta que um operador que faz poda de snapshots está fazendo é quanto o diretório ocupa, e não quanto o backup pretendia gravar.

Cada workspaces[].path é exatamente o que workspace.import recebe como source_path. Isso é deliberado: “restaurar este espaço de trabalho a partir deste snapshot” é a operação de importação, então as duas não podem divergir em tratamentos diferentes do mesmo arquivo.

Antes de qualquer coisa ser substituída, o arquivo candidato é aberto somente para leitura com uma conexão SQLite bruta de vida curta e a linha workspace_meta dele é lida.

Condição Resultado
Não é um banco de dados SQLite legível, ou não tem workspace_meta Recusado. Nada é tocado
Id de espaço de trabalho registrado ≠ o destino Permitido, registrado em log. É assim que se duplica ou restaura um espaço de trabalho sob um id novo
Id de instalação registrado ≠ esta instalação Permitido, registrado em log. Os dispositivos emparelhados e ids de usuário dele pertencem àquela instalação e não serão resolvidos aqui
Id de espaço de trabalho inválido, ou arquivo inexistente Recusado

Quando aceito, o banco de dados do espaço de trabalho de destino é fechado e removido do gerenciador antes de o arquivo ser copiado por cima dele (uma conexão de drift aberta mantém o arquivo e o -wal dele), e depois reaberto para que beforeOpen reinstale os gatilhos de FTS e de sincronização, e os índices de FTS são reconstruídos — as tabelas de conteúdo de um arquivo importado ficam preenchidas, mas o índice dele pode estar desatualizado.

Toda operação acima fala em caminhos do lado do servidor, o que é uma resposta completa apenas quando o servidor é a sua própria máquina. Estas três carregam os bytes, na mesma via assinada por PSK que o proxy de mídia e o armazenamento de blobs usam. O chamador assina uma string de destino com a chave pré-compartilhada do dispositivo e passa a assinatura como s.

Rota Método Query Destino assinado Exige
/backup/workspace GET w, d, s backup-workspace:<workspaceId> admin do espaço de trabalho
/backup/snapshot GET n, d, s backup-snapshot:<name> proprietário da instalação
/backup/restore POST w, d, s backup-restore:<workspaceId> proprietário do espaço de trabalho

w é um id de espaço de trabalho, n é um nome de diretório de snapshot, d é o id do dispositivo que chama e s é a assinatura. n é resolvido contra a listagem de backups em vez de ser concatenado à raiz de backups, então a rota não pode ser apontada para um diretório que a listagem não teria mostrado.

Status Causa
400 Falta um parâmetro de query obrigatório, ou o corpo de um upload está vazio
403 Dispositivo desconhecido ou revogado, assinatura inválida, ou o chamador não tem a função
404 Nenhuma porta de backup neste host, ou o snapshot/arquivo de espaço de trabalho nomeado não existe
405 /backup/restore chamado com qualquer coisa diferente de POST
413 O corpo do upload excede 8 GiB, pelo content-length declarado ou pelos bytes realmente lidos
500 A exportação ou o arquivamento falhou no lado do servidor

Os dois downloads respondem Cache-Control: no-store com Accept-Ranges: none. Cada requisição cria uma cópia nova e a exclui depois de transmitida, então uma resposta em cache ou retomada juntaria bytes de duas exportações diferentes em um único arquivo que parece válido e não é.

/backup/snapshot retorna <name>.zip, com entradas relativas à raiz do snapshot, de modo que descompactar reproduz manifest.json + global.db + <workspaceId>/workspace.db. As entradas são gravadas em ordem classificada, então dois arquivos compactados do mesmo snapshot são o mesmo arquivo.

/backup/restore transmite o corpo direto para um arquivo de preparação em vez de colocá-lo em buffer, limita o tamanho antes e durante a leitura, e exclui o arquivo preparado em todas as saídas, inclusive numa recusa.

Item Valor
Snapshots <dataDir>/backups/<timestamp>/
Backups agendados de espaços de trabalho <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Exportações de espaços de trabalho <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Preparação de transferência <dataDir>/backups/transfer/ — uma bancada de trabalho, varrida pela rota que a grava
Nome do arquivo do snapshot <snapshot directory name>.zip
Teto de upload 8 GiB por POST /backup/restore
Retenção Snapshots da instalação: exclusão manual. Backups de espaços de trabalho: pipeline semanal, 30 dias por padrão

Os diretórios exports/, transfer/ e workspace-backups/ não são snapshots da instalação e ficam excluídos de server.listBackups. Apenas o último diretório tem retenção agendada; excluir um snapshot da instalação exige uma ação explícita do proprietário da instalação.