Skip to main content
The github.com/cloudstic/cli package exposes a high-level Go API that mirrors the CLI commands. Use it to embed backup, restore, and repository management directly into your Go programs.

Installation

Import the root package:
Storage backends and keychain helpers live in sub-packages:
Two further packages turn user-facing configuration into live objects, and the split between them decides what importing costs you:
pkg/config holds resolved configuration values and performs no I/O against a store or a provider, so reading and validating configuration pulls in no cloud SDK. pkg/open constructs stores, sources, keychains and clients from those values, and necessarily links whichever provider SDK you use. If you only need to inspect configuration, import the first and not the second.

Quick Start

Storage Backends

All backends implement store.ObjectStore. Pass the raw store to InitRepo and NewClient.

Local

Amazon S3 (and S3-compatible)

Backblaze B2

SFTP

Keychain

The keychain resolves credentials to a master key. Build a keychain.Chain before calling InitRepo or NewClient.

Initializing a Repository

InitRepo is a package-level function that runs on the raw (unencrypted) store. It only needs to be called once per repository.

Init Options

InitResult

Example

Inspecting a Repository

These package-level functions read repository state from the raw store without requiring the encryption key — useful for deciding whether to prompt for credentials before calling NewClient.
LoadRepoConfig(ctx, rawStore, encryptionKey) (*RepoConfig, error) reads the full marker (not just its status) and requires the encryption key for a sealed repository. UpgradeRepoFormat stamps the on-disk format version; NewClient/Backup/Prune/Forget call it for you as part of normal operation, so most callers never need it directly.

Creating a Client

NewClient reads the repository config, resolves the master key via the keychain, and builds the encryption/compression/packfile decorator chain internally.

Client Options

WithEncryptionKey is intended for SaaS scenarios where the master key is resolved externally. For typical use, prefer WithKeychain.
client.Store() returns the underlying store.ObjectStore (the fully decorated store NewClient built), for callers that need lower-level access alongside the Client API.

Backup

Creates a new backup snapshot from the given source.

Backup Options

BackupResult

Example

Sources

Sources implement source.Source. Available implementations:

Restore

Writes the snapshot’s file tree as a ZIP archive to w. Pass io.Discard for a dry run. snapshotRef accepts "", "latest", a bare hash or unique hash prefix, or "snapshot/<hash-or-prefix>".

Restore Options

RestoreResult

Example

Restoring directly to a directory

Writes files directly to outputDir instead of a ZIP archive. Takes the same RestoreOptions and returns the same RestoreResult.

List

Lists all snapshots in the repository. Returns them sorted oldest-first.

List Options

ListResult

SnapshotEntry.Snap is a core.Snapshot, which carries Seq int, Source *core.SourceInfo (Type, Account, Path, …), Tags []string, and Meta map[string]string. SourceInfo may be nil for snapshots written before source identity was tracked.
These types are declared in github.com/cloudstic/cli/internal/core, which external modules cannot import directly — Go’s internal/ rule blocks the import statement. You don’t need to. The root cloudstic package re-exports each of them as a type alias, so you can name them explicitly:
Because a Go alias denotes the identical type, these are interchangeable with what the Client API returns — you can declare variables, write helper function signatures, and implement interfaces against them. Reading exported fields off returned values (entry.Snap.Seq, meta.Name) works without naming the types at all, as this example does.

Example

LsSnapshot

Loads all file metadata from a snapshot and returns the full directory tree. Accepts "latest", a bare hash or unique hash prefix, or "snapshot/<hash-or-prefix>".

LsSnapshot Options

LsSnapshotResult

See the note above about core.Snapshot/core.FileMeta and the internal/ import restriction.

Find

Locates files across every snapshot in the repository without you having to know which snapshot holds them. Unlike the other read operations, Find takes a snapshot as output rather than input: by default it searches every snapshot and reports, for each matching file, the versions it has had and which snapshots each version lives in. It is a pure read path — no lock is taken and nothing is written.

Find Options

Entry predicates (all given predicates must match): Snapshot selectors (which snapshots are searched): Presentation and execution: Two helpers parse the string forms the CLI accepts, for callers building SizeCompare/time values programmatically:

FindResult

FileMatch has two convenience methods: Path() returns the newest version’s first path, and LatestSnapshot() returns the newest snapshot holding the newest version — the one a follow-up Restore would target.

Example

Finding duplicate content:

Diff

Compares two snapshots and returns the set of added, modified, and removed files. Each argument accepts "latest", a full hash, or a unique hash prefix.

Diff Options

Snapshot reference errors

Snapshot readers return sentinel errors that you can inspect with errors.Is:
The same sentinels apply to Restore, RestoreToDir, LsSnapshot, and snapshot selectors passed to Find.

DiffResult

Example

Prune

Removes unreachable objects (mark-and-sweep garbage collection). Run after Forget to reclaim storage.

Prune Options

PruneResult

Forget

Remove a specific snapshot

Apply a retention policy

Forget Options

PolicyResult

GroupKey and KeepReason are internal types you can read fields from (as in the example below) without importing them — see the note under List.

Example

Check

Verifies repository integrity by walking the full reference chain (snapshots → HAMT nodes → filemeta → content → chunks).

Check Options

CheckResult

Example

BreakLock

Removes stale repository lock files. Returns the list of removed locks (empty slice if none found).

ErrRepoLocked

Backup, Restore, and Prune return ErrRepoLocked when the repository is already held by another operation. Check for it with errors.Is and prompt the caller toward BreakLock rather than treating it as a generic failure:

Cat

Fetches the raw (decrypted, decompressed) data for one or more object keys. Useful for debugging and inspection.

CatResult

Object Key Namespaces

Example

Key Management

These package-level functions operate on the raw (unencrypted) store.

List key slots

