Skip to content

CLI

Install the LoonFS CLI and manage profiles, namespaces, files, history, and maintenance.

The loonfs CLI manages LoonFS profiles, namespaces, filesystem content, revision history, and maintenance. It can connect directly to object storage in embedded mode or to a LoonFS server in remote mode.

Install the latest release on macOS or Linux with the install script:

Terminal window
curl -fsSL https://install.loonfs.com | sh
loonfs version

With Homebrew:

Terminal window
brew install loonfs/tap/loonfs

Or build the CLI from source:

Terminal window
cargo build --release -p loonfs-cli
cp ./target/release/loonfs ~/.local/bin/loonfs

This local embedded profile is useful for trying LoonFS without a server or cloud credentials. local-fs is intended for development and testing; use a cloud object store or remote profile for a durable deployment.

Terminal window
loonfs --no-input profile create local default \
--root "$HOME/.loonfs/data"
loonfs namespace create demo
loonfs use demo
printf 'Hello from LoonFS\n' | loonfs put - /hello.txt
loonfs ls /
loonfs cat /hello.txt

Run loonfs init without flags for an interactive setup. loonfs current shows the active profile and its default namespace.

A profile tells the CLI where LoonFS runs. Commands use the default profile and namespace unless you pass --profile or --namespace.

  • Embedded profiles access object storage directly from the CLI process. Supported stores are local filesystem, Amazon S3, Cloudflare R2, Google Cloud Storage, and Azure Blob Storage.
  • Remote profiles connect to a running LoonFS server. Use this mode when many clients need to write concurrently or when object-store credentials should remain on the server.

For example, create an embedded S3 profile using the standard AWS credential environment variables:

Terminal window
export AWS_ACCESS_KEY_ID={access_key_id}
export AWS_SECRET_ACCESS_KEY={secret_access_key}
loonfs --no-input profile create s3 production \
--bucket {bucket_name} \
--region {aws_region}
loonfs profile use production

Or connect to a LoonFS server:

Terminal window
export LOONFS_AUTH_TOKEN={auth_token}
loonfs --no-input profile create remote production \
--server-url https://loonfs.example.com
loonfs profile use production

Embedded mode is production-capable when backed by a compatible object store, but only one writer session can own a namespace at a time. Concurrent embedded writers can fence one another; a fenced command commits nothing and is safe to rerun. A LoonFS server coordinates concurrent remote clients.

TaskCommands
Profilesprofile create, profile list, profile show, profile update, profile delete, profile use
Namespacesnamespace create, namespace show, namespace fork, namespace delete, use, current
Snapshotssnapshot create, snapshot list, snapshot extend, snapshot delete
Readls, stat, cat, get, grep
Writeput, mkdir, mv, cp, rm
Attributesannotate
History and recoveryrevisions, restore, trash, undelete, changes
Maintenancemaintenance loop, maintenance metadata, maintenance flush, maintenance retention advance, maintenance gc, maintenance checkpoint and maintenance index commands, maintenance store probe

Common filesystem operations look like this:

Terminal window
loonfs put ./report.md /reports/report.md
loonfs mkdir -p /archive/2026
loonfs cp /reports/report.md /archive/2026/report.md
loonfs mv /reports/report.md /reports/final.md
loonfs stat /reports/final.md
loonfs get /reports/final.md ./final.md
loonfs rm /reports/final.md

Use -r with put, get, cp, or rm to operate on a directory tree. Moving a directory is already atomic and does not require -r.

Create a reserved point-in-time view, then pass its ID to supported reads:

Terminal window
loonfs snapshot create demo --name nightly-export --ttl-ms 3600000
loonfs snapshot list demo
loonfs use demo
loonfs ls /reports --snapshot-id {snapshot_id}
loonfs stat /reports/summary.csv --snapshot-id {snapshot_id}
loonfs get /reports/summary.csv --snapshot-id {snapshot_id}
loonfs changes --snapshot-id {snapshot_id}
loonfs snapshot extend demo {snapshot_id} --ttl-ms 3600000
loonfs snapshot delete demo {snapshot_id}

The snapshot_id automatically selects the file revision as of that snapshot, so cat and get cannot combine it with --revision. See Snapshots for lease and limit behavior.

loonfs grep searches file contents and can restrict results to a subtree:

Terminal window
loonfs grep 'TODO|FIXME' --path-prefix /projects -i

Patterns support regular expressions without backreferences or lookaround assertions. Indexed searches need a run of at least three consecutive literal bytes, typically three ASCII characters. Use --allow-scan to permit a capped exhaustive scan when a pattern cannot use the index, or --allow-stale to accept indexed-only results when the unindexed tail exceeds the scan budget.

Filesystem commands that commit (put, mkdir, rm, mv, cp, restore, and undelete) accept -m or --message to annotate the commit. They also accept --commit-id as an idempotency key: rerun the same request with the same ID to retry safely. When omitted, LoonFS generates an ID and includes it in the result.

Terminal window
loonfs put ./proposal.md /proposals/acme.md \
--message "Add initial proposal" \
--commit-id proposal-acme-v1

Use --expected-revision with put --force for a conditional replacement that fails if another writer changed the file first.

Deletes are recoverable. loonfs rm returns the deletion handle, and loonfs trash lists it again. Pass that handle to loonfs undelete; omit the destination path to restore the original binding.

Terminal window
loonfs trash
loonfs undelete --inode {inode_id} --deletion-seq {change_seq}

loonfs revisions lists a file’s retained revisions, while loonfs restore writes an older revision as the new current revision.

loonfs put and loonfs get stream large files with bounded memory and show transfer progress on stderr. Recursive transfers use bounded concurrency and commit file by file.

Interrupted transfers are resumable where the transport method can support it. If a transfer is interrupted, simply rerun the same command. Downloads resume from a verified partial file when the transport is streamable; server-proxied downloads restart. Remote direct-multipart uploads larger than 8 MiB also resume where they left off. Embedded or proxied uploads and uploads from stdin restart from the beginning.

The CLI works directly from any agent or automation environment that can run shell commands. Use the global flags to make execution deterministic and machine-readable:

Terminal window
loonfs --json --no-input --no-progress stat /reports/final.md
  • --json emits a stable JSON success or error envelope.
  • --no-input fails instead of prompting.
  • --no-progress suppresses transfer progress events on stderr.
  • --config selects a config file explicitly; LOONFS_CONFIG is the environment-variable equivalent.
  • --no-retry disables bounded retries for transient server and transport failures.

loonfs config path explains which configuration file is set, and loonfs config show prints the contents (secrets redacted)

Commands that mutate state accept --actor-id <stable-id>, which overrides LOONFS_ACTOR_ID and the profile’s actor ID. If none are set, the default is loonfs-cli.

loonfs cat and loonfs get ... - stream raw file bytes to stdout and therefore reject --json.

Remote servers run maintenance for namespaces they touch or are explicitly assigned. Embedded deployments must kick off maintenance for every namespace explicitly:

Terminal window
# Host maintenance until interrupted.
loonfs maintenance loop --namespaces demo
# Catch the namespace up and exit, suitable for a scheduled job.
loonfs maintenance loop --namespaces demo --drain

Other maintenance commands manage WAL flushing, retention, garbage collection, checkpoints, object-store contract probes, and the content index. Run loonfs maintenance --help before using these commands in production.

Run loonfs --help or loonfs <command> --help for the installed version’s exact flags. The repository also contains the complete CLI reference.