media-import

star 0

Unified inbox ingestion skill for carteakey.dev. Scans inbox/ subdirectories, diffs against already-imported files, shows a preview of what will be imported and handles 4 distinct content targets: photography (photos.yaml), vibes (src/static/img/vibes/), ai-memes folio (folio/ai-memes/index.html), and loose root inbox files that need classification first.

carteakey By carteakey schedule Updated 5/12/2026

name: media-import description: > Unified inbox ingestion skill for carteakey.dev. Scans inbox/ subdirectories, diffs against already-imported files, shows a preview of what will be imported and handles 4 distinct content targets: photography (photos.yaml), vibes (src/static/img/vibes/), ai-memes folio (folio/ai-memes/index.html), and loose root inbox files that need classification first.

Media Import Skill

You are helping import media from the inbox/ staging area into the site. There are 4 distinct content targets, each with its own ingestion pattern. Always diff first, confirm with the user, then execute.

Step 0 - Consult Manifest

Before any import, check inbox/manifest.yaml.

  • Missing Entries: If a file is not in the manifest, run the manifest-update skill to classify it.
  • Ignores: Files in inbox/_ignore/ are ignored by all skills and not tracked in the manifest.
  • Descriptions: Use the description field from the manifest for all imported media (captions, alt text, etc.).
  • Targets: Respect the suggested_target.

Step 1 - Scan and Diff

Run the following to understand what's in the inbox vs already imported:

# Show all files in inbox (recursively, excluding .DS_Store)
find inbox/ -type f ! -name ".DS_Store" | sort

# Show already-imported photos
grep "^  path:" src/_data/photos.yaml | sed 's|.*path: ||' | sort

# Show already-imported vibes
ls src/static/img/vibes/

# Show already-imported ai-memes
grep 'src="/img/folio/ai-memes/' src/folio/ai-memes/index.html | grep -o 'src="[^"]*"' | sed 's/src="//;s/"//' | sort

Build a table of unimported files per target:

File Inbox path Target Status
... inbox/photography/IMG_xxx.jpg photography ⏳ pending
... inbox/vibes/meme.webp vibes ⏳ pending
... inbox/ai-memes/funny.webp ai-memes folio ⏳ pending
... inbox/something.jpg ❓ unclassified needs routing

Manifest Pre-check: Always cross-reference the find output with inbox/manifest.yaml. If a file is not in the manifest, you must describe it and add it to the manifest first.

Hash-based dedup (required for photography): Do NOT rely on filename matching for photos - the same image may be deployed under a different name. Run MD5 hashes against all deployed photos and cross-check before importing:

