Ir al contenido

Respaldo, exportación e importación

Todo lo que Control Center puede copiar, entregar o adoptar, y la forma exacta de cada artefacto. Para crear un respaldo de verdad, consulta Respaldar y restaurar; para entender por qué la persistencia está dividida así, consulta Espacios de trabajo y aislamiento.

Hay tres artefactos de copia de bases de datos, con alcances y políticas de eliminación distintos.

Artefacto Escrito por Forma Abarca
Instantánea de la instalación server.backupNow Un directorio con marca de tiempo Todas las bases de datos de la instalación
Respaldo de espacio de trabajo Pipeline Workspace backup Directorio con marca de tiempo y un .db La base de datos de un espacio de trabajo
Exportación de espacio de trabajo workspace.export Un archivo .db único La base de datos de un espacio de trabajo

Todos se escriben con VACUUM INTO de SQLite, que es seguro frente a una base de datos WAL activa: toma una transacción de lectura, produce una copia desfragmentada y transaccionalmente consistente, y nunca requiere detener el servidor.

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

La estructura refleja exactamente el directorio de datos activo, y eso es lo que hace que restaurar una instalación sea una copia de vuelta y no una traducción. El nombre del directorio es la marca de tiempo UTC con : y . reemplazados por -, así que es seguro para el sistema de archivos en Windows y se ordena cronológicamente como una cadena simple.

Los respaldos de espacio de trabajo programados viven aparte, en <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db. No incluyen un manifiesto ni global.db y no son instantáneas de la instalación. El paso de retención del pipeline semanal solo elimina los respaldos de su propio espacio de trabajo con una antigüedad mayor a la configurada (30 días de forma predeterminada); las instantáneas de la instalación creadas a mano nunca se rotan con ese paso. server.listBackups solo lista instantáneas de la instalación, incluidas las incompletas.

Campo Tipo Significado
version int Versión del formato del manifiesto. Actualmente 1
created_at ISO-8601 UTC Cuándo se tomó la instantánea
global.file string Siempre global.db
global.schema_version int Versión del esquema de GlobalDatabase al momento de la captura
global.bytes int Tamaño del global.db escrito
workspace_schema_version int Versión del esquema de WorkspaceDatabase compartida por todos los archivos de espacio de trabajo
workspaces[] array Una entrada por cada espacio de trabajo capturado
workspaces[].workspace_id string El espacio de trabajo que contiene este archivo
workspaces[].file string Ruta relativa a la raíz de la instantánea, <workspaceId>/workspace.db
workspaces[].bytes int Tamaño de ese archivo
skipped_workspaces[] array de string Espacios de trabajo que el respaldo no pudo capturar

Un espacio de trabajo se omite cuando está registrado pero nunca se ha escrito en él (así que todavía no existe ningún archivo), o cuando su VACUUM INTO falló. En cualquier caso, la instantánea se completa igual y el manifiesto nombra lo que falta.

server.listBackups reporta una marca complete por instantánea. Es falsa cuando el manifiesto está ausente o no se puede analizar, cuando falta global.db, o cuando el manifiesto nombra un archivo de espacio de trabajo que no está en el disco.

Una instantánea incompleta se sigue listando, porque una instantánea que un operador no ve es una instantánea que cree tener. Cuando el manifiesto no se puede leer, el listado recurre a la propia estructura e informa los archivos <workspaceId>/workspace.db que encuentre; esos archivos se siguen pudiendo adoptar de forma individual mediante workspace.import, aunque la instantánea en su conjunto no pueda restaurar una instalación.

Ambos artefactos son solo bases de datos. El directorio de un espacio de trabajo contiene más que su base de datos, y nada del resto viaja:

Ruta ¿En una instantánea? ¿En una exportación de espacio de trabajo?
global.db Sí No
<workspaceId>/workspace.db Sí Sí (es el archivo)
<workspaceId>/blobs/ No No
<workspaceId>/skills/ No No
<workspaceId>/agents/ No No
<workspaceId>/chat_credentials/ No No
<workspaceId>/spaces/<spaceId>/ No No
<workspaceId>/pr_clones/ No No
secrets.json No No
models/ No No
meetings/<meetingId>/ No No
rigs/ No No

Parte de eso es desechable: spaces/ contiene worktrees copy-on-write que se reaprovisionan desde los repos, pr_clones/ es una caché, models/ se vuelve a descargar y rigs/ es estado de la máquina. Parte no lo es: blobs/ contiene las imágenes pegadas a las que apuntan filas de la base de datos, skills/ y agents/ contienen los archivos con los que se ejecuta un agente, y secrets.json contiene cada clave de emparejamiento, credencial de proveedor y ajuste de SSO de la instalación. Consulta Respaldar y restaurar para cubrir el resto.

Los RPC de respaldo de la instalación y la exportación/importación de espacios de trabajo son solo para fullClient: un teléfono emparejado no puede desencadenarlos. Todos están totalmente ausentes —no se rechazan, faltan a nivel estructural— en un servidor sin puerto de respaldo conectado, como el servidor de demostración.

