Backup and Restore

What you'll accomplish: Create full or agents-only backups of your Hoziron platform state, list available backups, and restore from a backup archive — via the CLI or the API directly.

What gets backed up

A full backup (hoziron-cli backup create, no flags) captures everything under $HOZIRON_HOME needed to reconstruct the platform, confirmed from crates/platform/hoziron-core/src/backup/mod.rs:

ItemFile/PathDescription
Platform configconfig.tomlProvider settings, routing, server config
Environment secrets.envAPI keys and credentials, if present
API key storekeys.dbAuth tokens, RBAC key metadata
Credential vaultvault.db + keys/vault.keyThe encrypted credential vault and its master key
Legacy integration vaultvault.encPre-existing integration-credential vault, included for the same reason as vault.db — it's a credential store, so it belongs in backups too
Audit trail (current)data/audit_segments/Segmented, Merkle-chained audit log — every file in this directory
Audit trail (legacy)data/audit.dbIncluded if it still exists from before the segmented-audit migration
Kernel statedata/hoziron-kernel.db (+ -wal/-shm if present)Kernel-owned SQLite state
Core statedata/hoziron-core.db (+ -wal/-shm if present)Core-owned SQLite state
Agent definitionsdata/agents/Manifests, lifecycle state
Memorydata/memory/Agent KV store, session history
Workflowsdata/workflows/Definitions, run history
Schedulesdata/schedules/Cron and event-trigger definitions
Competenciesdata/competencies/Installed competency manifests
Skillsdata/skills/Installed skill packages
Integrationsdata/integrations/MCP server configs

An agents-only backup (--agents-only) captures only data/agents/ and data/memory/ — no config, no auth/vault state, no audit trail. Useful for migrating agents between environments without carrying over platform config or credentials.

Consistency caveat, straight from the source comment: the SQLite databases are included via a raw file copy. If the daemon is actively writing when the backup runs, the archive can contain a partially-written WAL and be inconsistent. For a guaranteed-consistent backup, stop the daemon first (or trigger the backup via the API while traffic is quiet) — there's no SQLite online-backup (VACUUM INTO) coordination in this path yet.

CLI usage

Create a backup

# Full platform backup — default path: $HOZIRON_HOME/backups/hoziron-backup-<timestamp>.tar.gz
hoziron-cli backup create

# Agents-only (skip config, auth, vault, audit)
hoziron-cli backup create --agents-only

# Custom output path
hoziron-cli backup create --output /mnt/nfs/hoziron-backup-2026-07-08.tar.gz
# short flag also works:
hoziron-cli backup create -o /mnt/nfs/hoziron-backup-2026-07-08.tar.gz

# JSON output for scripting
hoziron-cli backup create --json

The CLI is a thin client — it POSTs to the running daemon's /backup/create endpoint and prints the response. The daemon (not the CLI) performs the actual archive creation, so the backup file lands wherever $HOZIRON_HOME resolves on the server, not on whatever machine ran the CLI command — matters if you're using a remote CLI context.

List backups

hoziron-cli backup list
ID                                     CREATED                SCOPE        SIZE
a1b2c3d4-...                           2026-06-05 02:00:00    Full         12.4MB
e5f6g7h8-...                           2026-06-04 02:00:00    Full         11.8MB

Restore from backup

Restore is destructive — it replaces the current platform state. Running without --confirm is a safe dry-run: the CLI just prints a warning and returns, without contacting the server at all.

# Dry run (no API call made)
hoziron-cli backup restore /path/to/backup.tar.gz

# Actually restore
hoziron-cli backup restore /path/to/backup.tar.gz --confirm

# Skip checksum validation (not recommended)
hoziron-cli backup restore /path/to/backup.tar.gz --confirm --no-verify

The path you pass must be reachable by the daemon process, not the CLI's machine — the CLI sends the path string to /backup/restore, and the server resolves it (either as a backup ID it recognizes from its own backups/ directory, or as a path relative to that directory, or as an absolute path it can read directly).

