User Manual
Content List Toolkit
Scan large folder trees, write CSV inventories with optional hash columns, copy email files into curated destinations, and verify drive clones. macOS, Linux, and Windows.
Overview
What this app does
Content List Toolkit is a desktop tool for archival migration workflows. Point it at a folder, and it produces a CSV inventory of every file under that folder — relative path, size, modified date, and an optional hash. Output streams to disk so multi-million-row scans do not run out of memory.
Three additional workflows live alongside the scan: copy every email-related file under a tree into a curated destination, compare two drives' content lists to verify a clone, and check the Getty tags on a CONTENTdm export before it is uploaded.
Getting Started
Download & install
Pick the build that matches your platform. All builds are unsigned at this stage and the OS may prompt before running.
Wails GUI universal
Download content-list-generator-gui-darwin-universal.zip. Unzip, drag the .app to Applications.
Wails GUI .exe
Download content-list-generator.exe. Double-click to run.
Terminal UI
Download content-list-generator-linux-amd64. In your terminal:
chmod +x content-list-generator-linux-amd64
./content-list-generator-linux-amd64
Latest release: github.com/snyderb-de/content-list-toolkit/releases/latest
Getting Started
The window at a glance
The GUI is organized as a vertical sidebar plus a workspace pane that swaps based on which workflow you pick.
- Sidebar. Three workflow tabs — Content List, Email Copy, Clone Compare — plus theme toggle.
- Source folder. Browse button. The folder you point this at is scanned recursively.
- Output folder + filename. Where the CSV (or copy destination) lands. Defaults to the source.
- Settings panel. Hash algorithm, exclusions, XLSX option, folders-only toggle.
- Generate. Starts the work. Progress bar + live stats appear.
- Done summary. Top extensions by count and by size, filtered samples, output paths.
Workflow 1
Generate a content list
Produces a recursive CSV inventory of every file under a folder.
- Pick a source folder. Browse to the drive or folder you want inventoried. Network drives work too, but expect slower throughput.
- Pick an output folder. Defaults to the source. Choose somewhere with enough free space — a CSV of 1M rows is roughly 200 MB.
- Tune settings. See the Settings reference below — hash algorithm, exclusions, XLSX, etc.
- Click Generate. The app first counts everything (so progress + ETA are real), then streams the scan to CSV.
- Review the done summary. Top extensions, totals, sample of filtered rows.
What each toggle does
| Setting | What it does |
|---|---|
| Verification hash | Off / SHA-1 / SHA-256 / BLAKE3. Adds a hash column to every row. See Hash algorithms. |
| Exclude hidden | Skips dotfiles on Unix, hidden-attribute files on Windows. |
| Exclude common system files | Skips .DS_Store, Thumbs.db, desktop.ini, etc. |
| Exclude extensions | Comma-separated list, e.g. tmp,log,bak. Case-insensitive. |
| Create XLSX after scan | Generates an Excel copy alongside the CSV. |
| Preserve leading zeros in XLSX | Keeps zero-padded filenames (001.001) as text, not numbers. |
| Delete CSV after XLSX | Cleans up the intermediate CSV once the XLSX exists. |
| Folders only | Switches to folder-list mode. No file rows. Useful for prepping migration plans. |
| Max depth | Only in folders-only mode. 0 = unlimited, 1 = top-level only, etc. |
Workflow 2
Copy email files
Finds every email file under a source folder and copies them into a destination, preserving the relative folder structure. Writes a manifest CSV of what got copied.
- Pick the email-copy tab in the sidebar.
- Source folder — the tree to search for email files.
- Destination folder — where copies land. Folder structure under the source is mirrored.
- Click Copy. The app walks the tree, copies files with matching extensions, and writes a manifest CSV.
- Review the manifest. The destination contains
email-copy-manifest-{timestamp}.csvwith one row per copied file:Source Path,Destination Path,Relative Path,File Name,Extension,Size in Bytes.
Workflow 3
Clone compare
Compares two drive content-list CSVs to verify a clone. Picks one of several verdicts and writes a diff CSV showing every difference.
- Generate a content list for the original drive (use BLAKE3 or SHA-256 for confidence).
- Generate a content list for the cloned drive — same hash algorithm.
- Open the clone-compare tab, point it at both CSVs.
- Optional: enable soft compare — accepts renamed paths with identical hashes as matches.
- Click Compare. Get a verdict + diff CSV.
Soft compare (PDFs)
Off by default. When enabled and a PDF's hashes differ at the byte level, the comparator re-reads the last 2 KB of each PDF, masks the PDF
/ID trailer (the random pair PDF writers stamp on every save), and accepts the pair as a soft match if the masked tails are identical.
Use this when a tool re-saved every PDF without changing rendered content — the verdict becomes Metadata Clone instead of Not a Clone.
Soft compare only runs on .pdf files. Other file types fall through to strict hash equality.
Workflow 4
Getty tag check
Checks the Tags column of a CONTENTdm export before you upload it. It does two jobs: it removes the invisible characters
that stop a tab-delimited file loading, and it checks every term against the Getty Art & Architecture Thesaurus. It writes a corrected
copy and a report, and never changes the file you point it at.
- Export the Access
Maintable to Excel, as the CONTENTdm process already has you do. - Open Getty Tags and browse to the export.
.xlsx,.csv, and tab-delimited.txtall work — including the.txtyou are about to upload. - Choose where terms are verified. See the table below.
- Click Check Tags. Rows with nothing wrong are not listed; a clean sheet says so.
- Fix what it found. Edit a tag directly, or click a suggested replacement.
- Apply Fixes & Re-check. Repeat until nothing is left, then upload the cleaned copy.
What it writes
Both files land beside the export. The export itself is never modified — it is the record of what Access held.
<name>-tags-cleaned.xlsx | A copy with the Tags column corrected. Every other column is untouched. |
<name>-tags-report.txt | What was found, what was changed, and what still needs a person. |
Use Show in Folder to find them. A sheet with nothing to correct gets no cleaned copy — an identical file would only raise the question of which one to upload.
Where terms are verified
Three choices, and they are not equivalent. Pick the first one your network allows.
| Option | Needs | Use when |
|---|---|---|
| Getty, live | vocab.getty.edu on port 443 | Always, when it is reachable. It is the only current source. |
| Built-in list | Nothing | Offline, or the live check is blocked. 176,629 English terms ship inside the app. |
| A term list on this machine | A file you supply | You keep your own curated list, or you downloaded a newer one. |
| Do not verify terms | Nothing | You only want the invisible characters cleaned. |
landscapes as a valid term; Getty no
longer holds it, having split it into qualified forms. The app says so wherever an answer comes from a dated list. The live check is the authority.
Getting a fresher list
Build list from a Getty archive turns a Getty relational archive (aat_rel_<mmyy>.zip, about 73 MB) that you
already have into an English term list, written beside the archive and selected for you. The publication date is written into the filename.
The app does not download that archive itself: Getty serves it over an unencrypted connection, and this app makes none. Fetch it separately if you need one, then point the app at the file.
If Getty is blocked here, Getty network access lists every request the check makes, with hosts and ports, written for whoever approves the firewall exception.
Reference
Understanding the output
Content list CSV columns
| Column | Contents |
|---|---|
File Name | Filename only, including extension. |
Extension | Lowercased extension with the leading dot (e.g. .pdf). |
Size in Bytes | Raw file size. |
Size in Human Readable | Pretty-printed size (e.g. 1.4 MB). |
Path From Root Folder | Relative path from the source root, including the filename. |
Hash Algorithm | Algorithm name (sha1, sha256, blake3) or empty when hashing is off. |
Hash Value | Hex digest. Empty when hashing is off. |
Date Created | Filesystem creation or birth time in local scan-machine time (YYYY-MM-DD HH:MM:SS ±HH:MM). Shows unknown when the operating system or filesystem does not expose it. |
Date Modified | Filesystem last-modified time in local scan-machine time (YYYY-MM-DD HH:MM:SS ±HH:MM). Shows unknown when unavailable. |
Creation-date note: copying, restoring, downloading, or migrating a file can change its filesystem creation time. It is metadata observed during the scan, not proof of when the document contents were authored.
Folders-only mode writes a single column: Path From Root Folder.
Companion files
Every scan also writes a -report.txt alongside the CSV. It contains totals, filtered samples, top extensions, and the settings used.
my-folder-content-list-2026-05-20T13-45-02.csv
my-folder-content-list-2026-05-20T13-45-02-report.txt
my-folder-content-list-2026-05-20T13-45-02.xlsx (if XLSX enabled)
Default base name is {source-folder}-content-list-{YYYY-MM-DDTHH-MM-SS}.csv. In folders-only mode it becomes …-folder-list-….
Reference
Hash algorithms
Hashing reads every byte of every file. Choose based on speed vs. cryptographic strength.
| Mode | Throughput | Use for |
|---|---|---|
Off | ~ disk read speed | Quick inventories where bytewise identity does not matter. |
SHA-1 | fast | Legacy compatibility, casual fingerprinting. |
SHA-256 | slower, stronger | Default for verifications that must hold up to scrutiny. |
BLAKE3 | fastest secure hash | Best speed/strength trade-off. Built in — nothing to install. |
Reference
CSV chunking for huge scans
CSV files over a few hundred thousand rows get unwieldy in Excel and many text editors. Content List Toolkit splits output every 300,000 rows by default.
| Row count | Output files |
|---|---|
| 1 – 300,000 | {name}.csv |
| 300,001 – 600,000 | {name}-001.csv, {name}-002.csv |
| 900,001+ | {name}-001.csv, {name}-002.csv, {name}-003.csv, … |
XLSX files are split using the same rule. Each chunk includes its own header row.
Reference
Filters & exclusions
Always-excluded files
These never appear in output regardless of settings:
| Pattern | Why |
|---|---|
pagefile.sys, hiberfil.sys, swapfile.sys | Windows swap files; not user content. |
Thumbs.db, ehthumbs.db, desktop.ini | Windows OS noise. |
.DS_Store | macOS Finder metadata. |
~$*, .~lock.* | Office/LibreOffice lock files. |
._* | macOS resource forks on non-HFS filesystems. |
*.tmp | Temporary files. |
Always-excluded directories
Recycle bins, indexer caches, and other OS infrastructure folders.
$RECYCLE.BIN,System Volume Information.Spotlight-V100,.Trashes,.fseventsd.TemporaryItems,.DocumentRevisions-V100
User-toggleable filters
- Hidden files — names starting with
.or with the hidden attribute set. - System files — short list of OS metadata files.
- Extension list — comma-separated. Match is on the lowercased extension without the dot.
Reference
Email file types recognized
The Copy Email Files workflow looks for files with any of these extensions:
| Extension | Source |
|---|---|
.eml | Standard MIME-encoded email — Apple Mail, Thunderbird, generic mail. |
.emlx, .emlxpart | Apple Mail message + attachment-part files. |
.msg | Outlook single-message format. |
.olk14msgsource, .olk15message | Outlook for Mac (2011, 2016+) single-message containers. |
.pst | Outlook personal storage table — whole-mailbox archive. |
.ost | Outlook offline storage — IMAP/Exchange cached copy. |
.mbox, .mbx | Unix mailbox / Eudora mailbox. |
.dbx | Outlook Express folder store. |
.tbb | The Bat! mailbox. |
.rge | Outlook Express identity archive. |
.wdseml | Windows Desktop Search email index entry. |
.pst and .ost files can be very large (multi-GB).
Copy time is bound by disk throughput; budget accordingly.
Reference
Clone-compare verdicts
Compare results land on one of these verdicts. The diff CSV always lists every actual difference, regardless of verdict.
| Verdict | Meaning |
|---|---|
| Exact Clone | Every file's path, size, and hash agree across both drives. The clone is byte-identical at the file level. |
| Content Clone | Every hash matches, but paths or extra metadata differ. The data is intact; the layout was reorganized. |
| Metadata Clone | Soft-compare only. Some PDF hashes differ at the byte level but their normalized content matches — i.e. only the PDF /ID metadata changed. Treated as a content-equivalent clone. |
| Not a Clone | At least one file is missing or has a true hash mismatch. Diff CSV lists every divergence. |
Difference Type column to see what changed.
Reference
Getty findings, and what to do about each
Every finding leads with what it wants from you.
| Prefix | Meaning |
|---|---|
| Fixed | Already corrected in the cleaned copy. Nothing to do. |
| Must Fix | Correct it before uploading. |
| Review | A judgement call. It will upload either way. |
What it looks for
| Finding | What it means |
|---|---|
| Invisible characters | A no-break space, zero-width space, tab, or similar, pasted in along with the term. These are what stop a tab-delimited upload. Fixed automatically. |
| Separator | A semicolon without its following space, or a space before it. Fixed automatically. |
| Spacing | Leading, trailing, or repeated spaces. Fixed automatically. |
| Empty tag | Two semicolons together, or a trailing one. The empty entry is dropped. |
| Not in AAT | Getty has no such term. Suggested replacements appear beside it where there are any. |
| Spelling case | The term exists but Getty spells it differently. AAT treats case as meaningful — acacia the wood is not Acacia the genus. |
| Unclosed bracket | A qualified term that lost its closing bracket, such as counters (furniture. No vocabulary will ever match it. |
| Duplicate | The same term twice in one cell, ignoring case. |
| Tag count | Fewer than 3 or more than 5 terms. |
| Too long | The cell is at or over 255 characters, the width of the Access Tags field. Access truncates at entry by character count rather than at a separator, so the last term arrives cut mid-word while looking complete. |
| Damaged text | A replacement character from an earlier encoding error. The original character cannot be recovered, so it is reported rather than guessed at. |
| Not checked | The vocabulary could not be reached for that term. This is not the same as the term being wrong, and is never reported as though it were. |
If Getty cannot be reached
The indicator beside the live option turns red before you run anything, and names the cause — a blocked host, a DNS failure, or a proxy intercepting the connection. Cleaning and every structural check still work; only term verification stops. Terms are then reported as not checked, never as wrong, because sending someone to re-verify metadata that was correct is worse than saying nothing.
Switch to the built-in list and the check runs with no network at all.
Reference
Updates
On Windows, the app checks the X:\Apps folder for a newer signed content-list-generator.exe.
Open About if support gives you a different release folder.
- The app only installs a newer signed executable from the configured release folder.
- When an update is ready, restart the app from the update prompt.
Reference
If something goes wrong
macOS: "could not verify free of malware"
Gatekeeper blocking an unsigned binary. Right-click the app → Open → Open.
Or System Settings → Privacy & Security → "Open Anyway."
Or terminal: xattr -d com.apple.quarantine /path/to/app.
Windows: SmartScreen prompt on launch
Click "More info" → "Run anyway." Will go away once the binary is code-signed.
Windows: .exe does not launch at all
Fixed in v0.2.2. If you are on an earlier version, upgrade to the current
.exe. Details in docs/debug/windows-launch-failure.md in the repo.
Output folder is not writable
The app verifies the folder is writable before scanning. If it errors out, pick a different output location.
The CSV exists already
You will be prompted to overwrite. Pick yes to replace it, or no to go back and rename the output file.
Scan is slower than expected
Network drives, encrypted volumes, and large hash modes (SHA-256, BLAKE3) all slow throughput. For a quick inventory, turn hashing off and rerun.
Reference
Frequently asked questions
Which download do I need?
macOS: the .app. Linux: the binary. Windows: the .exe. There is one application now — the Python runtime was retired once the Windows .exe could do everything it did. The .exe needs no admin rights and no installer, and runs from a USB drive or network share, so it suits managed fleets as well as personal machines.
Does it work on network drives?
Yes. SMB / NFS / mapped drives all scan correctly. Throughput is limited by network round-trip time per file, so a network scan is typically 5–20× slower than a local scan. Run with hashing off first to validate the inventory, then re-run with BLAKE3 if you need verification.
How large a scan can it handle?
There is no fixed cap. CSVs auto-chunk every 300,000 rows, and the scan streams to disk so memory stays flat regardless of row count. Multi-million-row scans are routine. The dominant cost is hash mode (full byte read of every file) and disk throughput.
Why are $RECYCLE.BIN / System Volume Information not in the output?
These OS infrastructure folders are always excluded, with no user toggle, because they never contain archival content. The same applies to swap files (pagefile.sys, hiberfil.sys, swapfile.sys), macOS metadata (.Spotlight-V100, .Trashes, .fseventsd), Office lock files (~$*, .~lock.*), and resource forks (._*).
Can I resume an interrupted scan?
No — stopping a scan discards its partial CSV. Scans are fast enough that restart is the safer model. For very large drives, work folder-by-folder so a stop only loses one subtree.
Do any of the hash options need something installed?
No. BLAKE3, SHA-1, and SHA-256 are all built into the application via github.com/zeebo/blake3 and the Go standard library. This used to be a real question on the retired Python runtime, where BLAKE3 needed a separate package.
Will email-copy modify or open .pst / .ost files?
No. Email-copy is a pure file copy by extension — it never opens, parses, or mutates email containers. Outlook can keep .pst / .ost exclusively locked while open; close Outlook before copying or expect "file in use" errors.
What if soft compare returns Metadata Clone but I want to know which PDFs differed?
The diff CSV always lists every divergence, regardless of verdict. Look for rows where Difference Type indicates a hash mismatch — those are the PDFs that matched only after /ID normalization.
Why is the XLSX file split into multiple files?
Excel's .xlsx format caps at 1,048,576 rows per sheet, and Excel itself becomes sluggish well below that. Splitting at 300,000 rows keeps each file responsive and aligns with the matching CSV chunks for easy cross-referencing.
How do I reset all settings?
Close the app, delete the settings file at the path listed in About for your OS, relaunch. The app re-creates it with defaults on next save.
Reference
Tips
- Start with hashing Off to validate paths and counts, then re-run with BLAKE3 once you trust the inventory plan.
- Stop a scan with
sorescin the TUI; in the GUI use the Stop button. - Filtered samples in the done summary tell you what got skipped. Glance over them to confirm exclusions did what you expected.
- For migrations, write the original and clone CSVs to the same output folder so the diff is easy to file alongside.
- The Windows .exe needs no admin rights and no installer — it runs from wherever you put it. Recommend it to less-technical users.
- Folders-only mode + a depth cap is the fastest way to map a drive before deciding what to scan in full.
- Settings persist across launches per-user. Reset them by deleting the settings file (path listed in About).
Reference
About this app
Diagnostic info you may need to share with whoever set up your install.
| Item | Where to find it |
|---|---|
| App version | Shown in the Wails GUI title bar; in the TUI it appears on the home screen. |
| Settings file (macOS) | ~/Library/Application Support/content-list-generator/settings.json |
| Settings file (Windows) | %APPDATA%\content-list-generator\settings.json |
| Settings file (Linux) | ~/.config/content-list-generator/settings.json |
| Settings file (Windows) | %APPDATA%\content-list-generator\settings.json |
| Latest release | github.com/snyderb-de/content-list-toolkit/releases/latest |
| Source code | github.com/snyderb-de/content-list-toolkit |
| Project dashboard | Open the dashboard — live stats, downloads, roadmap. |