Skip to content

v0.20 Migration

rhoopr edited this page May 21, 2026 · 2 revisions

v0.20 Migration

v0.20 is kei's breaking config cleanup release.

The rule is:

  • TOML is for settings you want to keep.
  • CLI flags are for one run or one action.
  • Env vars are for secrets, config path/bootstrap, process-manager glue, and tests.

Use kei config show to print the resolved v0.20 TOML. Use kei config setup if you want the wizard to write a new file.

Quick migration

  1. Create or update ~/.config/kei/config.toml.
  2. Move durable sync settings out of CLI flags and KEI_* env vars.
  3. Keep secrets and process-manager glue in env when that fits your deploy.
  4. Run kei sync --config ~/.config/kei/config.toml.

Minimal config:

[auth]
username = "you@example.com"

[download]
directory = "/photos"

Account and storage

Old New
--username, durable ICLOUD_USERNAME [auth].username; ICLOUD_USERNAME still works for automation
--domain [auth].domain
--data-dir, durable KEI_DATA_DIR top-level data_dir; Docker still uses KEI_DATA_DIR=/config as runtime glue
--download-dir, KEI_DOWNLOAD_DIR [download].directory
--folder-structure [download].folder_structure
--folder-structure-albums [download].folder_structure_albums
--folder-structure-smart-folders [download].folder_structure_smart_folders

Selection and filters

Old New
--album [filters].albums = ["Name"]
--smart-folder [filters].smart_folders = ["Favorites"]
sync --library [filters].libraries = ["primary"]
--unfiled false [filters].unfiled = false
--filename-exclude "*.AAE" [filters].filename_exclude = ["*.AAE"]
--skip-videos, --skip-photos [filters].media
--exclude-album Name, KEI_EXCLUDE_ALBUM [filters].albums = ["!Name"]
[filters].album [filters].albums
[filters].exclude_albums [filters].albums = ["!Name"]
[filters].library [filters].libraries

These stay as one-run overrides and also remain valid TOML keys for permanent mirrors:

  • --recent
  • --skip-created-before
  • --skip-created-after
[filters]
recent = 100
skip_created_before = "2024-01-01"
skip_created_after = "30d"

Escape selector sentinels with = when a real album, smart folder, or library name looks like a control word:

[filters]
albums = ["=all", "=none", "=!Drafts", "!Archive"]

Photos, Live Photos, RAW, and filenames

Old New
--size original [photos].resolution = "original"
--live-photo-size original [photos].live_resolution = "original"
--live-photo-mode skip [photos].live_photo_mode = "skip"
--align-raw original [photos].raw_policy = "prefer-raw"
--align-raw alternative [photos].raw_policy = "prefer-jpeg"
--force-size [photos].force_resolution = true
--keep-unicode-in-filenames [photos].keep_unicode_in_filenames = true
--live-photo-mov-filename-policy original [photos].live_photo_mov_filename_policy = "original"
--file-match-policy name-id7 [photos].file_match_policy = "name-id7"

Old multi-size workflow:

kei sync --size adjusted --size original --size alternative

New TOML:

[photos]
resolution = "original"
edited = true
alternative = true
raw_policy = "as-is"

edited = true adds adjusted/edited extras. alternative = true adds the alternative or RAW sibling when Apple provides one. Missing extras are skipped.

Retry, watch, reports, and server

Old New
--threads, KEI_THREADS [download].threads
--bandwidth-limit, KEI_BANDWIDTH_LIMIT [download].bandwidth_limit
--temp-suffix, KEI_TEMP_SUFFIX [download].temp_suffix
[download.retry].max_retries [download.retry].per_transfer
[download.retry].max_download_attempts [download.retry].per_asset
--watch-with-interval, KEI_WATCH_WITH_INTERVAL [watch].interval
--notify-systemd [watch].notify_systemd
--pid-file [watch].pid_file
--reconcile-every-n-cycles [watch].reconcile_every_n_cycles
--notification-script [notifications].script
--report-json [report].json
--http-bind [server].bind
--http-port [server].port
[metrics].port, KEI_METRICS_PORT [server].port

kei service run supplies a 24-hour watch fallback when [watch].interval is unset. Plain kei sync stays one-shot unless [watch].interval is set.

Metadata and UI

Old New
--set-exif-datetime [metadata].set_exif_datetime = true
--set-exif-rating [metadata].set_exif_rating = true
--set-exif-gps [metadata].set_exif_gps = true
--set-exif-description [metadata].set_exif_description = true
--embed-xmp [metadata].embed_xmp = true
--xmp-sidecar [metadata].xmp_sidecar = true
[download].no_progress_bar = true [ui].progress_bar = false

--no-progress-bar is still a one-run override.

Docker migration

The Docker image reads /config/config.toml by default and runs:

kei service run --config /config/config.toml

Put durable settings in ./config/config.toml:

[auth]
username = "you@example.com"

[download]
directory = "/photos"

[watch]
interval = 86400

Keep secrets out of Compose when you can. Use kei password set, --password-file /run/secrets/icloud_password, or --password-command.

KEI_DATA_DIR=/config is still set by the image. That's container runtime glue so sessions, the state DB, and credentials stay on the mounted config volume.

The image also sets MALLOC_ARENA_MAX=2. This keeps long-running watch containers from reserving large glibc malloc arenas. If you manage kei with your own Linux systemd unit, add the same environment line:

Environment=MALLOC_ARENA_MAX=2

Kept runtime flags

These remain public because they are action or one-run controls:

  • --config
  • --log-level, --verbose
  • --friendly, --no-friendly
  • --password, --password-file, --password-command, --save-password
  • --dry-run
  • --only-print-filenames
  • --retry-failed
  • --no-progress-bar
  • --recent
  • --skip-created-before
  • --skip-created-after
  • subcommand action flags such as reset --yes, uninstall --purge, verify --checksums, import-existing --strict, and service install flags

Commands

Getting Started

Features

Clone this wiki locally