Skip to content

Naming Convention

Filenames should be meaningful to both humans and machines. A file named scan001.pdf tells you nothing. A file named 20240315-irs-w2_wage_statement-final.pdf tells you the date, the entity, the content, and the version — without opening it.

fialr applies a template-driven naming convention that produces filenames with consistent, semantic tokens. The convention is deterministic: given the same metadata, fialr produces the same filename. All tokens are optional — the pattern controls which appear, their order, and their format.

{{ date }}-{{ entity | slugify }}-{{ descriptor | slugify }}.{{ ext | lower }}

All tokens are optional. Users define their own patterns in fialr.toml or per-category in schema.yaml. The pattern controls which tokens appear and in what order.

Each token is separated by hyphens (configurable). Within a token, words are separated by underscores (configurable). This distinction is structural — the token separator delimits tokens, the word separator delimits words within tokens.


TokenDefaultFormatRulesExample
dateIncludedConfigurable via date_formatDocument subject date, not file creation date. Falls back to mtime only when no better source exists. Format defaults to %Y%m%d but is user-configurable (e.g., %Y-%m-%d via the format filter).20240315
entityIncludedLowercase, underscore-separated (via slugify filter)Primary subject or organization. One entity per filename. No abbreviations unless the abbreviation is the canonical name (e.g., irs, dmv).acme_corp, irs, dr_chen
descriptorIncludedLowercase, underscore-separated (via slugify filter)Semantic description of the content. Specific enough to distinguish from other files by the same entity on the same date.quarterly_report, w2_wage_statement, invoice_1847
versionOptionalLowercase, no hyphensPresent only when multiple versions of the same document coexist. Common values: v1, v2, draft, final, signed. Omit when there is only one version.v2, final, signed
extIncludedLowercaseMIME-derived canonical extension. Normalized to standard form (.jpeg becomes .jpg, .tiff becomes .tif)..pdf, .jpg, .docx

Lowercase everywhere. No uppercase characters in any token. Acme-Corp becomes acme-corp. INVOICE.PDF becomes invoice.pdf.

Underscores within, hyphens between. Underscores separate words inside a token (wage_statement). Hyphens separate tokens from each other (irs-w2_wage_statement). Spaces are never used.

No special characters. Parentheses, brackets, ampersands, hash symbols, and other special characters are stripped or transliterated. Report (Final).pdf becomes report_final.pdf in the descriptor token.

No hashes in filenames. Content hashes belong in SQLite and XATTRs. Filenames are for human-readable semantic content. A filename like a1b2c3d4_report.pdf defeats the purpose.

Reject generic names. fialr flags files with generic names and routes them to the review queue rather than preserving meaningless tokens. The following patterns are rejected: scan001, untitled, document, new-file, copy-of, img_, dsc_, file.


Token and word separators, case, and date format are all configurable:

SettingDefaultOptionsConfig key
Token separator- (hyphen)Any character[naming] separator
Word separator_ (underscore)Any character[naming] word_separator
Caselowerlower, upper, title, preserve[naming] case
Date format%Y%m%dAny strftime[naming] date_format

Token separator (-) joins top-level tokens: 20240315-amazon-purchase_receipt.pdf

Word separator (_) joins words within tokens: purchase_receipt, quarterly_review


Using the default pattern:

20240315-irs-w2_wage_statement-final.pdf
20240108-acme_corp-consulting_agreement-signed.pdf
20231120-dr_chen-annual_physical_results.pdf
20240601-apartment_lease-renewal_terms-v2.pdf
20240912-nikon_d850-yellowstone_morning_fog.jpg
20230430-fidelity-401k_quarterly_statement.pdf

Each filename is parseable by splitting on hyphens. The first token is always a date. The last segment before the extension is either a descriptor or a version. This predictability is what makes the convention machine-queryable.


Different file types can use different naming patterns. Configure file-type overrides in fialr.toml:

[naming.patterns]
"*.jpg" = "{{ date }}_{{ descriptor | slugify }}.{{ ext | lower }}"
"*.mp3" = "{{ entity | slugify }}_{{ descriptor | slugify }}.{{ ext | lower }}"

When a file matches a glob key, the corresponding pattern is used instead of the default. This allows photos to omit the entity token, audio files to omit the date, etc.


Different directories can use different naming patterns. Configure directory overrides in fialr.toml:

