Skill: 10oss/skreenshot (version 0.0.1)

--- name: Skreenshot description: Organize, tag, search, and manage screenshots on macOS. Use when users need to: (1) find specific screenshots, (2) organize screenshots into folders by category/project, (3) search screenshot content via OCR, (4) bulk rename or move screenshots, (5) clean up old screenshots, or (6) integrate with CleanShot X or macOS screenshot tool. --- # Skreenshot macOS accumulates screenshots rapidly—on the Desktop by default, often forgotten and unorganized. This skill provides workflows to tame the chaos. ## Quick Start **Find screenshots:** ```bash # List recent screenshots (last 7 days) find ~/Desktop -name "Screenshot*.png" -mtime -7 | head -20 # Search by content (OCR) textsnip -i ~/Desktop/Screenshot*.png | grep -i "receipt" ``` **Organize:** ```bash # Move to categorized folders mkdir -p ~/Pictures/Screenshots/{work,personal,receipts,memes} mv ~/Desktop/Screenshot*.png ~/Pictures/Screenshots/personal/ ``` ## Default Screenshot Location macOS saves to `~/Desktop` by default. Change it: ```bash # Set custom location defaults write com.apple.screencapture location ~/Pictures/Screenshots killall SystemUIServer ``` ## Screenshot Naming Patterns Default: `Screenshot YYYY-MM-DD at HH.MM.SS.png` Smart rename with context: ```bash # Use script for batch rename with date + optional tags python scripts/rename_screenshots.py --add-tags work,receipt ``` ## OCR Search Search screenshot content with OCR tools: - **textsnip** (CLI): `textsnip -i *.png | grep "search term"` - **EasyOCR** (Python): See `references/ocr-setup.md` - **macOS built-in**: Live Selection (Cmd+Shift+4 then drag) ## Organization Strategies ### By Project/Client ``` Pictures/Screenshots/ ├── client-acme/ ├── client-globex/ └── personal/ ``` ### By Category ``` Pictures/Screenshots/ ├── receipts/ ├── bugs/ ├── inspiration/ ├── memes/ └── reference/ ``` ### By Date (auto-archive) ``` Pictures/Screenshots/ ├── 2026/ │ ├── 01-january/ │ ├── 02-february/ │ └── ... ``` ## CleanShot X Integration If using CleanShot X: - Screenshots save to custom folder (configurable) - OCR built-in (Cmd+Shift+O) - Auto-upload to cloud (optional) See `references/cleancast-x.md` for workflow details. ## Automation Scripts ### `scripts/rename_screenshots.py` Batch rename with smart patterns (date, app name, tags). ### `scripts/archive_old_screenshots.py` Move screenshots older than N days to archive folder. ### `scripts/ocr_search.py` Search all screenshots by text content. ## Workflow Examples **"Find that screenshot of the error message"** 1. Search by date range (when did you see the error?) 2. OCR search for error text 3. Open matching results **"Organize my Desktop screenshots"** 1. Run archive script for old screenshots 2. Move recent ones to categorized folders 3. Update links if needed (wikilinks, docs) **"Search all screenshots for 'invoice'"** 1. Run OCR search script 2. Filter results by date/category 3. Return matches with preview --- **References:** - `references/ocr-setup.md` - OCR tool setup and usage - `references/cleancast-x.md` - CleanShot X workflows - `references/automation-patterns.md` - Advanced automation scripts

path: scripts/rename_screenshots.py
content: #!/usr/bin/env python3
"""
Rename screenshots with smart patterns.

Usage:
    python rename_screenshots.py [directory] [--tags tag1,tag2] [--dry-run]

Examples:
    python rename_screenshots.py ~/Desktop --tags work,bug
    python rename_screenshots.py --dry-run
"""

import os
import re
import sys
from datetime import datetime
from pathlib import Path

def parse_screenshot_filename(filename):
    """Extract date/time from default screenshot name."""
    # Pattern: Screenshot YYYY-MM-DD at HH.MM.SS.png
    match = re.search(r'Screenshot (\d{4}-\d{2}-\d{2}) at (\d{2})\.(\d{2})\.(\d{2})', filename)
    if match:
        date_str = match.group(1)
        time_str = f"{match.group(2)}:{match.group(3)}:{match.group(4)}"
        return date_str, time_str
    return None, None

def rename_screenshot(filepath, tags=None, dry_run=False):
    """Generate new filename with optional tags."""
    filename = os.path.basename(filepath)
    date_str, time_str = parse_screenshot_filename(filename)
    
    if not date_str:
        # Use file modification date as fallback
        mtime = os.path.getmtime(filepath)
        date_str = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d')
        time_str = datetime.fromtimestamp(mtime).strftime('%H:%M:%S')
    
    # Build new name
    base_name = f"{date_str}_{time_str.replace(':', '-')}"
    if tags:
        base_name += f"_{'+'.join(tags)}"
    
    new_filename = f"{base_name}.png"
    return new_filename