Operación Tipo Alcance Rol mínimo Argumentos Devuelve
server.backupNow mutación Instalación propietario de la instalación ninguno {ok, path}
server.listBackups lectura Instalación propietario de la instalación ninguno {backups: [...]}
server.deleteBackup mutación Instalación propietario de la instalación name {ok}
workspace.export lectura Espacio de trabajo admin ninguno {ok, path}
workspace.import mutación Espacio de trabajo owner source_path {ok, workspace_id}
workspace.delete mutación Instalación* owner id Fila del registro marcada como eliminada
  • workspace.delete no tiene alcance porque la fila que marca vive en el registro global; su manejador comprueba la pertenencia del llamador al espacio de trabajo indicado y requiere owner.

path en cada respuesta es una ruta en el host del servidor.

Las más recientes primero, ordenadas por el nombre del directorio (que es la marca de tiempo, así que el orden se mantiene incluso para una instantánea cuyo manifiesto no se pudo leer).

{
"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 se omite cuando el manifiesto no se pudo leer. bytes en el nivel superior es el tamaño real en disco de todo el directorio, no la suma que trae el manifiesto: la pregunta que se hace un operador que poda instantáneas es cuánto ocupa el directorio, no cuánto pretendía escribir el respaldo.

Cada workspaces[].path es exactamente lo que workspace.import toma como source_path. Es a propósito: «restaurar este espacio de trabajo desde esta instantánea» es la operación de importación, así que ambas no pueden divergir en tratos distintos del mismo archivo.

Antes de reemplazar nada, el archivo candidato se abre en solo lectura con una conexión SQLite en crudo de vida corta y se lee su fila workspace_meta.

Condición Resultado
No es una base de datos SQLite legible, o no tiene workspace_meta Rechazado. No se toca nada
El id de espacio de trabajo registrado ≠ el destino Permitido, se registra. Así se duplica un espacio de trabajo o se restaura con un id nuevo
El id de instalación registrado ≠ esta instalación Permitido, se registra. Sus dispositivos emparejados y sus ids de usuario pertenecen a esa instalación y no se resolverán aquí
Id de espacio de trabajo no válido, o el archivo no existe Rechazado

Al aceptarse, la base de datos del espacio de trabajo de destino se cierra y se quita del administrador antes de copiar el archivo encima (una conexión de Drift abierta mantiene tomado el archivo y su -wal); luego se vuelve a abrir para que beforeOpen reinstale los disparadores de FTS y de sincronización, y los índices FTS se reconstruyen: las tablas de contenido de un archivo importado quedan pobladas, pero su índice puede estar desactualizado.

Todas las operaciones anteriores hablan en rutas del lado del servidor, lo que es una respuesta completa solo cuando el servidor es tu propia máquina. Estas tres transportan los bytes, en el mismo carril firmado con PSK que usan el proxy de medios y el almacén de blobs. El llamador firma una cadena de destino con la clave precompartida de su dispositivo y pasa la firma como s.

Ruta Método Consulta Destino firmado Requiere
/backup/workspace GET w, d, s backup-workspace:<workspaceId> admin del espacio de trabajo
/backup/snapshot GET n, d, s backup-snapshot:<name> propietario de la instalación
/backup/restore POST w, d, s backup-restore:<workspaceId> propietario del espacio de trabajo

w es un id de espacio de trabajo, n un nombre de directorio de instantánea, d el id del dispositivo que llama y s la firma. n se resuelve contra el listado de respaldos en lugar de concatenarse a la raíz de respaldos, así que la ruta no puede apuntarse a un directorio que el listado no habría mostrado.

Estado Causa
400 Falta un parámetro de consulta requerido, o el cuerpo de una subida está vacío
403 Dispositivo desconocido o revocado, firma incorrecta, o el llamador no tiene el rol
404 No hay puerto de respaldo en este host, o la instantánea o el archivo de espacio de trabajo indicado no existe
405 Se llamó a /backup/restore con algo distinto de POST
413 El cuerpo de la subida supera los 8 GiB, ya sea por el content-length declarado o por los bytes realmente leídos
500 La exportación o el archivado falló en el servidor

Ambas descargas responden Cache-Control: no-store con Accept-Ranges: none. Cada solicitud acuña una copia nueva y la elimina una vez transmitida, así que una respuesta en caché o reanudada empalmaría bytes de dos exportaciones distintas en un archivo que parece válido y no lo es.

/backup/snapshot devuelve <name>.zip, con entradas relativas a la raíz de la instantánea, de modo que al descomprimir se reproduce manifest.json + global.db + <workspaceId>/workspace.db. Las entradas se escriben en orden, así que dos archivos comprimidos de la misma instantánea son el mismo archivo.

/backup/restore transmite el cuerpo directamente a un archivo de preparación en lugar de almacenarlo en búfer, lo acota antes y durante la lectura, y elimina el archivo preparado en todas las salidas, incluido un rechazo.

Elemento Valor
Instantáneas <dataDir>/backups/<timestamp>/
Respaldos de espacio de trabajo programados <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Exportaciones de espacio de trabajo <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Preparación de transferencias <dataDir>/backups/transfer/ — un banco de trabajo, barrido por la ruta que lo escribe
Nombre del archivo comprimido de la instantánea <snapshot directory name>.zip
Límite de subida 8 GiB por POST /backup/restore
Retención Instantáneas de la instalación: eliminación manual. Respaldos de espacio de trabajo: pipeline semanal, 30 días de forma predeterminada

Los directorios exports/, transfer/ y workspace-backups/ no son instantáneas de la instalación y quedan excluidos de server.listBackups. Solo el último directorio tiene retención programada; eliminar una instantánea de la instalación requiere una acción explícita del propietario de la instalación.