Ir al contenido

Copia de seguridad, exportación e importación

Todo lo que Control Center puede copiar, entregar o adoptar, y la forma exacta de cada artefacto. Para hacer una copia de seguridad de verdad, consulta Hacer copia de seguridad y restaurar; para entender por qué la persistencia está dividida de esta forma, consulta Espacios de trabajo y aislamiento.

Hay tres artefactos de copia de la base de datos, con ámbitos y políticas de eliminación distintos.

Artefacto Escrito por Forma Cubre
Instantánea de la instalación server.backupNow Un directorio con marca de tiempo Todas las bases de datos de la instalación
Copia de seguridad de un espacio de trabajo Pipeline Workspace backup Directorio con marca de tiempo con un archivo .db La base de datos de un espacio de trabajo
Exportación de un espacio de trabajo workspace.export Un único archivo .db 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 coherente, y nunca exige detener el servidor.

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

La estructura replica exactamente el directorio de datos activo, que es lo que hace que restaurar una instalación sea copiar de vuelta en lugar de traducir. El nombre del directorio es la marca de tiempo UTC con : y . sustituidos por -, de modo que es seguro para el sistema de archivos en Windows y se ordena cronológicamente como una cadena simple.

Las copias de seguridad programadas de espacios de trabajo 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 elimina únicamente las copias de seguridad de su propio espacio de trabajo más antiguas que la antigüedad 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 en el 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 espacio de trabajo capturado
workspaces[].workspace_id string El espacio de trabajo al que pertenece 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 of string Espacios de trabajo que la copia de seguridad 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 igualmente y el manifiesto indica qué falta.

server.listBackups informa de un indicador complete por instantánea. Es falso cuando el manifiesto falta 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 lista igualmente, porque una instantánea que un operador no puede ver es una instantánea que cree tener. Cuando el manifiesto no se puede leer, el listado recurre a la propia estructura e informa de los archivos <workspaceId>/workspace.db que encuentre; esos siguen siendo adoptables individualmente 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í (el archivo es este)
<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 prescindible: spaces/ contiene worktrees con 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 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 todas las claves de emparejamiento, credenciales de proveedores y ajustes de SSO de la instalación. Consulta Hacer copia de seguridad y restaurar para cubrir el resto.

Las RPC de copia de seguridad de la instalación y la exportación e importación de espacios de trabajo son solo para fullClient: un teléfono emparejado no puede activarlas. Todas están ausentes por completo —no se rechazan, faltan estructuralmente— en un servidor sin el puerto de copia de seguridad conectado, como el servidor de demostración.

Operación Tipo Ámbito 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 ámbito porque la fila que marca vive en el registro global; su manejador comprueba la pertenencia de quien llama al espacio de trabajo nombrado y exige owner.

La path de cada respuesta es una ruta del host del servidor.

De la más reciente a la más antigua, ordenadas por nombre de 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 del propio manifiesto: la pregunta que se hace un operador que poda instantáneas es cuánto ocupa el directorio, no cuánto pretendía escribir la copia de seguridad.

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

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

Condición Resultado
No es una base de datos SQLite legible, o no tiene workspace_meta Se rechaza. No se toca nada
El id de espacio de trabajo registrado ≠ el de destino Se permite y se registra. Así es como se duplica un espacio de trabajo o se restaura con un id nuevo
El id de instalación registrado ≠ esta instalación Se permite y se registra. Sus dispositivos emparejados e 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 Se rechaza

Cuando se acepta, la base de datos del espacio de trabajo de destino se cierra y se descarta del gestor antes de copiar el archivo encima (una conexión de drift abierta retiene el archivo y su -wal), y 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 están pobladas, pero su índice puede estar obsoleto.

Todas las operaciones anteriores hablan en rutas del lado del servidor, lo cual 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 imágenes. Quien llama 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 copias de seguridad en lugar de concatenarse a la raíz de las copias de seguridad, 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 obligatorio, o el cuerpo de una subida está vacío
403 Dispositivo desconocido o revocado, firma incorrecta, o quien llama carece del rol
404 No hay puerto de copia de seguridad en este host, o la instantánea o el archivo de espacio de trabajo indicados no existen
405 Se llama a /backup/restore con algo distinto de POST
413 El cuerpo de la subida supera los 8 GiB, por la longitud de contenido declarada o por los bytes leídos realmente
500 La exportación o el archivado falló en el lado del servidor

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

/backup/snapshot devuelve <name>.zip, con las entradas relativas a la raíz de la instantánea, de modo que descomprimirlo reproduce manifest.json + global.db + <workspaceId>/workspace.db. Las entradas se escriben en orden de clasificación, así que dos archivos comprimidos de la misma instantánea son idénticos.

/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 posibles, incluida una denegación.

Cosa Valor
Instantáneas <dataDir>/backups/<timestamp>/
Copias de seguridad programadas de espacios de trabajo <dataDir>/backups/workspace-backups/<workspaceId>/<timestamp>/workspace.db
Exportaciones de espacios de trabajo <dataDir>/backups/exports/<workspaceId>-<timestamp>.db
Preparación de transferencias <dataDir>/backups/transfer/ — un banco de trabajo, barrido por la ruta que escribe en él
Nombre del archivo de la instantánea <snapshot directory name>.zip
Techo de subida 8 GiB por POST /backup/restore
Retención Instantáneas de la instalación: eliminación manual. Copias de seguridad de espacios 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 se excluyen de server.listBackups. Solo el último directorio tiene retención programada; eliminar una instantánea de la instalación exige la acción explícita del propietario de la instalación.