def main():
    args = sys.argv[1:]
    
    # Parse args
    directory = None
    tags = None
    dry_run = False
    
    i = 0
    while i < len(args):
        if args[i] == '--tags' and i + 1 < len(args):
            tags = args[i + 1].split(',')
            i += 2
        elif args[i] == '--dry-run':
            dry_run = True
            i += 1
        elif not args[i].startswith('--'):
            directory = args[i]
            i += 1
        else:
            i += 1
    
    # Default directory
    if not directory:
        directory = os.path.expanduser('~/Desktop')
    
    directory = os.path.expanduser(directory)
    
    # Find screenshots
    screenshots = [f for f in os.listdir(directory) 
                   if f.startswith('Screenshot') and f.endswith('.png')]
    
    if not screenshots:
        print(f"No screenshots found in {directory}")
        return
    
    print(f"Found {len(screenshots)} screenshots in {directory}\n")
    
    for filename in screenshots:
        filepath = os.path.join(directory, filename)
        new_name = rename_screenshot(filepath, tags=tags)
        
        if dry_run:
            print(f"[DRY] {filename} → {new_name}")
        else:
            new_path = os.path.join(directory, new_name)
            if os.path.exists(new_path):
                print(f"[SKIP] {new_name} already exists")
            else:
                os.rename(filepath, new_path)
                print(f"[RENAMED] {filename} → {new_name}")

if __name__ == '__main__':
    main()


path: scripts/archive_old_screenshots.py
content: #!/usr/bin/env python3
"""
Archive old screenshots to organized folders.

Usage:
    python archive_old_screenshots.py [--days N] [--dry-run]

Moves screenshots older than N days from Desktop to Pictures/Screenshots/
organized by date.

Examples:
    python archive_old_screenshots.py --days 7
    python archive_old_screenshots.py --days 30 --dry-run
"""

import os
import re
import sys
import shutil
from datetime import datetime, timedelta
from pathlib import Path

def get_screenshot_date(filepath):
    """Extract date from filename or use mtime."""
    filename = os.path.basename(filepath)
    match = re.search(r'Screenshot (\d{4})-(\d{2})-(\d{2})', filename)
    if match:
        return datetime(int(match.group(1)), int(match.group(2)), int(match.group(3)))
    
    # Fallback to modification time
    mtime = os.path.getmtime(filepath)
    return datetime.fromtimestamp(mtime)

def archive_screenshots(source_dir, dest_base, days_old=30, dry_run=False):
    """Move old screenshots to dated archive folders."""
    
    source_dir = os.path.expanduser(source_dir)
    dest_base = os.path.expanduser(dest_base)
    
    # Find screenshots
    screenshots = [f for f in os.listdir(source_dir)
                   if f.startswith('Screenshot') and f.endswith('.png')]
    
    if not screenshots:
        print(f"No screenshots found in {source_dir}")
        return
    
    cutoff_date = datetime.now() - timedelta(days=days_old)
    moved = 0
    skipped = 0
    
    for filename in screenshots:
        filepath = os.path.join(source_dir, filename)
        screenshot_date = get_screenshot_date(filepath)
        
        if screenshot_date >= cutoff_date:
            # Recent, skip
            skipped += 1
            continue
        
        # Create dated folder: YYYY/MM/
        year_folder = os.path.join(dest_base, str(screenshot_date.year))
        month_folder = os.path.join(year_folder, f"{screenshot_date.month:02d}")
        
        if dry_run:
            print(f"[DRY] {filename} ({screenshot_date.date()}) → {month_folder}/")
        else:
            os.makedirs(month_folder, exist_ok=True)
            dest_path = os.path.join(month_folder, filename)
            if os.path.exists(dest_path):
                print(f"[SKIP] {filename} already exists in archive")
                skipped += 1
            else:
                shutil.move(filepath, dest_path)
                print(f"[MOVED] {filename} → {month_folder}/")
                moved += 1
    
    print(f"\nSummary: {moved} moved, {skipped} skipped (recent)")

def main():
    args = sys.argv[1:]
    
    days_old = 30
    dry_run = False
    
    i = 0
    while i < len(args):
        if args[i] == '--days' and i + 1 < len(args):
            days_old = int(args[i + 1])
            i += 2
        elif args[i] == '--dry-run':
            dry_run = True
            i += 1
        else:
            i += 1
    
    source = '~/Desktop'
    dest = '~/Pictures/Screenshots'
    
    print(f"Archiving screenshots older than {days_old} days")
    print(f"Source: {source}")
    print(f"Destination: {dest}")
    if dry_run:
        print("[DRY RUN - no files will be moved]\n")
    
    archive_screenshots(source, dest, days_old=days_old, dry_run=dry_run)

if __name__ == '__main__':
    main()


path: references/automation-patterns.md
content: # Automation Patterns

## Weekly Cleanup Cron

Add to crontab for automatic screenshot organization:

```bash
# Weekly: Move old screenshots to archive (Sundays at 9am)
0 9 * * 0 cd ~/Documents/Skreenshot && python scripts/archive_old_screenshots.py --days 30
```

