Skip to content

Folder Structure

rhoopr edited this page Jun 1, 2026 · 12 revisions

Folder Structure

kei uses one directory template per pass: album, smart folder, and unfiled.

Config

[download]
directory = "/photos"
folder_structure = "%Y/%m/%d"
folder_structure_albums = "{album}"
folder_structure_smart_folders = "{smart-folder}"
Pass Key Default Token
Album folder_structure_albums {album} {album}
Smart folder folder_structure_smart_folders {smart-folder} {smart-folder}
Unfiled folder_structure %Y/%m/%d none

All three templates accept {library} as the first segment. Standard strftime specifiers such as %Y, %m, and %d are supported. The Python {:%Y/%m/%d} shape is also accepted.

Defaults

With the default templates:

Asset type Path
Photo in user album Vacation 2024 /photos/Vacation 2024/IMG_1234.HEIC
Photo in smart folder Favorites /photos/Favorites/IMG_1234.HEIC
Photo in no user album /photos/2024/03/15/IMG_1234.HEIC

Smart-folder passes are off by default. Enable them in [filters].smart_folders.

Pass behavior

[filters]
albums = ["all"]
smart_folders = ["none"]
unfiled = true

A photo in N albums writes N on-disk copies when the album template produces distinct paths per {album}. The unfiled pass excludes assets that are in any user album, so albumed assets don't also appear in the unfiled tree.

Explicit album and smart-folder selectors are collection-scoped. A named album or smart folder can download members from shared libraries even when [filters].libraries is still ["primary"]. Unfiled output stays scoped to [filters].libraries.

Changing a path-affecting setting forces a full reconciliation. kei clears stored zone tokens and replans known assets into the new path shape, rather than trusting an incremental token that cannot rediscover files already seen under an old template.

Examples

Date hierarchy under each album:

[download]
folder_structure_albums = "{album}/%Y/%m/%d"

Only specific albums, no unfiled pass:

[filters]
albums = ["Vacation", "Family"]
unfiled = false

Smart folders with dates:

[filters]
smart_folders = ["all"]

[download]
folder_structure_smart_folders = "{smart-folder}/%Y/%m/%d"

Multi-library

When more than one library is in scope, prefix active templates with {library} to keep paths separate:

[filters]
libraries = ["all"]

[download]
folder_structure = "{library}/%Y/%m/%d"
folder_structure_albums = "{library}/{album}"

{library} renders as PrimarySync for the personal library or a truncated shared-library zone name such as SharedSync-A1B2C3D4.

Token placement rules

  • {library} must be the first path segment when present.
  • {album} in folder_structure_albums must come before any strftime specifier and after {library} if present.
  • {smart-folder} follows the same rule in folder_structure_smart_folders.
  • Each token may appear at most once per template.

Examples:

Template Valid?
{album} yes
{album}/%Y/%m/%d yes
{library}/{album}/%Y yes
Photos/{album}/%Y no
%Y/{album}/%m no
{album}/%Y/{album} no

Name sanitization

Names used as directory components are sanitized to prevent path traversal and invalid directories:

  • .. becomes _
  • Leading/trailing dots and spaces are stripped
  • Windows reserved names are prefixed with _
  • Invalid filesystem characters are removed

Related

Commands

Getting Started

Features

Clone this wiki locally