bcmr v0.6.3
docs / guide / Configuration

Configuration

BCMR reads configuration from ~/.config/bcmr/config.toml (or config.yaml). All settings are optional — defaults are used when a key is absent.

Full Example

[progress]
style = "fancy"          # "fancy" (default) or "plain" (same as --tui flag)

[progress.theme]
bar_gradient = ["#CABBE9", "#7E6EAC"]   # Hex color stops for the progress bar
bar_complete_char = "█"
bar_incomplete_char = "░"
text_color = "reset"                     # "reset", named color, or "#RRGGBB"
border_color = "#9E8BCA"
title_color = "#9E8BCA"

[progress.layout]
box_style = "rounded"    # "rounded" (default), "double", "heavy", "single"

[copy]
reflink = "auto"         # "auto" (default), "force", or "disable"
sparse = "auto"          # "auto" (default), "force", or "disable"

update_check = "off"     # "off" (default, no network), "quiet", or "notify"

[scp]
parallel_transfers = 4   # concurrent SSH transfers (default: 4)
compression = "auto"     # "auto" (default), "force", or "off"

[transfer]
fallback_warning = true  # warn on stderr when serve fast path fails
                         # and we fall back to legacy SSH (default: true)

Progress Settings

progress.style

ValueDescription
"fancy"TUI box with gradient bar, ETA, speed, per-file bar (default)
"plain"3-line text output, no box drawing

progress.theme

  • bar_gradient — Array of hex colors. The progress bar interpolates between them. Default: ["#CABBE9", "#7E6EAC"] (Morandi purple).
  • bar_complete_char / bar_incomplete_char — Characters for filled and empty portions.
  • text_color — Named color ("red", "green", etc.), hex ("#RRGGBB"), or "reset" for terminal default.
  • border_color / title_color — Same format as text_color.

progress.layout.box_style

ValuePreview
"rounded"╭──╮ ╰──╯
"single"┌──┐ └──┘
"double"╔══╗ ╚══╝
"heavy"┏━━┓ ┗━━┛

Copy Settings

Controls copy-on-write (reflink) behavior. Can be overridden per-command with --reflink.

ValueDescription
"auto"Try reflink, fall back to regular copy (default)
"force"Require reflink; fail if unsupported
"disable"Never attempt reflink

Note: The config file also accepts "never" as an alias for "disable".

copy.sparse

Controls sparse file detection. Can be overridden per-command with --sparse.

ValueDescription
"auto"Detect zero blocks ≥ 4KB and create holes (default)
"force"Always write sparse output, even for non-sparse sources
"disable"Write all data, no hole detection

Note: The config file also accepts "never" as an alias for "disable".

SCP Settings

scp.parallel_transfers

Number of concurrent SSH file transfers for remote copy. Can be overridden per-command with -P.

ValueDescription
4Default — 4 parallel SSH streams
1Sequential transfer (no parallelism)
NAny positive integer

scp.compression

Controls SSH transport compression for remote transfers.

ValueDescription
"auto"Smart: enable if >30% of bytes are compressible by extension (default)
"force"Always enable SSH compression (-o Compression=yes)
"off"Never compress

In auto mode, known compressed extensions (.gz, .zip, .mp4, .jpg, etc.) are treated as incompressible. Compression is enabled only when a significant portion of the data would benefit.

Update Check

Controls whether BCMR checks for new versions in the background when running any command.

ValueDescription
"notify"Check and print update notification to stderr (default)
"quiet"No notification
"off"Skip update check entirely

Config File Locations

BCMR checks these paths in order:

  1. ~/.config/bcmr/config.toml
  2. ~/.config/bcmr/config.yaml
  3. Platform-specific config directory (via directories crate):
    • macOS: ~/Library/Application Support/com.bcmr.bcmr/
    • Windows: %APPDATA%\bcmr\bcmr\

Path Bookmarks

Long, repeated remote destinations get tedious. The [paths] table maps short @aliases to full host:path strings; bcmr substitutes them at startup so every downstream code path sees the resolved destination.

[paths]
proj   = "lab:/data/projects/myrepo/"
backup = "nas:/backups/"
logs   = "archive:/var/log/myapp/"
bcmr copy ./project/  @proj           # → lab:/data/projects/myrepo/
bcmr copy db.gz       @proj/backups/  # → lab:/data/projects/myrepo/backups/
bcmr copy report.pdf  @backup/today/  # → nas:/backups/today/

Rules:

  • Alias names must match [A-Za-z_][A-Za-z0-9_-]*. Invalid names error at use.
  • The trailing slash on the configured target is preserved for the bare-alias form (@proj returns the target verbatim) and normalised for the suffixed form (@proj/foo joins with exactly one / between).
  • An unknown @alias errors with a did you mean ...? suggestion (Levenshtein-based) and lists all known aliases. Bcmr does not silently fall through to a literal-file lookup.
  • To copy a literal file whose name starts with @, prefix with ./ — e.g. bcmr copy ./@weird-filename ./dst/.

Aliases work in every position that accepts a path: source list, destination, bcmr check, bcmr remove.

Per-Host Default Flags

Apply a fixed set of flags whenever a transfer involves a particular host:

[host."lab"]
default_args = ["-p", "--compress", "zstd", "--reflink", "force"]

[host."slow_link"]
default_args = ["--bwlimit", "200K"]
bcmr copy ./project/ lab:dst/
# resolves to: bcmr copy -p --compress zstd --reflink force ./project/ lab:dst/

The host name matched is whatever appears in the host: portion of any source or destination argument (first one found wins). Explicit CLI flags appear after the injected defaults, so a user-typed --compress none overrides a host's default_args = ["--compress", "zstd"].

Profiles

Named bundles activated by --profile <name> or BCMR_PROFILE=<name>:

[profile.work]
default_args = ["-p", "-V"]

[profile.home]
default_args = ["-p"]
bcmr --profile work copy ./report.pdf host:dst/
# resolves to: bcmr copy -p -V ./report.pdf host:dst/

BCMR_PROFILE=home bcmr copy ./report.pdf host:dst/
# resolves to: bcmr copy -p ./report.pdf host:dst/

Precedence (left wins): explicit user flags > host defaults > profile defaults > built-in defaults. The injection ordering is profile, host, user, all left-to-right; clap parses earlier-then-later, so user flags win.

Unknown --profile <name> (no matching [profile.<name>] table) is a silent no-op — the rest of the command runs unchanged.

Environment Variables

VariableDefaultDescription
BCMR_CAS_DIR$XDG_DATA_HOME/bcmr/casOverride the content-addressed store location used by the remote dedup path. Also honoured by the integration tests — they point it at a tempdir for isolation.
BCMR_CAS_CAP_MB1024 (1 GiB)Soft byte cap on the CAS, enforced by LRU eviction before each dedup-enabled PUT. Set to 0 to disable the cap and let the store grow unbounded. Values are whole megabytes.

CAS paths by platform (when BCMR_CAS_DIR is unset):

  • Linux: ~/.local/share/bcmr/cas/
  • macOS: ~/Library/Application Support/bcmr/cas/
  • Windows: %APPDATA%\bcmr\cas\

Block files live under a two-level hex prefix (<aa>/<bb>/<rest>.blk) so no single directory accumulates more than ~65k entries on typical workloads. Clearing the store is safe: rm -rf the cas directory and the next dedup-enabled PUT rebuilds it from the wire.