Skip to content

Object Storage (S3)

The verda object-storage commands provide AWS-CLI-style access to Verda's S3-compatible object storage (the oss alias is shorter: verda oss ls). They use a separate credential set (keys prefixed verda_s3_) so object-storage access is independent of your main API credentials while still sharing the profile system.

Every command works two ways: non-interactively with positional URIs and flags (for scripts, pipes, and AI agents), and interactively with a TUI when you omit the target on a terminal.


Command reference

Command Description
verda object-storage configure Set up S3 credentials (wizard or flags)
verda object-storage show Print active S3 credential status (no secrets)
verda object-storage ls List buckets, or list keys under a prefix
verda object-storage cp Copy between local and S3, or S3 and S3
verda object-storage mv Move (copy + delete source)
verda object-storage rm Delete one or many keys
verda object-storage sync Sync a directory and a prefix in either direction
verda object-storage mb Make bucket
verda object-storage rb Remove bucket (optionally force-empty first)
verda object-storage presign Generate a time-limited GET URL for a key
verda object-storage ls-uploads List incomplete multipart uploads (resumable)
verda object-storage abort-uploads Abort incomplete multipart uploads

Configure credentials

First create an access key in the Verda dashboard: log in → select your project → Project management → Credentials → Object Storage Access Keys.

