LibraLibra
LibraLibra
DocsBlogLibra
Getting Started
Architecture
Design
Commands
libra addlibra agentlibra alternateslibra applylibra archivelibra authlibra automationlibra bisectlibra blamelibra branchlibra bundlelibra cachelibra cat-filelibra check-attrlibra check-ignorelibra check-mailmaplibra checkoutlibra cherry-picklibra cleanlibra clonelibra cloudlibra code-controllibra codelibra commit-treelibra commitlibra completionslibra configlibra credentiallibra depslibra describelibra diff-fileslibra diff-indexlibra diff-treelibra difflibra dirtylibra fast-exportlibra fast-importlibra fetchlibra filelibra for-each-reflibra format-patchlibra fscklibra gclibra graphlibra greplibra hash-objectlibra hookslibra hydratelibra index-packlibra initlibra investigatelibra layerlibra lfslibra loglibra logfilelibra loginlibra logoutlibra ls-fileslibra ls-remotelibra ls-treelibra maintenancelibra medialibra merge-baselibra merge-filelibra mergelibra metadatalibra mvlibra noteslibra oplibra openlibra pack-objectslibra packagelibra prunelibra publishlibra pulllibra pushlibra read-treelibra rebaselibra refloglibra remotelibra repacklibra replacelibra rererelibra resetlibra restorelibra rev-listlibra rev-parselibra revertlibra reviewlibra revisionlibra rmlibra sandboxlibra servicelibra shortloglibra show-reflibra showlibra sparse-viewlibra stashlibra statslibra statuslibra switchlibra symbolic-reflibra taglibra update-indexlibra update-reflibra usagelibra verify-packlibra whoamilibra worktreelibra write-tree
API Reference
Policy
Commands

libra cloud

Command reference for `libra cloud`

Cloud backup and restore operations (D1/R2).

Synopsis

libra cloud sync [--force] [--batch-size <N>]
libra cloud restore [--repo-id <ID> | --name <NAME>] [--metadata-only]
libra cloud status [--verbose]

Description

libra cloud provides backup and restore capabilities using Cloudflare D1 (serverless SQLite) for object indexes and metadata, and Cloudflare R2 (S3-compatible object storage) for git objects. This enables full repository backup to the cloud with incremental sync support.

The sync workflow tracks which objects have been uploaded via an is_synced flag in the local object_index table. Before selecting work, sync reconciles the local .libra/objects store into object_index so older loose or packed objects are not skipped. On each default sync, objects are selected when they are locally unsynced or missing from D1, making repeated syncs efficient while still repairing stale local sync flags after a D1 database change. A --force flag allows re-syncing all indexed local objects and is the recovery path for R2 bucket-side data loss. After objects are synced, repository metadata (references/branches) is serialized to JSON and uploaded to R2, with a content hash check to avoid unnecessary uploads.

Each repository is identified by a UUID (libra.repoid config key) and optionally a human-readable project name (cloud.name config key or directory name). The project name is registered in a D1 repositories table for lookup during restore.

Restore can target a repository by UUID (--repo-id) or project name (--name). It downloads the object index from D1, optionally downloads objects from R2, restores metadata (references), and populates the working directory from HEAD.

Options

Subcommand: sync

Sync local repository to cloud. Uploads objects to R2 and indexes to D1.

FlagDescription
--forceSync all indexed local objects, regardless of local/D1 sync state. Useful for deliberately re-upserting every object or recovering after R2 bucket-side data loss.
--batch-size <N>Number of objects to process per batch. Default: 50. Must be at least 1. Smaller batches produce more frequent progress output; larger batches reduce overhead.
# Incremental repair sync
libra cloud sync

# Force re-sync everything
libra cloud sync --force

# Use smaller batches for verbose progress
libra cloud sync --batch-size 10

Subcommand: restore

Restore repository from cloud. Downloads object indexes from D1, objects from R2, and restores metadata and working directory.

FlagDescription
--repo-id <ID>UUID of the repository to restore. Mutually exclusive with --name. One of --repo-id or --name is required.
--name <NAME>Human-readable project name to restore. Looked up in the D1 repositories table. Mutually exclusive with --repo-id.
--metadata-onlyOnly restore the object index to the local database. Do not download objects from R2 or restore the working directory. Useful for inspecting what a repository contains before doing a full restore.
# Restore by repository ID
libra cloud restore --repo-id a1b2c3d4-e5f6-7890-abcd-ef1234567890

# Restore by project name
libra cloud restore --name my-project

# Only restore metadata (object index)
libra cloud restore --name my-project --metadata-only

Subcommand: status

Show the current cloud sync status for the repository.

FlagDescription
--verboseShow details of individual unsynced objects (up to 20).
# Show sync status summary
libra cloud status

# Show detailed status with unsynced object list
libra cloud status --verbose

Common Commands

# Initial sync to cloud
libra cloud sync