## Hazel Rules (macOS)

Hazel can auto-sort screenshots based on rules:

**Rule 1: Move to dated folders**
- If name matches `Screenshot .*`
- Created date is not in last 7 days
- → Move to `~/Pictures/Screenshots/YYYY/MM/`

**Rule 2: Tag receipts**
- If name contains `receipt` OR OCR contains "invoice", "total", "$"
- → Add tag: receipts
- → Move to `~/Pictures/Screenshots/receipts/`

**Rule 3: Delete old screenshots**
- If created date > 1 year ago
- AND not in any tagged folder
- → Move to Trash

## Keyboard Maestro Macros

**Macro: Quick Screenshot Sort**
1. Trigger: Hot key (Cmd+Opt+S)
2. Action: Run script `rename_screenshots.py --tags quick`
3. Action: Move to `~/Pictures/Screenshots/quick/`

**Macro: Search Last Screenshot**
1. Trigger: Hot key (Cmd+Opt+F)
2. Action: Get last screenshot from Desktop
3. Action: OCR and display in alert
4. Action: Copy OCR text to clipboard

## Shell Aliases

Add to `~/.zshrc`:

```bash
# Quick screenshot search
alias ss-search='textsnip -i ~/Desktop/Screenshot*.png | grep -i'

# List recent screenshots
alias ss-recent='find ~/Desktop -name "Screenshot*.png" -mtime -7 | head -20'

# Organize Desktop screenshots
alias ss-organize='cd ~/Documents/Skreenshot && python scripts/archive_old_screenshots.py'
```

## Shortcuts App (iOS/macOS)

**Shortcut: Screenshot Tagger**
1. Input: Selected screenshot(s)
2. Action: Run Python script with tag parameter
3. Output: Moved to categorized folder

**Shortcut: Find Screenshot**
1. Input: Search term (text)
2. Action: OCR search across Pictures/Screenshots
3. Action: Return matching files
4. Output: Quick Look preview


path: references/cleancast-x.md
content: # CleanShot X Workflows

CleanShot X is a premium screenshot tool for macOS with advanced features.

## Key Features

- **Custom save location** (not Desktop clutter)
- **Built-in OCR** (Cmd+Shift+O)
- **Auto-upload to cloud** (optional, generates shareable links)
- **Scrolling screenshots** (full webpage capture)
- **Screen recording** (GIF/MP4)
- **Annotation tools** (arrows, boxes, blur, text)

## Configuration

### Set Custom Save Location
1. CleanShot X Preferences → Save To → Custom Folder
2. Recommended: `~/Pictures/Screenshots`

### Auto-OCR
Enable auto-OCR on capture to make screenshots searchable immediately.

### Cloud Upload
- Uploads to cleancast.cloud (or custom S3)
- Generates short shareable URLs
- Optional: auto-copy URL to clipboard

## Workflow Integration

**Capture → Organize:**
1. Capture with CleanShot (saves to custom folder)
2. Run `scripts/archive_old_screenshots.py` weekly
3. OCR index updated automatically

**Capture → Share:**
1. Capture → auto-upload enabled
2. URL copied to clipboard
3. Paste in chat/docs

**Search:**
1. Use CleanShot OCR library (stored in metadata)
2. Or run `scripts/ocr_search.py` on folder

## Keyboard Shortcuts

| Action | Shortcut |
|--------|----------|
| Area capture | Cmd+Shift+A |
| Window capture | Cmd+Shift+W |
| Full screen | Cmd+Shift+F |
| OCR selection | Cmd+Shift+O |
| Last capture | Cmd+Shift+L |


path: references/ocr-setup.md
content: # OCR Setup for Screenshot Search

## Tools

### textsnip (CLI)
Fast, lightweight OCR for macOS.

**Install:**
```bash
brew install textsnip
```

**Usage:**
```bash
# OCR a single image
textsnip -i screenshot.png

# OCR multiple files
textsnip -i ~/Desktop/Screenshot*.png

# Pipe to grep for search
textsnip -i ~/Desktop/Screenshot*.png | grep -i "error"
```

### EasyOCR (Python)
More accurate, supports multiple languages.

**Install:**
```bash
pip install easyocr
```

**Usage:**
```python
import easyocr
reader = easyocr.Reader(['en'])
result = reader.readtext('screenshot.png')
for (bounds, text, prob) in result:
    print(text)
```

### macOS Built-in (Live Text)
- **Cmd+Shift+4** then drag to select
- Text is auto-copied to clipboard
- Works in Preview app: select text tool

## Performance Tips

- **textsnip**: Fast for batch operations, good accuracy
- **EasyOCR**: Slower but better for complex layouts
- **Live Text**: Best for one-off captures

## Indexing Strategy

For large screenshot collections, build an index:
```bash
# One-time index creation
for f in ~/Pictures/Screenshots/*.png; do
  textsnip -i "$f" >> ~/Pictures/Screenshots/ocr-index.txt
done

# Search index
grep -i "invoice" ~/Pictures/Screenshots/ocr-index.txt
```


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)