Inspiration

Phone backup apps put every photo into one NAS folder. After a year that folder holds thousands of files called IMG_20260712_183005.jpg. Nobody remembers photos that way. We remember "the Split trip" or "Grandma's birthday".

The NAS can already sort files by type or by month, and Google Photos or Apple Photos group trips inside their own apps. I wanted plain folders on my own storage, named after what happened, that open in any file manager and still make sense if I switch apps.

What it does

photo-event-folders is a Uliya Skill for the UGREEN AI NAS. You name a source folder and a destination. The Skill finds events from capture time and place and names each folder by date, place and a short scene label from the NAS vision model. It shows you the plan and moves files only after you reply yes.

2026/
├── 2026-05-03 Dolomites – mountain hike/
├── 2026-07-12 Split – beach/
└── 2026-07 Misc/

How I built it

I started with a brainstorming session in Claude Code to pin down who the Skill is for. Then came a grilling round of 14 design questions: gap length, minimum event size, what counts as a trip, Live Photos, name conflicts and repeat runs. I made each decision, and Claude drafted SKILL.md from them.

The grouping rules fit in a few lines. With files sorted by capture time, file i starts a new group when

$$t_i - t_{i-1} > 6\ \text{h}$$

Home is the place that occurs most often in the batch. Groups on consecutive days at one place other than home merge into a trip. A group G becomes an event when

$$|G| \ge 10$$

counting a Live Photo pair once. Smaller groups go to a monthly Misc folder.

The Skill holds no code. It delegates to two NAS expert agents: file-agent lists files, creates folders and moves them, and photo-agent reads capture metadata and place names and asks the vision model for scene labels. I checked every action against the kit's capability catalog of 78 actions and ran the kit's static checker until it reported zero errors and zero warnings.

Challenges

  • The checker is stricter than the template. Capability evidence needs the → arrow, while the kit template uses ->. Delegate instructions must be single-quoted and may not contain apostrophes, flags or angle-bracket placeholders, so I rewrote several of them.
  • Repeat runs. People rename folders, so matching by name would create duplicates. The Skill reads each existing folder's date range from the photo index, and a new group joins any folder it overlaps.
  • Safety. Moved files are hard to put back, so the Skill never overwrites, deletes or renames. A name conflict leaves the file in the source and lists it in the report. I left out the batch-move action because it can rename files.
  • Approvals. cpmv moves one file per call behind the approval gateway, so a big first run may ask for many approvals.
  • Missing metadata. Messaging apps strip EXIF. The Skill falls back to dates in file names and leaves undated files where they are.

What I learned

  • A Uliya orchestration Skill never calls the CLI itself. The parent only delegates to expert agents and has to handle every state they return: completed, failed, cancelled, waiting_user and waiting_approval.
  • Reading the capability catalog first kept me from rebuilding what the NAS already does. Sorting by date is built in. Event detection and naming are not.
  • The catalog lists permissions and stability as unknown for every action. I planned for the strict case: every change goes through approval, and every step reports partial results.

What's next

If the Skill reaches Round 2, I will test it on the assigned NAS: place names from the photo index, scene label quality, and how approval prompts and speed hold up on 1000+ files.

Built With

  • claude-code
  • exif
  • markdown
  • node.js
  • ugos
  • ugreen-ai-nas
  • uliya
  • uliya-skill-kit
  • vision-language-model
Share this project:

Updates

Submission history