Returns metadata for all key slots. Does not require authentication. Slot metadata is stored unencrypted.

Change password

Replaces the password key slot. kc must unlock the current master key. pwd supplies the new password. Use PasswordString for a known value at call time:
Use PasswordProviderFunc when the new password must be obtained lazily (e.g. interactive prompt):

Add recovery key

Generates a BIP39 recovery key slot and returns the 24-word mnemonic. kc must unlock the current master key.
A distinct Label lets a repository hold several recovery keys, all valid at once. Without Replace: true, adding a recovery key under a label that already exists returns a *keychain.SlotExistsError and writes nothing — this protects a previously issued mnemonic from being silently invalidated.

Workstation Setup and Source Discovery

These are no longer part of the client library. Workstation onboarding — discovering local backup candidates, proposing a set of profiles, and applying that plan — moved to an internal package, because it is a CLI wizard rather than a library capability: none of it needed a repository client, and the entry points were package-level functions rather than Client methods.Use the CLI instead:
The profiles file those commands write is still readable and writable programmatically — see Backup Profiles below.

Backup Profiles

The profiles YAML format lives in github.com/cloudstic/cli/pkg/profile. It is a separate package from the client precisely so that reading or writing a user’s profiles does not require opening a repository:
Save validates before writing, so a malformed secret reference is rejected there rather than at backup time. The failure is a *secretref.Error, so you can branch on Kind rather than matching on the message:
profile.DefaultPath("") returns where the file lives when the user names no path — profiles.yaml inside the config directory, honouring CLOUDSTIC_CONFIG_DIR. Use it so your program reads the same file the cloudstic CLI does rather than a second one that silently disagrees. It resolves a path without touching the filesystem, so asking the question creates nothing.

Acting on a Profile

Reading a profile is one thing; using one is another. pkg/open turns a named profile into a connected client in one call:
This is the one-call form of the explicit sequence, which you want instead whenever something has to happen in between — displaying the resolved configuration, diffing it, or deciding something from it before connecting:
A client, once returned, is already connected — so anything you want to override must be decided before this point, not after.

Layering Your Own Configuration

If your program has a configuration mechanism of its own — command-line flags, its own file, a form — WithDecided layers it over the profile, with the same precedence the cloudstic CLI applies to its flags. Every field you name is taken from your value, and the profile supplies the rest:
config.FieldsSetIn reports which fields your value is non-empty for, which is the right answer when your mechanism has no notion of “present but empty”. When empty is a choice you need to keep — -password "" meaning “no password”, as the CLI treats it — name the fields explicitly instead:
The field names are typed constants rather than strings, because the profiles file and the CLI spell the same field differently — s3_access_key against -s3-access-key — and a misspelled string silently meant “not decided”, which would connect you with a credential you had not chosen. config.StoreFields() and config.BackupFields() enumerate the complete set, so iterating them keeps your mapping current as fields are added; Field.ProfileKey() renders the profiles-file spelling for an error message.
Two groups of fields behave differently on purpose. Location and KMS settings are taken only when the profile actually names one, so a silent profile leaves what you had. Credentials are taken whenever you have not decided them, empty included — selecting a profile clears an ambient credential, because a profile is an explicit choice of which store to talk to, and reaching it with half a credential set inherited from the environment would be worse than failing to reach it.
A field you have decided is never resolved, so a broken secret reference on a field you are about to replace is not an error.

Backing Up From a Profile

The same layering applies to what a profile says to back up. config.Backup holds the resolved form, and open.Backup constructs both the source and the options a backup runs with:
open.Backup returns the source and the options together rather than as two calls, because they share a derived value. The snapshot records a hash of the active exclude patterns, and the next backup compares its own against it to decide between an incremental scan and a full rescan. The patterns come from two places — Excludes and the file named by ExcludeFile — so a hash computed without reading that file describes a different exclude set than the one in force, and every subsequent run reads the difference as “the patterns changed”. Getting the source and the options from one call is what keeps them consistent. If you supply your own source.Source implementation, use open.BackupOptions(cfg) for the options and apply cfg.Source.Excludes yourself — otherwise the recorded hash describes filtering that is not happening. source.ExcludeHash is exported if you need to compute it directly.

Secret References

Store and source credentials can be written as scheme://path references instead of inline secrets. github.com/cloudstic/cli/pkg/secretref resolves them, and pkg/secretref/backends holds the schemes Cloudstic ships with: env://, file://, config-token://, keychain://, secret-service:// and wincred://.
Failures are typed, so you can tell a malformed reference from a missing value from a backend that is not available on this platform:

Adding your own scheme

Backend is a single method, so a custom scheme — Vault, a cloud KMS, your own service — is small. backends.Default() returns a fresh map on every call, which is what lets you extend the built-in set rather than replace it:
Use secretref.NewError for failures so callers can branch on Kind the same way they do for the built-in backends.
Implement WritableBackend as well (adding Scheme, DisplayName, WriteSupported, DefaultRef, Exists and Store) if the scheme should also be offered when the CLI and TUI write a secret, rather than only when resolving one.

Choosing where managed tokens live

The config-token:// backend stores tokens itself, encrypted at rest, and by default puts them in Cloudstic’s own config directory — CLOUDSTIC_CONFIG_DIR or the OS default. For an embedding program that is usually the wrong place, and an environment variable is a poor way for a library to be configured:
The salt that derives the at-rest encryption key lives in that directory too. Two backends pointed at different directories therefore hold different keys — tokens written under one are not readable under the other. Changing the directory of an existing deployment orphans whatever was already stored there.

Progress Reporting

cloudstic.Reporter receives progress events during long-running operations:
Pass your reporter to NewClient:
If WithReporter is omitted, all progress output is suppressed (no-op default).

Complete Example: Automated Backup

See Also