# Check sync progress
libra cloud status

# Detailed status showing pending objects
libra cloud status --verbose

# Force re-sync after a failed attempt
libra cloud sync --force

# Restore a repository by name into a fresh directory
libra init
libra cloud restore --name my-project

# Preview what would be restored without downloading objects
libra cloud restore --name my-project --metadata-only

Human Output

cloud sync (with objects to sync):

Starting cloud sync...
Found 42 objects to sync.
Progress: 42/42 synced, 0 failed
Sync complete: 42 synced, 0 failed
Syncing metadata...
Metadata synced (3 references).

cloud sync (nothing to sync):

Starting cloud sync...
No objects to sync.
Syncing metadata...
Metadata unchanged, skipping upload.

cloud restore:

Starting restore for repo: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Found 42 objects in cloud for repo.
Restored 42 object indexes to local database.
Restore complete: 38 downloaded, 4 skipped (already exist), 0 failed
Restoring metadata...
Metadata restored.
Restoring working directory to HEAD (abc1234)
Successfully restored working directory files.

cloud restore --metadata-only:

Starting restore for repo: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Found 42 objects in cloud for repo.
Restored 42 object indexes to local database.
Metadata-only restore complete.

cloud status:

Cloud Sync Status:
  Repo ID:       a1b2c3d4-e5f6-7890-abcd-ef1234567890
  Total objects: 42
  Synced:        40 (95%)
  Pending:       2

By object type:
  blob: 30/32 synced
  tree: 8/8 synced
  commit: 2/2 synced

cloud status --verbose:

Cloud Sync Status:
  Repo ID:       a1b2c3d4-e5f6-7890-abcd-ef1234567890
  Total objects: 42
  Synced:        40 (95%)
  Pending:       2

By object type:
  blob: 30/32 synced
  tree: 8/8 synced
  commit: 2/2 synced

Unsynced objects:
  abc123def456... (blob, 1024 bytes)
  789012abc345... (blob, 512 bytes)

Structured Output

--json and --machine are supported for cloud status and cloud sync. --json emits a command envelope and --machine emits the same envelope as a single NDJSON line.

{
  "ok": true,
  "command": "cloud.status",
  "data": {
    "repo_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "total_objects": 42,
    "synced": 40,
    "pending": 2,
    "synced_percent": 95,
    "by_type": [
      {
        "object_type": "blob",
        "total": 32,
        "synced": 30,
        "pending": 2
      }
    ]
  }
}

When --verbose is set, the status payload also includes up to 20 unsynced_objects entries with oid, object_type, and size.

cloud sync --json / --machine emits cloud.sync on successful sync runs:

{
  "ok": true,
  "command": "cloud.sync",
  "data": {
    "repo_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "project_name": "my-project",
    "total_unsynced": 42,
    "synced_count": 42,
    "failed_count": 0,
    "metadata": {
      "status": "synced",
      "references": 3
    },
    "agent_capture": {
      "status": "completed",
      "sessions_synced": 2,
      "sessions_failed": 0,
      "checkpoints_synced": 6,
      "checkpoints_failed": 0
    }
  }
}

cloud restore --json / --machine emits cloud.restore on successful restore runs:

{
  "ok": true,
  "command": "cloud.restore",
  "data": {
    "repo_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "metadata_only": false,
    "total_objects": 42,
    "indexes_restored": 42,
    "object_restore": {
      "downloaded": 30,
      "skipped": 12,
      "failed": 0
    },
    "metadata": {
      "status": "restored"
    },
    "agent_capture": {
      "status": "restored"
    }
  }
}

For cloud restore --metadata-only, the payload keeps metadata_only: true and omits object_restore.

cloud sync --progress=json emits NDJSON progress events to stderr (no legacy human progress text on stdout). Event names cover object, metadata, and agent-capture phases, for example:

{"event":"cloud_sync.start"}
{"event":"cloud_sync.objects.total","total":42}
{"event":"cloud_sync.objects.progress","synced":42,"total":42,"failed":0}
{"event":"cloud_sync.metadata.synced","references":3}
{"event":"cloud_sync.agent_capture.complete","sessions_synced":2,"sessions_failed":0,"checkpoints_synced":6,"checkpoints_failed":0}

cloud sync default mode still uses the legacy human progress output. cloud restore and cloud sync failures continue through Libra's standard CLI error machinery.

Environment Variables

Cloud operations require the following keys. Libra reads repo-local vault.env.* entries first, then global vault.env.*, then the matching environment variables. If all layers are missing for a required key, the command reports the key and asks you to configure it before retrying.

D1 (required for all operations)

KeyDescription
LIBRA_D1_ACCOUNT_IDCloudflare account ID
LIBRA_D1_API_TOKENCloudflare API token with D1 access
LIBRA_D1_DATABASE_IDD1 database UUID

R2 (required for sync and full restore)