# Hash all inbox photos
md5 inbox/photography/*.{jpg,jpeg,png,JPG} 2>/dev/null

# Hash all deployed photos
md5 src/static/img/photography/real/*.{jpg,jpeg,png,JPG} 2>/dev/null | sort -k4

# Any matching hash = already imported, skip it

If a hash match is found, update the existing YAML entry with the correct title, path rename, and real EXIF data - do NOT add a new entry. Rename the deployed file to the human title slug.

For vibes and ai-memes, filename-based dedup is sufficient (filenames are stable Reddit/Twitter hashes).

Show the user this table and ask: "Which of these should I import, and to which target?" before proceeding.


Step 2 - Content Targets

Target A: Photography (inbox/photography/)

Destination: src/static/img/photography/{real|virtual}/ + src/_data/photos.yaml

Rules:

  • Use the existing script: node utils/add-photo.mjs (interactive) for one-off imports.
  • For bulk AI-agent imports, replicate its logic manually:
    1. Read EXIF data (device, aperture, ISO, shutter, date, GPS).
    2. Reverse-geocode GPS if available (Nominatim API).
    3. Generate a short, human title (2–5 words, lowercase vibes, no AI slop). Examples: "Still waters", "Golden hour on the lake", "Dam son". Do NOT generate verbose sentences or use words like "serene", "tranquil", "vibrant", "evocative".
    4. Do NOT generate descriptions - leave description field absent unless truly necessary.
    5. Classify as real (photos) or virtual (game screenshots).
    6. Slugify the title for the filename. Copy file to appropriate subdirectory.
    7. Prepend the YAML entry to src/_data/photos.yaml.

YAML entry format (real photo):

- title: Short human title
  category: real
  path: /img/photography/real/slugified-title.jpg
  device: iPhone 16          # from EXIF or "Unknown"
  make: Apple                # from EXIF or "Unknown"
  lens: ...                  # from EXIF or "Unknown"
  focalLength: ...           # from EXIF or "Unknown"
  aperture: ...              # from EXIF or "Unknown"
  iso: ...                   # from EXIF or "Unknown"
  shutterSpeed: ...          # from EXIF or "Unknown"
  date: 'YYYY-MM-DD'
  width: 1234
  height: 5678
  location: City, Country    # from GPS reverse-geocode or "Unknown"

YAML entry format (virtual / game screenshot):

- title: Short title
  category: virtual
  path: /img/photography/virtual/slugified-title.png
  date: 'YYYY-MM-DD'
  width: 1234
  height: 5678
  game: Elden Ring
  platform: PC

Target B: Vibes (inbox/vibes/)

Destination: src/static/img/vibes/

Rules:

  • Just copy the file. vibes.js auto-discovers everything in that directory.
  • Supported formats: .jpg, .jpeg, .png, .gif, .webp, .avif.
  • Rename to a slugified lowercase filename if the original is a messy Reddit/Twitter URL hash.
  • No YAML or HTML edits needed.
cp "inbox/vibes/some-meme.webp" "src/static/img/vibes/some-meme.webp"

Target C: AI Memes Folio (inbox/ai-memes/)

Destination: src/_data/memes.yaml and src/static/img/folio/ai-memes/

Rules:

  • Copy the file to src/static/img/folio/ai-memes/.
  • Prepend a new YAML entry to src/_data/memes.yaml (newest first).
  • Increment the id from the previous highest card (e.g., if the highest is "025", the new one is "026").

YAML entry format:

- id: "026"
  image: "/img/folio/ai-memes/FILENAME.webp"
  caption: "Short punchy caption"
  tags:
    - "TAG1"
    - "TAG2"
  vibes: 0
  submitter: "anonymous intern"
  time: "just now"
  source_name: "the feed" # optional
  source_url: "#"         # optional

Caption / tags guidance:

  • Caption: 1 punchy sentence. Dry wit preferred. No AI-sounding descriptions.
  • Tags: pick from existing set (xkcd-style, agents, vibe-coding, existential, relatable, burnout, prompt-engineering, hallucinated, shipped-to-prod, my-agent-did-this) or invent short kebab-case tags.

Target D: Unclassified root inbox/*.{jpg,png,...}

Files sitting in inbox/ root (not in a subfolder) need to be classified first.

Ask the user: "I found [N] unclassified files in inbox/. Where should each go?" Show a thumbnail description and let them route to A/B/C or skip.


Step 3 - Execute

For each approved file:

  1. Copy the file to its destination.
  2. Make the appropriate data or HTML edit.
  3. By default, plan to delete successfully imported files from the inbox/ directory at the end of the run to keep it clean.

After all imports, run a quick sanity check:

# Verify photos.yaml is valid YAML
node -e "import('js-yaml').then(m => { m.default.load(require('fs').readFileSync('src/_data/photos.yaml','utf8')); console.log('photos.yaml OK'); })"

# Count vibes images
ls src/static/img/vibes/ | wc -l

# Count meme cards in folio
grep -c 'class="meme-card"' src/folio/ai-memes/index.html

Step 4 - Commit

git add src/_data/photos.yaml src/static/img/photography/ src/static/img/vibes/ src/static/img/folio/ai-memes/ src/folio/ai-memes/index.html
git commit -m "feat(inbox): import [N] photos / [N] vibes / [N] ai-memes"
git push origin main

Step 5 - Inbox Cleanup

After successfully committing and verifying the media is live in the destination folders, automatically delete the original files from the inbox/ subdirectories to keep the staging area clean.

# Example: delete imported photos after commit
rm inbox/photography/IMG_xxx.jpg

Conventions & Anti-Patterns

✅ Do ❌ Don't
Short 2–5 word titles for photos Generate verbose AI descriptions
Use words like "Dam son", "Still waters" Use "serene", "vibrant", "evocative", "tranquil"
Leave description absent if not needed Copy or paraphrase what the script generates
Preserve EXIF data accurately Make up EXIF values
Insert ai-memes newest-first Append to end of meme grid
Renumber all card indices after insert Leave index numbers out of sync
Ask before routing unclassified files Guess the target
Install via CLI
npx skills add https://github.com/carteakey/carteakey.dev --skill media-import
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator