Skip to main content

Filez4Eva

⚠️ DISCLAIMER: This is a hobby/personal project. Not a commercial product. Not for production use.

Shift scans, photos, and other files into structured folders for permanent safekeeping

Filez4Eva is a command-line tool that helps you organize files by naming them correctly and placing them in the right directory structure. It's especially useful for managing account documents, scanned files, and other personal records.

Installation

It's best to install using pipx:

pipx install filez4eva

If you don't have pipx installed, visit the pipx site for installation instructions.

Usage

Stowing Individual Files

To organize a single file (like a downloaded PDF):

filez4eva stow-file ~/Desktop/123456789SomeFileIDownloaded.pdf

Filez4Eva will interactively prompt for:

  • Cabinet, only if several are configured (with tab-completion of cabinet names; see Cabinets)
  • Date in YYYYMMDD format
  • Account name (with tab-completion from existing accounts)
  • Part name (with tab-completion from existing files for that account)

Values can also be piped in as a YAML mapping on stdin, which is handy for other tools that produce a record for the file:

printf 'date: 20240213\naccount: acct\npart: statement\n' \
  | filez4eva stow-file ~/Desktop/statement.pdf
  • Recognised keys are cabinet, date, account and part; any other keys are ignored.
  • Command-line flags override values from stdin.
  • Anything still missing is prompted for as usual.
  • date may be 20240213, '20240213' or 2024-02-13. If it isn't a valid date, stow-file exits with an error.
  • If stdin is empty, isn't valid YAML, or isn't a mapping, it is ignored.
  • Values are read as plain text, so 0123 stays 0123 and yes stays yes.
  • ~ and null are treated as missing, so that value is prompted for.
  • Stdin is only read by stow-file itself. scan-dir ignores it.

However the values are supplied (flags, stdin or prompts), account must be a single directory name (not empty, . or .., and without / or \), and part may contain only letters, digits and hyphens. An invalid value from a flag or stdin makes stow-file exit with an error. An invalid value typed at a prompt is rejected and the prompt asks again.

Processing Multiple Files

To process all files in a directory:

filez4eva scan-dir ~/Desktop

This interactive process lets you:

  • Skip a file (x)
  • Preview a file (p)
  • Stow a file (s)
  • Delete a file (d)
  • Quit processing (q)

Stowing a file works like process: the file is transcribed (reusing an up-to-date transcript) and classified, then the summary and doctype are shown and the Date:, Account: and Part: prompts are pre-filled with the proposed values (the Date: prompt starts empty if the document has no date of its own). Press Enter to accept a value, or type a new one. With several cabinets, the cabinet is asked for once, before anything is sent to the model.

  • If transcription or classification fails (for example, no API key or an unsupported file type), the error is shown and the prompts start empty, as they would without AI.
  • Empty input at any prompt returns to the action choice for the same file, without moving anything.

Transcripts written by transcribe are not offered as files of their own: X.md is skipped when X is in the same directory (for example scan.pdf.md next to scan.pdf). A .md file with no such companion is offered as usual. Deleting a file also deletes its transcript. Stowing a file moves its transcript with it (see stow-file).

Transcribing Files

To transcribe a file to Markdown using an AI model:

filez4eva transcribe ~/Desktop/scan.pdf

This writes scan.pdf.md next to the file (the full file name plus .md) and prints its path on stdout. The transcript looks like:

---
source: scan.pdf
sha256: 3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b
model: claude-opus-4-6
transcribed: '2026-10-10T17:42:05+00:00'
---
<!-- Generated by an AI process from a binary file. ... -->

...Markdown transcription...
  • Supported file types are PDF, PNG, JPEG, GIF, WebP, plain text, Markdown and CSV.
  • If the transcript already exists and its sha256 matches the file, nothing is sent to the model and the existing path is printed (status Unchanged on stderr). If the file has changed, or the transcript has no readable front matter, it is transcribed again and overwritten.
  • --force (or -f) transcribes again even if the transcript is up to date.
  • If transcription fails (e.g. an unsupported file type or an API error), transcribe exits with an error and any existing transcript is left as it was.

See Transcription settings for the model and API key.

Classifying Files

To have an AI model propose where a file should be filed:

filez4eva classify ~/Desktop/scan.pdf

classify transcribes the file first if needed (exactly as transcribe does, reusing an up-to-date transcript), then asks the model to classify the transcript and prints a YAML record on stdout:

file: /Users/me/Desktop/scan.pdf
transcript: /Users/me/Desktop/scan.pdf.md
cabinet: accounts
date: '20261002'
account: amazon
part: receipt
doctype: receipt
summary: Amazon.ca order receipt for a USB hub
  • date is the document's own date, as YYYYMMDD. If the document has no date of its own (or the model can't tell what it is), date is null rather than a guess. Today's date and the file's modified time are never used.
  • doctype is one of the configured doctypes, or other.
  • summary is a single line.
  • The model is told the cabinet's description, the accounts already in the cabinet with the parts already used for each (the same ones offered by tab completion, so only with the default pattern), and asked to reuse them when they fit. It is also given the doctype names and descriptions.
  • The cabinet is chosen as for stow-file: --cabinet NAME, the only cabinet, or a prompt.
  • If transcription or classification fails, or the model's answer isn't a valid account, part or doctype, classify exits with an error and prints nothing on stdout. A date that isn't a valid YYYYMMDD date becomes null instead of an error.

Nothing is moved. To file the document as proposed, pipe the record into stow-file, which reads cabinet, date, account and part and ignores the other keys:

filez4eva classify ~/Desktop/scan.pdf | filez4eva stow-file ~/Desktop/scan.pdf

If the record has date: null, stow-file prompts for the date.

Processing a File with AI

To transcribe, classify, confirm and stow a file in one go:

filez4eva process ~/Desktop/scan.pdf

process:

  1. transcribes the file if needed (as transcribe does, reusing an up-to-date transcript)
  2. classifies it (as classify does)
  3. shows the summary and doctype, then prompts for Cabinet: (only if several cabinets are configured and it wasn't just chosen), Date:, Account: and Part:, each pre-filled with the proposed value. Press Enter to accept it, or type a new value (backspace clears the pre-filled value first). If the classification has no date, the Date: prompt starts empty. Tab completion works as for stow-file.
  4. stows the file and its transcript, exactly as stow-file does, and prints the destination path on stdout
  • Confirmation is always interactive.
  • Empty input at any prompt cancels without moving anything. An invalid value is rejected and the prompt asks again.
  • The cabinet is chosen as for classify (--cabinet NAME, the only cabinet, or a prompt) before anything is sent to the model, and the whole configuration is checked first.
  • --dry-run transcribes, classifies and prompts as usual, then prints where the file (and its transcript) would go, without moving anything.

Command Line Options

Global options:

  • --config PATH: Specify path to config file
  • --debug: Enable debug output

stow-file command:

  • --cabinet, -c NAME: Specify the cabinet (destination) to stow into
  • --date, -d DATE: Specify date in YYYYMMDD format
  • --account, -a ACCOUNT: Specify account name
  • --part, -p PART: Specify part name
  • file: Path to the file to stow

After a successful move, stow-file prints the absolute destination path on stdout (the Done status goes to stderr), so scripts can capture it, e.g. dest=$(filez4eva stow-file -d 20240213 -a acct -p part file.pdf).

If the file has a transcript (FILE.md, written by transcribe), stow-file moves it too, named after the stowed file. By default it goes adjacent to the stowed file: .../20261002-receipt.pdf gets .../20261002-receipt.pdf.md. It can instead go into a parallel tree; see Transcript location. If a transcript already exists at its destination, stow-file fails before moving anything.

scan-dir command:

  • dir: Optional path to directory to scan (defaults to configured source)

transcribe command:

  • --force, -f: Transcribe again even if the transcript is up to date
  • file: Path to the file to transcribe

classify command:

  • --cabinet, -c NAME: Specify the cabinet to classify for
  • file: Path to the file to classify

process command:

  • --cabinet, -c NAME: Specify the cabinet to classify for and stow into
  • --dry-run: Show where the file would go without moving anything
  • file: Path to the file to process

Configuration

Create a filez4eva.yml file with:

filez4eva:
  source: '~/Desktop'          # Default source directory
  target: '~/Dropbox/accounts' # Target directory for stowed files

Files will be organized in this pattern:

~/Dropbox/accounts/<year>/<account>/<date>-<part>.<extension>

Destination pattern

The layout under target can be changed with the optional pattern key:

filez4eva:
  target: '~/Dropbox/accounts'
  pattern: '{account}/{year}/{part}-{date}{ext}'

The default is '{year}/{account}/{date}-{part}{ext}', which gives the layout shown above. Quote the pattern in YAML, since it starts with {.

Placeholders:

  • {year}: four-digit year, e.g. 2024
  • {date}: date as YYYYMMDD, e.g. 20240213
  • {account}: account name
  • {part}: part name
  • {ext}: the source file's extension, including the dot (e.g. .pdf), or nothing if the file has no extension

Use / to create subdirectories; missing directories are created. Any other text is used literally. A pattern is a configuration error, and stow-file exits before moving anything or prompting, if it:

  • uses a placeholder not listed above, or a positional one like {} or {0}
  • uses format specs, conversions, attributes or indexes (e.g. {year:>4}, {account!r}, {year.x}, {account[0]})
  • has unbalanced braces
  • is absolute, starts with ~, or contains ..

Tab completion of accounts and parts reads existing files in the default layout, so it only works with the default pattern. With any other pattern the prompts still accept typed values but offer no completion.

Cabinets

To file into more than one destination, configure named cabinets:

filez4eva:
  cabinets:
    accounts:
      target: ~/Dropbox/accounts
      pattern: '{year}/{account}/{date}-{part}{ext}'
      description: Personal account records
    memories:
      target: ~/Dropbox/memories
      pattern: '{account}/{year}/{part}-{date}{ext}'

Each cabinet has:

  • target (required): the directory files are stowed under
  • pattern (optional): the layout under the target, as described above. Defaults to the top-level pattern if set, otherwise '{year}/{account}/{date}-{part}{ext}'
  • description (optional): a note on what the cabinet holds
  • transcripts (optional): where transcripts of files stowed in this cabinet go, with location and root keys. Each key defaults to the top-level transcripts value; see Transcript location

Choose the cabinet with --cabinet NAME (or -c NAME), or with a cabinet key on stdin; the flag wins if both are given. If neither is given and there is more than one cabinet, stow-file prompts for one, with tab-completion of the names. With only one cabinet it is used without asking. An unknown name from the flag or stdin is an error; an unknown name typed at the prompt is rejected and the prompt asks again. scan-dir asks for a cabinet for each file it stows (once per file, before classifying it).

Tab completion of accounts and parts reads the chosen cabinet's target.

If there is no cabinets section (or it is empty), the top-level target and pattern form a single cabinet named default, so existing configurations work unchanged. If cabinets is present, the top-level target is ignored.

The whole configuration is checked before any prompt: a cabinet with no target, or with an invalid pattern or transcripts setting, is an error even if it isn't the one being used.

Transcript location

When stow-file stows a file that has a transcript, the transcript goes next to the stowed file by default (adjacent). To keep transcripts in a parallel tree instead:

filez4eva:
  transcripts:
    location: parallel           # or 'adjacent' (the default)
    root: ~/Dropbox/transcripts

With location: parallel, the transcript goes to <root>/<cabinet>/<path under the cabinet target>.md. For example, stowing into the accounts cabinet at 2026/amazon/20261002-receipt.pdf puts the transcript at ~/Dropbox/transcripts/accounts/2026/amazon/20261002-receipt.pdf.md. Missing directories are created, and the root may be on another filesystem. Without a cabinets section the single cabinet is named default, so transcripts go under <root>/default/.

A cabinet can override either key with its own transcripts block; a key it doesn't set falls back to the top-level value:

filez4eva:
  transcripts:
    location: parallel
    root: ~/Dropbox/transcripts
  cabinets:
    accounts:
      target: ~/Dropbox/accounts         # transcripts in the parallel tree
    memories:
      target: ~/Dropbox/memories
      transcripts:
        location: adjacent               # transcripts next to the files

A location other than adjacent or parallel, parallel without a root, or a transcripts value (top-level or in a cabinet) that isn't a mapping is a configuration error, and stow-file exits before prompting or moving anything. An error in a top-level setting names the top level rather than a cabinet. An empty transcripts: block, or an empty location, counts as unset, but other values such as no or 0 are rejected as invalid locations.

This only affects stow-file. transcribe and scan-dir always write the transcript of an incoming file next to it, as FILE.md.

Transcription settings

transcribe uses these optional keys:

filez4eva:
  transcribe:
    model: claude-opus-4-6              # Anthropic model ID
  anthropic:
    key: $(op read op://vault/anthropic/credential)
  • transcribe: model: defaults to claude-opus-4-6.
  • anthropic: key: is the Anthropic API key. Like other values it may use $(...) to run a command, such as a password manager lookup. It can also be set with the FILEZ4EVA_ANTHROPIC_KEY environment variable, which takes precedence over the config file. If neither is set, the Anthropic SDK's own ANTHROPIC_API_KEY environment variable is used.

Filez4Eva only reads its own configuration; Kwark's configuration is never used.

Classification settings

classify uses these optional keys, as well as the transcribe model and the anthropic key above:

filez4eva:
  classify:
    model: claude-haiku-4-5     # Anthropic model ID (the default)
  doctypes:
    receipt:
      description: Proof of purchase or payment
    bill:
      description: A request for payment, usually with a due date
  • classify: model: defaults to claude-haiku-4-5. Transcription still uses transcribe: model:.
  • doctypes maps each document type to an optional description, which is shown to the model. Names must be single words (letters, digits, - and _). other is always available; configure it only to change its description. With no doctypes, every document's doctype is other.
  • A doctypes value that isn't a mapping, a name that isn't a single word, or a description that isn't text is a configuration error, and classify exits before calling the model.

Metadata

Release files for filez4eva 5.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for filez4eva 5.1.1
File Size Uploaded
filez4eva-5.1.1.tar.gz 25.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for filez4eva 5.1.1
File Interpreter ABI Platform
filez4eva-5.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 50.9 kB

Release files / filez4eva-5.1.1.tar.gz

Download URL filez4eva-5.1.1.tar.gz
Size 25.7 kB
Tags Source
SHA-256 checksum
How to use checksums
3ab5e535405c3c4ef000c53db914154e1be7d8f84de198a1e050ef00d76d7230
BLAKE2b-256 checksum
How to use checksums
6871dd0bc1699004aee5a9abba4a580da09a293859e21e6654064b1792ef7444
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / filez4eva-5.1.1-py3-none-any.whl

Download URL filez4eva-5.1.1-py3-none-any.whl
Size 25.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ba7f52e0235f906430ba43c56e213c1b5fbbead73d074ddd0f204766dbd5d43c
BLAKE2b-256 checksum
How to use checksums
b2d7ed3558c9894b415eef957103af2828d4eb73cfae558e069b771df8a209ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

5.2.0

2 release files

This release

5.1.1 This release

2 release files

5.1.0

2 release files

5.0.0

2 release files

4.0.0

2 release files

3.0.13

2 release files

3.0.12

2 release files

3.0.11

2 release files

3.0.10

2 release files

3.0.9

2 release files

3.0.7

2 release files

3.0.6

2 release files

3.0.5

2 release files

3.0.4

2 release files

3.0.3

2 release files

3.0.2

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.2.8

2 release files

2.2.7

2 release files

2.2.6

2 release files

2.2.5

2 release files

2.2.4

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page