add btime fallback, app-library exclusion, --year, --include-untagged
Behavior changes (all opt-in or safety-first):
- prep refuses to operate inside .photoslibrary, .lrlibrary, .aplibrary,
.fcpbundle, .band, .logicx, .app, etc. unless --allow-app-libraries
- --year YYYY restricts to files whose embedded ts (or btime) starts with YYYY
- --include-untagged accepts hand-named image files (no CleanShot/Screenshot
prefix) and dates them via stat btime → mtime fallback. Gated on the folder
containing ≥10 tagged matches to prevent sweeping ~/Pictures or similar
- prep pre-pass auto-normalizes the missing-space typo
('foo barCleanShot 2026-...' → 'foo bar CleanShot 2026-...') by os.rename
- plan now iterates the desc-tsv contents instead of the full src dir, with
alt-extension fallback for Haiku's occasional .jpg-instead-of-.png echo
- build_new_name supports app=None (untagged) — emits
'<keywords> - <Description> - YYYY-MM-DD.ext'
SKILL.md: gotchas #14-17 documenting each new guard, run-order updated
with the new flags, common-mistakes table extended.
Verified by smoke test with seeded files: --year filter, --include-untagged
threshold gate, app-library refusal, and typo normalization all behave.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,11 +26,14 @@ The pipeline is **prep → batch → describe (parallel agents) → validate pla
|
||||
- Both `CleanShot ...` and Apple `Screenshot ...` filename prefixes are recognized in the same pass
|
||||
- Files with a leading user-typed keyword prefix (e.g. `jojo travel CleanShot 2026-...png`) are recognized; the keywords are preserved and merged into the new name
|
||||
- Files already in the renamed form (`App - Description - timestamp.ext`) are detected and skipped — re-running the skill on a folder is safe and idempotent
|
||||
- Hand-named files with no embedded timestamp (e.g. `flight to australia 1.png`) — pass `--include-untagged`. Date is taken from filesystem btime/mtime. Only allowed when the folder already contains ≥10 tagged screenshots, so we don't sweep up arbitrary photo libraries.
|
||||
- Restrict to a single year with `--year YYYY` (matches embedded ts or btime).
|
||||
|
||||
**Don't use for:**
|
||||
- Code or text files — vision isn't needed
|
||||
- Files where the name pattern is already meaningful
|
||||
- Single-file rename (just do it directly)
|
||||
- App-managed image catalogs (Apple Photos `.photoslibrary`, Lightroom `.lrlibrary`, Aperture `.aplibrary`, Final Cut, etc.) — the pipeline refuses to run inside these by default. Override with `--allow-app-libraries` only if you know what you're doing.
|
||||
|
||||
## Workflow
|
||||
|
||||
@@ -89,6 +92,14 @@ The pipeline is **prep → batch → describe (parallel agents) → validate pla
|
||||
|
||||
13. **Leading keyword prefix is part of the source signal.** When the user has hand-prefixed a file (e.g. `jojo travel flight ... CleanShot 2026-...png`), those keywords are user knowledge the AI doesn't have. Title-case them and prepend them to the AI description before assembling the new name. Don't drop them.
|
||||
|
||||
14. **App library packages are off-limits by default.** Apple Photos (`.photoslibrary`), Lightroom (`.lrlibrary`), Aperture (`.aplibrary`), Final Cut (`.fcpbundle`), GarageBand (`.band`), Logic (`.logicx`) and any `.app` are all bundles whose internals are managed by the host app. Renaming files inside them silently corrupts the catalog. The pipeline checks every segment of the source path against a suffix list and refuses to run if any matches. `--allow-app-libraries` overrides for the rare legitimate case (e.g. a `.app` bundle that happens to contain user-curated screenshots).
|
||||
|
||||
15. **Untagged files need a "this is a screenshot dump" gate.** A naive run on `~/Pictures` would happily try to rename every JPEG in sight. The fix: require ≥10 files matching the existing CleanShot/Screenshot regex BEFORE accepting any untagged file as a rename candidate. Without that signal, fall back to a hint-only message ("N untagged file(s) skipped; pass --include-untagged"). The threshold is configurable via `--untagged-threshold`.
|
||||
|
||||
16. **Filename embeds a timestamp until it doesn't.** Hand-named files like `flight to australia 1.png` have no `2026-MM-DD at HH.MM.SS` to harvest. Use `stat -f %SB -t %F` for macOS btime when available; mtime if btime is absent or before 1990 (a sentinel for "filesystem doesn't track this"). Date precision drops from `YYYY-MM-DD at HH.MM.SS` to `YYYY-MM-DD` and the new filename uses ` - ` between the kept-stem and the AI description: `<stem> - <Description> - YYYY-MM-DD.ext`.
|
||||
|
||||
17. **The missing-space typo (`tabCleanShot 2026-...`) silently excludes files.** Some user-prefixed files lack the space between the user's keyword and `CleanShot`/`Screenshot`. The parser requires `\s+` and drops these. The fix is a pre-pass in `prep` that runs `os.rename` to insert the space (`tabCleanShot ...` → `tab CleanShot ...`) before parsing. Logged so the user sees what got normalized.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Step | Command |
|
||||
@@ -111,6 +122,14 @@ Run order:
|
||||
python3 ~/.claude/skills/screenshot-rename/pipeline.py prep \
|
||||
--src "/path/to/folder" --batch-size 19
|
||||
|
||||
# Optional flags on prep:
|
||||
# --year 2026 only files whose ts (or btime) starts with 2026
|
||||
# --include-untagged also rename hand-named images using btime/mtime
|
||||
# as the date (only if folder has ≥10 tagged files)
|
||||
# --untagged-threshold N override the ≥10 default
|
||||
# --allow-app-libraries bypass the .photoslibrary / .lrlibrary guard
|
||||
# (DANGEROUS — only for the rare legitimate case)
|
||||
|
||||
# Now dispatch one Haiku Agent per /tmp/screenshot-rename/full-batch-NN file
|
||||
# (Claude Code does this — see SKILL.md "Workflow" step 3)
|
||||
|
||||
@@ -159,6 +178,10 @@ Dispatch all batches **in a single message with multiple Agent tool calls** so t
|
||||
| Looking up Haiku's filename column verbatim | Apple Screenshot files contain U+202F (narrow no-break space); Haiku echoes it as ASCII space, lookup misses every Screenshot file | Normalize U+202F → ASCII space on both sides of the desc dict |
|
||||
| Hardcoding a single `--prefix` (e.g. `CleanShot`) | Apple Screenshot files and user-prefixed files get silently excluded from the manifest | Parser accepts both `CleanShot` and `Screenshot` and an optional leading keyword phrase |
|
||||
| Re-running the skill without an already-renamed skip rule | Each run prepends another description; names balloon | Detect `^App - .+ - timestamp\.ext$` and skip |
|
||||
| Walking into `.photoslibrary` / `.lrlibrary` etc. on a parent dir scan | Renames inside an app-managed bundle silently corrupt the catalog | Refuse if any path segment ends with one of the package suffixes; require `--allow-app-libraries` to override |
|
||||
| Sweeping arbitrary photos in a non-screenshot folder | A user invokes the skill on `~/Pictures` and the pipeline tries to rename every JPEG | Gate untagged-file inclusion on ≥10 CleanShot/Screenshot matches in the folder, AND require explicit `--include-untagged` |
|
||||
| Treating filename as the only date source | Hand-named files (e.g. `flight to Australia 1.png`) have no embedded timestamp and get dropped | Fall back to filesystem btime (`stat -f %SB`), then mtime; emit `YYYY-MM-DD` (no time component) in the new filename |
|
||||
| User keyword abutting `CleanShot` with no space | Files like `weird tabCleanShot 2026-...png` don't match the regex and get silently excluded | Pre-pass in `prep` runs `os.rename` to insert the missing space before parsing |
|
||||
|
||||
## Recovery — if something does go wrong
|
||||
|
||||
@@ -174,4 +197,6 @@ First run on 196 CleanShot files lost 4 of them due to the bash-regex-in-zsh got
|
||||
|
||||
Third run (20 mixed CleanShot + Apple Screenshot + one user-prefixed file) hit the U+202F gotcha (rule #11) on first plan attempt — every Screenshot file was dropped from the plan with a NO_DESC error despite the description being present. Diagnosed via `repr()` of the live filename. After adding U+202F normalization, multi-prefix support, and keyword preservation, all 20 renamed in one pass.
|
||||
|
||||
Fourth run (43 files of mixed years in a Dropbox folder containing 2,260 total) needed a year filter and revealed that hand-named files (`flight to Australia 1.png`) silently fell through both the prefix gate and the year-substring filter. Subsequent skill update added `--year`, `--include-untagged` (gated on ≥10 tagged matches), btime/mtime fallback for date inference, automatic missing-space typo normalization, and a hard refusal to walk into Apple Photos / Lightroom / Aperture / Final Cut packages. The "screenshot dump" gate was added specifically to prevent the skill from sweeping `~/Pictures` on a future invocation.
|
||||
|
||||
This skill exists so those don't happen again.
|
||||
|
||||
Reference in New Issue
Block a user