Restart the server after restoring for the daemon to pick up the restored state cleanly:

hoziron-server

API usage

Routes are unprefixed — there's no /v1/ in the path; API versioning is header-based (Api-Version header, defaults to v1) rather than path-based.

Create a backup

curl -X POST http://localhost:4200/backup/create \
  -H "Content-Type: application/json" \
  -d '{"scope": "full"}'
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "path": "/home/user/.hoziron/backups/hoziron-backup-20260708_020000.tar.gz",
  "scope": "full",
  "created_at": "2026-07-08T02:00:00Z",
  "checksum": "sha256:abcdef...",
  "size_bytes": 13012480
}

List backups

curl http://localhost:4200/backup/list

Restore

curl -X POST http://localhost:4200/backup/restore \
  -H "Content-Type: application/json" \
  -d '{"file": "/path/to/backup.tar.gz"}'

All three routes require the appropriate RBAC action (BackupCreate, BackupList, BackupRestore) when auth is enabled — expect a 403 without the right role/key.

Backup archive format

A standard .tar.gz archive with a manifest written as the last entry:

hoziron-backup-20260708_020000.tar.gz
├── MANIFEST.json         # id, created_at, scope, hoziron_version, included_files
├── config.toml
├── .env
├── keys.db
├── vault.db
├── vault.enc
├── keys/
│   └── vault.key
└── data/
    ├── audit_segments/
    │   └── ...
    ├── audit.db          # only if a pre-migration legacy store still exists
    ├── hoziron-kernel.db
    ├── hoziron-core.db
    ├── agents/
    ├── memory/
    ├── workflows/
    ├── schedules/
    ├── competencies/
    ├── skills/
    └── integrations/

Alongside the archive itself, create_backup also writes a checksum sidecar file<output-path>.tar.gz.sha256 — and sets both the archive and the sidecar to file mode 0600 (they contain secrets). Keep that sidecar next to the archive if you copy it elsewhere; it's what the checksum-validation step on restore reads.

Integrity validation

Each backup's SHA-256 checksum is computed at creation time (written to the .sha256 sidecar) and validated by default on restore (skip with --no-verify). This catches storage or transfer corruption, not tampering by someone with write access to the archive and its sidecar — there's no cryptographic signature over the archive.

Configuration

An optional [backup] section in config.toml:

[backup]
schedule = "0 2 * * *"       # cron expression — parsed and validated, but not wired to a scheduler; automated backups don't actually run yet
retention = 7                # accepted, but nothing currently prunes old backups automatically
storage_path = "/mnt/backup/hoziron"
backup_on_shutdown = false   # accepted, but no shutdown hook currently creates a backup

All four fields deserialize into BackupConfig and are available to the platform, but none of them are consumed by any running code path — no cron loop reads schedule, nothing prunes by retention, and the graceful-shutdown sequence doesn't check backup_on_shutdown. Treat [backup] as config for a feature that isn't wired up; automate backups externally (a systemd timer or cron job calling hoziron-cli backup create).

Operational recommendations

Frequency: daily full backups for production, driven externally (systemd timer or cron, since [backup].schedule isn't active). More frequent if agents process high-value data.

Retention: keep at least 7 days of backups; for compliance environments, retain per your policy — [backup].retention won't prune for you.

Storage: off-host. The archive is a plain tar.gz — copy it to NFS, S3, or any durable storage after creation.

Pre-restore checklist:

  1. Stop the server process (Ctrl+C, kill <pid>, or systemctl stop hoziron)
  2. hoziron-cli backup restore <file> --confirm (checksum validated automatically unless --no-verify)
  3. Restart: hoziron-server
  4. Verify: hoziron-cli health, and check hoziron-cli licence status if the restored state predates a licence renewal

Security note: backups contain live secrets — .env, keys.db, vault.db, vault.key. Encrypt at rest if storing off-host; there's no built-in backup encryption yet.

Next steps


Related: