ExStorageServiceCli
ess is the standalone S3 client from ExStorageService. It provides native named-endpoint workflows, an AWS-style s3 namespace, and model-backed s3api commands. The compatibility baseline is AWS CLI 2.31.18; implementation and provider evidence remain scoped. A command appearing in help is not proof of full AWS or mc parity.
Install
mix escript.install hex ex_storage_service_cli
Add ~/.mix/escripts to PATH. Building/installing requires Elixir 1.18+, Erlang/OTP, a C11 compiler (CC, or cc on PATH), and OTP development headers. The escript embeds the compiled native library and pager helper. Running it requires Erlang/OTP with the matching native OS/CPU/OTP major, but no C compiler, Mix project, storage server, Phoenix, or database. Build on the target platform. Package/runtime probes pass on Linux x86_64 with Elixir 1.18.0/OTP 27, 1.18.5/OTP 28 and 1.19.6/OTP 28, and macOS 26 arm64/x86_64 with Elixir 1.19.6/OTP 28. Other combinations remain unverified. Interactive paging is currently Linux-only.
Choose a frontend
ess version
ess --help
ess s3 --help
ess s3api head-object --help
# Native legacy profile configuration remains supported.
ess configure
ess mb example-bucket
ess cp ./file.txt s3://example-bucket/file.txt
ess ls example-bucket
# Named endpoints can refer to an existing AWS profile without copying secrets.
ess alias set archive https://s3.us-east-1.amazonaws.com --provider aws-profile --profile archive
ess ls archive/example-bucket
ess cp archive/example-bucket/file.txt ./downloaded.txt
# AWS namespaces use AWS shared configuration independently of ESS config.
ess s3 ls s3://example-bucket --profile archive
ess s3api head-object --bucket example-bucket --key file.txt --profile archive
ess s3api list-objects-v2 --bucket example-bucket --query 'Contents[].Key' --output json
Use command-specific --help for accepted flags. Native commands include alias import/export, transfer inspection/resume/abort, recursive transfers, synchronization/diff/mirror, versioning, object metadata and policy controls. ess completion bash, ess completion zsh, and ess completion fish generate shell completions. ess sso login --profile archive and ess sso logout --profile archive operate on the selected IAM Identity Center session; interactive login reports its authorization URL and attempts the Linux desktop browser launcher, with URL fallback when unavailable.
AWS namespaces preserve their S3 URI grammar and pinned model options. They do not interpret native aliases as AWS targets. Native commands take local paths, s3://bucket/key, and configured alias/bucket/key targets. Quote paths and keys containing spaces or shell metacharacters.
Native cp, mv, and get accept --version-id for one remote source object.
The provider must confirm that version before the transfer; ignored version
selection fails without replacing a local destination. Recursive/version
combinations are rejected. mv deletes only the confirmed selected version.
Native cp --rewind TIME copies a single object or a recursive prefix as it
existed strictly before TIME. A selected delete marker hides older data. The
complete version inventory must succeed before transfers begin, and historical
identity is checked before publication. Choose either rewind or an explicit
version ID; rewind requires a remote source. Absolute dates use UTC (including
date-only input), unlike mc's host-local date interpretation.
cat/head accept --rewind and --vid; cat also accepts --offset,
--tail, and --part-number, and head --n limits lines. ls, stat, and
tree expose bounded historical snapshots. tree --files --depth N projects
files and directories. du --depth N enables descendant summaries and
du --rewind TIME totals every older data version, excluding delete markers.
Structured inspection marks incomplete result projections with Partial.
ls --versions applies literal prefix and delimiter selection and uses
--max-keys on every page. Its default folder delimiter is /; use
--recursive for a flat version listing. Historical --rewind views stay flat
and reject an explicit delimiter before requesting metadata.
pipe TARGET --dryrun reports the upload without reading stdin or creating a
spool. Its accepted options control the destination upload, progress and expected
size; copy-source, filter and listing options fail before I/O.
anonymous get-json retains the full bucket policy. anonymous set-json FILE TARGET
requires --replace when a policy exists; inspect its --dry-run first. list
reports recognizable policy grants, and links requires an unambiguous policy
and complete listing. These are policy inspections, without a claim that IAM,
ACLs, or public-access restrictions permit anonymous access.
Native lifecycle rules support portable mc date/day aliases; replication conveniences require an explicit role ARN and destination bucket ARN. MinIO administration extensions retain separate provider boundaries. The compatibility decision reports record the exact supported spellings and behavior differences.
ilm restore TARGET restores selected objects with a default one-day Expedited
request. It accepts recursive/version selection and polls completion with a
bounded attempt count; cancellation and partial failures return nonzero. It
requires a provider that supports S3 restore.
Native mb supports --ignore-existing, --with-lock and --with-versioning.
Lock is requested during creation; versioning is a separate operation. A later
versioning error preserves completed creation and does not delete the bucket.
Deprecated ilm add|edit|ls|rm|export|import and encrypt clear|info reuse the
corresponding tested rule/encryption handlers.
legalhold set|clear|info TARGET and
retention set governance 30d TARGET support bounded version-aware selection.
Retention also accepts compliance mode and calendar years such as 1y;
--default edits an already-enabled bucket lock configuration. Bypass must be
explicit. Full-document set forms remain available and reject convenience-only
selectors. Enumerated mutations require confirmed immutable object versions.
Native shares accept --expire 1h30m or legacy --expires seconds. Download
shares support selected versions and bounded recursive inventories; recursive
uploads generate POST grants for a nonempty key prefix. Private history is
limited to 1000 active entries and 1 MiB. share list download|upload is offline
and redacted by default; --reveal prints the signed capability. History uses
the selected config directory with private permissions. Expired entries are
hidden and pruned on the next successful write; local deletion is not revocation.
Shell completion
Completion is generated from the same offline registry as parsing/help. It follows
native command groups, s3, modeled s3api operations and waiters, and the
options applicable to the selected command. Enumerated registry values complete
with separate or --option=value syntax. Option values are not interpreted as
commands, and -- ends option completion.
# Bash, for the current shell:
source <(ess completion bash)
# Zsh, after initializing its completion system:
autoload -Uz compinit
compinit
source <(ess completion zsh)
# Fish, persistently:
mkdir -p ~/.config/fish/completions
ess completion fish > ~/.config/fish/completions/ess.fish
Generate again after upgrading. Generation and completion do not load credentials, run credential_process, read aliases/profiles, or make requests. Remote bucket/key, profile-name, and filesystem-value discovery are not offered. Scripts treat token text literally and do not evaluate it as shell commands.
Configuration and credentials
Native configuration remains at ~/.config/ess/config.toml; ESS_CONFIG_DIR overrides it, otherwise XDG_CONFIG_HOME/ess is used when set. Existing [default] and [profiles.<name>] tables remain readable. Updates preserve unrelated TOML and use private atomic writes. Named endpoint records may refer to ESS profiles, AWS profiles, environment credentials, anonymous access, or explicit static credentials. Prefer profile/environment references to embedding secrets.
Native --config-dir / -C selects a configuration directory for one invocation.
--disable-pager / --dp disables paging. --insecure disables TLS verification
with a stderr warning. Repeated --custom-header / -H values use Name: value
syntax and are validated before signing; authentication and framing fields are
reserved. --limit-upload and --limit-download accept rates such as 10MiB
per second, with zero meaning unlimited. Concurrent requests share each endpoint's
budget; source and destination have independent limits. --conn-read-deadline
and --conn-write-deadline independently bound socket inactivity, defaulting to
10m. Zero disables that direction. Positive Go durations must resolve exactly
to whole milliseconds, at most 4294967295ms; other values fail explicitly.
The overall request has no implicit duration cap. The HTTP/1 adapter uses
request-scoped network-idle and consumer-acknowledgement policies, so bounded
slow delivery can exceed the global 60-second streaming-operation default.
Socket inactivity and cancellation remain active. The required HTTP 0.21.13
also confirms successful fixed-length upload source finalization before
returning success. Forced cancellation can interrupt a finalizer.
Repeated --resolve HOST[:PORT]=literal-IP entries pin socket addresses while
preserving the signed Host, TLS SNI and certificate identity. A port-specific
entry wins over a host-only entry, and failed pins do not fall back to DNS.
AWS namespaces read AWS_CONFIG_FILE/AWS_SHARED_CREDENTIALS_FILE, defaulting to ~/.aws/config and ~/.aws/credentials. Explicit command options take precedence over applicable environment and selected-profile settings. --profile, AWS_PROFILE, and AWS_DEFAULT_PROFILE choose the profile. Explicit profile selection changes credential precedence; providers keep access key, secret, and token as one record. Supported provider paths include environment/shared credentials, role/web identity, credential_process, IAM Identity Center, ECS, and IMDS. --no-sign-request skips credential loading. See the repository credential compatibility report for exact tested modes and remaining live-service gaps.
AWS --cli-read-timeout sets socket read inactivity in seconds, defaulting to 60;
--cli-connect-timeout independently sets connection establishment time. Zero
disables the corresponding timeout. Neither imposes a total transfer duration.
For stdin uploads, --expected-size is a multipart sizing hint; actual captured
bytes determine Content-Length and provider object limits. Native pipe retains
its exact expected-size check.
| Variable | Effect/default |
|---|---|
ESS_CONFIG_DIR, XDG_CONFIG_HOME |
Native configuration directory overrides |
ESS_STATE_DIR |
Native durable transfer state root; takes precedence over XDG |
XDG_STATE_HOME |
State root is <value>/ess; otherwise ~/.local/state/ess |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN |
Coherent temporary/static environment credentials |
AWS_PROFILE, AWS_DEFAULT_PROFILE |
Selected AWS profile; default default |
AWS_REGION, AWS_DEFAULT_REGION |
AWS region settings |
AWS_CONFIG_FILE, AWS_SHARED_CREDENTIALS_FILE |
Shared configuration/credentials paths |
AWS_ENDPOINT_URL_S3, AWS_ENDPOINT_URL |
Applicable explicit service/global endpoint settings |
AWS_ENDPOINT_URL_S3_CONTROL, AWS_ENDPOINT_URL_STS |
Independent control endpoints for move validation; STS also serves role/web-identity credentials; data --endpoint-url does not override them |
AWS_STS_REGIONAL_ENDPOINTS |
ESS extension: explicit regional (default) or legacy STS mode, constrained by pinned partition rules |
AWS_IGNORE_CONFIGURED_ENDPOINT_URLS |
Ignore configured service/global endpoints when true |
AWS_CLI_S3_MV_VALIDATE_SAME_S3_PATHS |
Enable underlying access-point/MRAP path checks for AWS moves with the exact case-insensitive value true |
AWS_S3_USE_ARN_REGION |
Allow the applicable Outposts ARN region policy |
AWS_CA_BUNDLE |
Trusted CA bundle; TLS peer verification is enabled by default |
AWS_DEFAULT_OUTPUT |
Structured output format when no command option overrides it |
AWS_RETRY_MODE |
standard (default) or adaptive; pinned legacy is rejected |
AWS_MAX_ATTEMPTS |
Total attempts including the initial request; default 3 |
AWS_USE_FIPS_ENDPOINT, AWS_USE_DUALSTACK_ENDPOINT |
Boolean endpoint-resolution settings |
AWS_REQUEST_CHECKSUM_CALCULATION |
when_supported or when_required |
AWS_RESPONSE_CHECKSUM_VALIDATION |
when_supported or when_required |
AWS_EC2_METADATA_DISABLED |
Disables instance metadata credentials when true |
AWS_EC2_METADATA_V1_DISABLED |
Forbids permitted IMDSv1 fallback when true |
AWS_CLI_AUTO_PROMPT |
Explicit on, on-partial, or off (default); requires a terminal |
AWS_PAGER |
TTY pager command; empty disables; precedes profile cli_pager, PAGER, then less |
PAGER, LESS |
Pager fallback; LESS=FRX supplied only when absent |
CC |
Build-time C compiler executable; defaults to cc |
ESS_RESOURCE_LARGE_BYTES |
Test-only transfer acceptance object size in bytes; default 67108864, multi-GiB acceptance 2147483648 |
Selected-profile cli_binary_format is resolved before parsing blob inputs; --cli-binary-format overrides it, default base64. Use fileb://path for raw bytes. No AWS_CLI_BINARY_FORMAT environment variable is introduced. JSON/YAML/file/shorthand inputs, skeleton generation, JMESPath queries, and structured output use pinned packaged models and parsers. Auto-prompt asks required questions and confirmation on stderr; its bounded question UI differs from AWS's full-screen editor. Sensitive input disables echo before showing its field label.
Output and safe operations
Stdout contains requested data; diagnostics, prompts, and progress belong on stderr. Raw cat, pipe, and stdout downloads preserve binary bytes and bypass structured paging. --no-cli-pager disables paging; auto color is disabled for redirected output. Interactive pager output uses a private 64 MiB bounded spool and a five-minute pager deadline. A missing, failed, or timed-out pager returns an error and cleans its owned processes/files.
Inspect synchronization with ess sync SOURCE DEST --dryrun before enabling deletion. Exclusions protect destination entries, and incomplete enumeration or failed transfers prevent the deletion phase. Native alias roots are not implicit delete-all permission. Retain local source and durable transfer records until multipart completion is confirmed; inspect ess transfer --help for supported recovery operations. A failed abort can leave an upstream upload that needs explicit cleanup. Never reuse a journal against a changed source or changed provider identity.
For alias backup use ess alias export > aliases.json; secrets are redacted by default. Restore with ess alias import aliases.json --dry-run before applying. Secret-bearing export/import and replacement require explicit flags. A redacted static-credential record cannot restore credentials; profile references can. Preserve native config and state directories before upgrades; this client does not automatically import mc config or alter AWS config.
The source repository includes docs/cli/compatibility/ with generated command inventories, provider limitations, evidence, and deliberate differences, plus docs/cli/design.md and docs/cli/implement-plan.md. These reports must agree with any release claim. Server metadata migration, cluster control, repair, and node drain use server Mix tasks/release RPC, outside this client.
License
MIT — see LICENSE. Vendored reference/model/parser notices are included under priv/compatibility/NOTICE.txt and the relevant source directories.