Run the interactive wizard. The endpoint and region come pre-filled with defaults (https://objects.fin-03.verda.storage, us-east-1), so you normally just pick a profile and paste the access key and secret:

verda object-storage configure

Non-interactive (endpoint defaults if omitted; pass --endpoint for another region):

verda object-storage configure \
  --access-key AKIA... \
  --secret-key ...

Show the active configuration (no secrets are printed):

verda object-storage show
verda object-storage show --profile staging
Flag Description
--access-key S3 access key ID
--secret-key S3 secret access key
--endpoint S3 endpoint URL (defaults to https://objects.fin-03.verda.storage)
--region Region (defaults to us-east-1)
--profile Profile to write to (defaults to the active profile)
--credentials-file Override the credentials file path

S3 credentials are stored in the same credentials file as your API credentials (~/.verda/credentials), using verda_s3_-prefixed keys.


List buckets and objects

verda object-storage ls                              # list all buckets
verda object-storage ls s3://my-bucket               # top-level keys + prefixes (delimiter /)
verda object-storage ls s3://my-bucket --recursive   # every key under the bucket
verda object-storage ls s3://my-bucket --human-readable --summarize

On a terminal, running verda object-storage ls with no argument opens an interactive folder browser — drill into prefixes, run per-object actions, or multi-select objects to download.

Browsing buckets and objects with the interactive S3 browser


Copy files

# upload
verda object-storage cp ./local-file s3://my-bucket/key.txt

# download
verda object-storage cp s3://my-bucket/key.txt ./local-file

# server-side copy (S3 → S3, no data traverses the client)
verda object-storage cp s3://src-bucket/key s3://dst-bucket/key

# recursive directory upload
verda object-storage cp ./dir s3://my-bucket/prefix/ --recursive

# with include/exclude filters (match against relative path; * does not cross /)
verda object-storage cp ./dir s3://my-bucket/prefix/ --recursive \
  --include '*.go' --exclude '*_test.go'

# override content-type (otherwise inferred from extension)
verda object-storage cp ./file s3://my-bucket/key --content-type 'application/json'

# preview what would happen
verda object-storage cp ./dir s3://my-bucket/prefix/ --recursive --dryrun

# tune throughput for large transfers
verda object-storage cp ./big.bin s3://my-bucket/big.bin --concurrency 16 --part-size 32MiB
Flag Description
--recursive Copy a directory or prefix recursively
--include / --exclude Filter by relative path (filepath.Match; * does not cross /)
--content-type Override the content-type (otherwise inferred from extension)
--dryrun Print what would happen without transferring
--concurrency Number of concurrent parts for large transfers
--part-size Multipart part size (e.g. 32MiB)
--no-resume Force a fresh transfer, ignoring any saved progress

To upload without typing an s3:// URI, run verda object-storage cp <file> with no destination on a terminal — a wizard picks the destination bucket and folder for you:

Uploading with the cp wizard — pick a bucket and folder instead of typing the s3:// URI


Resumable large transfers

Single-file uploads and single-object downloads larger than the part size are multipart, parallel (5 concurrent parts by default), and resumable. If a transfer is interrupted (network drop, Ctrl+C, crash), re-run the exact same command and it continues — only the missing parts are sent or fetched:

# upload; if it breaks, run the SAME command again to resume
verda object-storage cp ./model.safetensors s3://my-bucket/models/model.safetensors

# download; re-run to resume (a partial <dest>.part is kept until it completes)
verda object-storage cp s3://my-bucket/models/model.safetensors ./model.safetensors

# force a fresh transfer, ignoring any saved progress
verda object-storage cp s3://my-bucket/models/model.safetensors ./model.safetensors --no-resume

Re-running an interrupted upload resumes only the missing parts

A few details worth knowing:

  • Resume reuses the same part size that the interrupted run used. Passing a different --part-size (or changing the file) is detected and the transfer restarts cleanly. Part sizes accept binary forms (MiB, GiB); the loose MB/M forms are also treated as binary (1MB = 1048576 bytes).
  • Resume state lives locally: uploads under ~/.verda/s3-uploads/, downloads under ~/.verda/s3-downloads/ (plus a <dest>.part file). The key is a hash of the source path + destination, so resume requires re-running with the same source and destination.
  • Incomplete uploads stage parts on the server that cost storage until completed or aborted. Use verda object-storage ls-uploads to list them (and pick one to resume) and verda object-storage abort-uploads to clean them up.

    Uploading with the cp wizard, interrupting, then resuming from the object-storage ls-uploads picker

  • No silent overwrites: if a local file of the same name already exists, an interactive download is saved as name-2.ext, name-3.ext, … A genuine resume of the same object keeps its original name so its .part is continued.

  • Recursive (--recursive), sync, and mv transfers are not yet resumable per-file.

Move files

mv has the same flag surface as cp; the source is removed on success.

verda object-storage mv ./tmpfile s3://my-bucket/final-name
verda object-storage mv s3://my-bucket/old-key s3://my-bucket/new-key

On a terminal, verda object-storage mv with no arguments (or a single s3:// source) opens an S3 → S3 move/rename wizard. Local ↔ S3 moves always require both explicit arguments.

Moving an object with the interactive move wizard


Sync directories

# local → S3
verda object-storage sync ./local-dir s3://my-bucket/prefix/

# S3 → local
verda object-storage sync s3://my-bucket/prefix/ ./local-dir

# remove destination files that don't exist in source (AWS-convention --delete)
verda object-storage sync ./a s3://bucket/ --delete

# treat any mtime difference as "changed" (not just newer-source)
verda object-storage sync ./a s3://bucket/ --exact-timestamps --dryrun

By default, sync copies a file when the source size differs or the source is newer. --exact-timestamps instead copies on any mtime difference.


Remove objects

verda object-storage rm s3://bucket/key
verda object-storage rm s3://bucket/prefix/ --recursive
verda object-storage rm s3://bucket/prefix/ --recursive --include '*.log' --yes
verda object-storage rm s3://bucket/prefix/ --recursive --dryrun

Warning

rm is destructive and prompts for confirmation unless --yes is passed. In agent mode, --yes is mandatory.

Deleting objects with the interactive browser — multi-select and a confirmation guard


Buckets

verda object-storage mb s3://new-bucket-name

verda object-storage rb s3://old-bucket              # only works if empty
verda object-storage rb s3://old-bucket --force      # empty the bucket first, then remove

rb prompts for confirmation unless --yes. --force implies a recursive delete of the bucket contents, so be sure before using it.


Presigned URLs

Generate a time-limited GET URL for an object:

verda object-storage presign s3://bucket/key                    # default 1h
verda object-storage presign s3://bucket/key --expires-in 15m
verda object-storage presign s3://bucket/key --expires-in 24h

The URL is printed to stdout (pipe-friendly) and the expiration hint goes to stderr, so it's safe to pipe:

verda object-storage presign s3://bucket/key --expires-in 30m | pbcopy

Multiple profiles

Profiles work across both API and S3 credentials. Create a second profile via:

verda object-storage configure --profile staging

configure and show take a local --profile flag. The other commands (ls, cp, rm, …) have no local --profile flag — select a profile with the global --auth.profile staging, the VERDA_PROFILE=staging environment variable, or persist it with verda auth use staging.

Info

configure writes to the profile you pick or name; it does not auto-follow the active profile the way the read commands do. If you create credentials for a non-active profile, point the read commands at it with --auth.profile <name>, VERDA_PROFILE, or switch with verda auth use <name>.


Output formats

All commands honour the global output flags:

  • --output table (default)
  • --output json / --output yaml — a single structured payload at the end
  • --agent — disables interactive prompts, implies JSON, and requires --yes for destructive operations
  • --debug — dumps SDK request/response metadata to stderr

Per-file progress lines (uploaded, downloaded, copied, moved, deleted) are only emitted when the format is table. Structured output produces exactly one payload so it stays parseable.


Interactive vs non-interactive

The interactive TUI triggers only when stdout is a terminal, you're not in --agent mode, and the output format is the default table. Otherwise an omitted target returns the command help (or a structured error in --agent).

Command Interactive trigger (on a TTY) Flow
configure any of --access-key/--secret-key/--endpoint missing credential wizard
ls no argument folder browser (drill in, per-object actions, multi-download)
cp no destination (and not a bare s3:// download) upload wizard (source → bucket → folder → confirm)
mb no argument prompts for the new bucket name
rb no argument bucket picker, then the destructive confirm
rm no argument folder browser; tick files at a level to delete (confirm + preview)
mv no args, or a single s3:// source S3 → S3 move/rename wizard

Esc steps back (ascends a folder or returns to the previous wizard step); Ctrl+C exits immediately.


Environment variables

Variable Description
VERDA_SHARED_CREDENTIALS_FILE Override the default credentials path (~/.verda/credentials)
VERDA_PROFILE Select the active profile for read/transfer commands