-
-
Notifications
You must be signed in to change notification settings - Fork 5
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.
- Create or update
~/.config/kei/config.toml. - Move durable sync settings out of CLI flags and
KEI_*env vars. - Keep secrets and process-manager glue in env when that fits your deploy.
- Run
kei sync --config ~/.config/kei/config.toml.
Minimal config:
[auth]
username = "you@example.com"
[download]
directory = "/photos"| 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 |
| 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"]| 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 alternativeNew 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.
| 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.
| 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.
The Docker image reads /config/config.toml by default and runs:
kei service run --config /config/config.tomlPut durable settings in ./config/config.toml:
[auth]
username = "you@example.com"
[download]
directory = "/photos"
[watch]
interval = 86400Keep 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=2These 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