KeyDescription
LIBRA_STORAGE_ENDPOINTS3-compatible endpoint URL
LIBRA_STORAGE_BUCKETBucket name
LIBRA_STORAGE_ACCESS_KEYAccess key ID
LIBRA_STORAGE_SECRET_KEYSecret access key
LIBRA_STORAGE_REGIONRegion (defaults to auto)

Note: When --metadata-only is used with restore, only D1 variables are required.

Design Rationale

Why D1/R2 specifically?

Libra targets Cloudflare's ecosystem for several reasons. D1 provides serverless SQLite, which aligns with Libra's local SQLite-based architecture: the same query patterns and data model work both locally and in the cloud. R2 provides S3-compatible object storage with no egress fees, which is critical for a VCS where objects are frequently downloaded. The combination provides a fully serverless backup backend with no infrastructure to manage.

Why not generic cloud storage?

Libra already has generic S3-compatible storage support via LIBRA_STORAGE_* environment variables for tiered object caching. The cloud command serves a different purpose: full repository backup including metadata (references, HEAD, config). This requires a structured database (D1) for the object index, not just a blob store. A generic backend would require implementing a metadata layer on top of every storage provider, which adds complexity without clear benefit. Users who need backup to other providers can use the object-level storage tiering instead.

Why a batch-size parameter?

Object sync involves uploading to R2 and then indexing in D1 for each object. For large repositories with thousands of objects, this can take significant time. The --batch-size parameter controls how many objects are processed before a progress report is printed. Smaller batches give more responsive feedback; larger batches reduce per-batch overhead. The default of 50 balances these concerns. A batch size of 1 is allowed for maximum granularity during debugging.

Why --repo-id and --name as mutually exclusive options?

Repository UUIDs are stable and unambiguous but not human-friendly. Project names are human-friendly but can conflict or be renamed. Making them mutually exclusive with one required ensures the user explicitly chooses their lookup strategy. The UUID is stored in local config (libra.repoid) and is authoritative; the name is a convenience alias stored in D1's repositories table.

Why does restore attempt to populate the working directory?

A bare object restore (indexes + objects) leaves the repository in a state where files exist in the object store but the working directory is empty. For most users, the goal of restore is to get back to a working state. Libra automatically checks out HEAD (or the main branch as fallback) after restoring objects. This matches user expectations and avoids an extra manual step. The --metadata-only flag skips this for users who only need the index.

Parameter Comparison: Libra vs Git vs jj

OperationLibraGitjj
Sync to cloudcloud syncN/A (use push to remote)N/A (use push to remote)
Force synccloud sync --forceN/AN/A
Batch sizecloud sync --batch-size <N>N/AN/A
Restore from cloudcloud restore --name <N>clone <url>git clone <url>
Restore by IDcloud restore --repo-id <ID>N/AN/A
Metadata-only restorecloud restore --metadata-onlyN/AN/A
Sync statuscloud statusN/AN/A
Verbose statuscloud status --verboseN/AN/A
BackendCloudflare D1 + R2Git remotes (SSH/HTTPS)Git remotes (SSH/HTTPS)
Incremental syncAutomatic (is_synced flag)Automatic (pack negotiation)Automatic (via Git)
Object verificationHash check on restoreHash check on transferHash check on transfer
Metadata backupAutomatic (references JSON)Included in push/fetchIncluded in push/fetch

Note: Neither Git nor jj have a built-in cloud backup command. They rely on pushing to remote repositories for backup and collaboration. Libra's cloud command fills a different niche: backing up the full repository state (including local branches, config, and object index) to a serverless cloud backend without requiring a Git server.

Error Handling

CodeCondition
LBR-REPO-001Not a libra repository
LBR-CLI-002Missing required Vault/env credential keys (lists which ones)
LBR-CLI-002Batch size must be at least 1
LBR-CLI-002Neither --repo-id nor --name provided for restore
LBR-CLI-003Repository with given name not found in D1
LBR-CONFLICT-002Project name already taken by another repository
LBR-IO-001D1 client initialization failure
LBR-IO-001Failed to create D1 tables
LBR-IO-001Database query failure
LBR-IO-002R2 upload failure
LBR-IO-002R2 download failure
LBR-IO-002Hash mismatch on restored object
LBR-IO-002Failed to save restored object to local storage
LBR-IO-002Metadata sync/restore failure

libra clone

Command reference for `libra clone`

libra code-control

Command reference for `libra code-control`

On this page

SynopsisDescriptionOptionsSubcommand: syncSubcommand: restoreSubcommand: statusCommon CommandsHuman OutputStructured OutputEnvironment VariablesD1 (required for all operations)R2 (required for sync and full restore)Design RationaleWhy D1/R2 specifically?Why not generic cloud storage?Why a batch-size parameter?Why --repo-id and --name as mutually exclusive options?Why does restore attempt to populate the working directory?Parameter Comparison: Libra vs Git vs jjError Handling