[naming.directories]
"receipts" = "{{ date }}-{{ entity | slugify }}-{{ descriptor | slugify }}.{{ ext }}"
"photos/*" = "{{ date }}-{{ descriptor | slugify }}.{{ ext }}"
"work/reports" = "{{ date }}-{{ descriptor | slugify }}{{ version }}.{{ ext }}"

Directory patterns match against the relative path within the target directory. Glob patterns are supported.

Schema categories can also define naming_pattern in schema.yaml to override per-category:

media:
naming_pattern: "{{ date }}_{{ descriptor | slugify }}.{{ ext | lower }}"

Pattern resolution priority (highest wins):

  1. Schema category naming_pattern
  2. Directory pattern — [naming.directories] glob match
  3. File-type pattern — [naming.patterns] glob match
  4. Config default pattern — [naming] pattern
  5. Hardcoded fallback

Custom variables are available in all naming templates. Define them in fialr.toml:

[naming.variables]
project = "acme"
owner = "jane"

Use them in any pattern:

[naming]
pattern = "{{ project }}_{{ date }}_{{ descriptor | slugify }}.{{ ext | lower }}"

User variables have lower priority than extracted tokens — they will not override date, entity, descriptor, version, or ext if those are extracted from the file.


The default date format is %Y%m%d (compact ISO 8601). Override it in fialr.toml:

[naming]
date_format = "%Y-%m-%d"

Or use the format filter directly in patterns for per-pattern control:

{{ date | format: "%Y/%m" }}_{{ descriptor }}.{{ ext }}

Each token is derived from metadata, with sources tried in priority order:

TokenSource priority
date1. Extracted from document content (PDF metadata, EXIF date taken, ID3 date). 2. Inferred by local LLM from extracted text. 3. File modification time (mtime) as last resort.
entity1. Extracted from document content (letterhead, sender, organization name). 2. Inferred by local LLM. 3. Parent directory name as heuristic fallback.
descriptor1. Inferred by local LLM from extracted text (one-phrase semantic summary). 2. Derived from original filename after cleanup.
version1. Detected from original filename patterns (v2, final, _signed). 2. Inferred from duplicate group membership (when multiple versions of the same document exist).
ext1. MIME type detection (python-magic). 2. Original file extension, normalized to lowercase canonical form.

For Tier 1 files, local LLM inference is available (via Ollama) with results routed to the review queue. Cloud inference requires two-step confirmation. For Tier 2 files, LLM-derived tokens require human confirmation. For Tier 3 files, LLM-derived tokens are applied automatically above the confidence threshold. See sensitivity tiers for details.


fialr rename --dirs normalizes directory names using the configured case and word separator:

Terminal window
# Preview directory renames
fialr rename ~/Documents --dirs
# Apply directory renames
fialr rename ~/Documents --dirs --execute
# Apply prefix map from schema.yaml
fialr rename ~/Documents --dirs --prefix --execute

The --prefix flag applies a prefix_map from schema.yaml, adding sort-order prefixes to top-level directories (e.g., work/01_work/, personal/02_personal/).


The naming pattern, date format, rejected patterns, file-type overrides, and user variables are configured in fialr.toml:

[naming]
# Default pattern — all tokens optional
pattern = "{{ date }}-{{ entity | slugify }}-{{ descriptor | slugify }}.{{ ext | lower }}"
# Separators
separator = "-"
word_separator = "_"
# Case: lower, upper, title, preserve
case = "lower"
# Date output format (strftime)
date_format = "%Y%m%d"
# Generic names routed to enrichment
reject_names = [
"scan001", "untitled", "document", "new-file", "copy-of",
"img_", "dsc_", "screenshot",
]
# Per-directory pattern overrides
[naming.directories]
"receipts" = "{{ date }}-{{ entity | slugify }}-{{ descriptor | slugify }}.{{ ext }}"
"photos/*" = "{{ date }}-{{ descriptor | slugify }}.{{ ext }}"
# File-type pattern overrides
[naming.patterns]
"*.jpg" = "{{ date }}-{{ descriptor | slugify }}.{{ ext | lower }}"
"*.mp3" = "{{ entity | slugify }}-{{ descriptor | slugify }}.{{ ext | lower }}"
# User-defined variables
[naming.variables]
project = "acme"
owner = "jane"

Files matching reject_names in their original filename are flagged for enrichment rather than carrying the generic name forward. The descriptor token for these files must come from content extraction or LLM inference.

See the organize command reference for execution details, and the enrichment guide for how token values are derived from file content.