instagram-pipeline — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited instagram-pipeline (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
End-to-end pipeline: sync saved posts from Instagram's API, download media, and extract searchable text (Whisper transcription + OCR). Works with just Chrome cookies — no archive download or separate login needed.
The pipeline code is bundled with this skill in the scripts/ directory — no external package needed.
venv modulelightning-whisper-mlx and ocrmac)# Find the skill's scripts directory (works for both plugin and manual installs)
SCRIPTS_DIR=$(find ~/.claude -path '*/instagram-pipeline/scripts' -type d 2>/dev/null | head -1)
# Fallback: search in common locations
if [ -z "$SCRIPTS_DIR" ]; then
SCRIPTS_DIR=$(find ~/Claude\ Code\ Projects -path '*/instagram-pipeline/scripts' -type d 2>/dev/null | head -1)
fi
echo "Scripts: $SCRIPTS_DIR"If SCRIPTS_DIR is empty, the skill isn't installed. Install with:
claude plugin add simonstrumse/vibelabs-skills# Option A: Use the setup script
bash "$SCRIPTS_DIR/setup.sh" # Core (sync + download)
bash "$SCRIPTS_DIR/setup.sh" --extract # Core + Whisper + OCR
# Option B: Manual setup
python3 -m venv .venv
.venv/bin/pip install -e "$SCRIPTS_DIR" # Core
.venv/bin/pip install -r "$SCRIPTS_DIR/requirements-extract.txt" # Extraction (optional)PROJECT_DIR=$(pwd)
VENV="$PROJECT_DIR/.venv/bin/python3"
DATA_FILE="$PROJECT_DIR/data/instagram/saved_posts.json"Verify these exist before proceeding.
| Step | Command | What it does | Rate |
|---|---|---|---|
| 1. Sync | api_bootstrap sync | Fetches all saved posts + collection tags from API | ~260 posts/min |
| 2. Media | api_bootstrap sync (default) | Downloads images/videos in parallel | 4 concurrent threads |
| 3. Extract | media_extractor run | Whisper large-v3 audio + ocrmac OCR | ~2.8 posts/min |
Steps 1-2 happen together in a single sync command. Step 3 runs separately on downloaded media.
$ARGUMENTS is status or empty → show status only (Step 1), don't run anything$ARGUMENTS is collections → list collections from API, don't run anything$ARGUMENTS as collection name and run the full pipeline (Steps 1-4)If a data file exists, show enrichment and extraction progress:
SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -c "
from socmed.config import DATA_FILES
from socmed.storage.json_store import JsonStore
from collections import Counter
store = JsonStore(DATA_FILES['instagram']['saved_posts'])
posts = store.read()
enriched = sum(1 for p in posts if p.get('source') == 'archive+api')
pending = sum(1 for p in posts if p.get('source') == 'archive')
extracted = sum(1 for p in posts if p.get('extracted_text'))
with_media = sum(1 for p in posts if any(m.get('local_path') for m in p.get('media', [])))
print(f'Total: {len(posts)}')
print(f'Enriched: {enriched} ({enriched*100//len(posts) if posts else 0}%)')
print(f'Pending enrichment: {pending}')
print(f'With local media: {with_media}')
print(f'Extracted (Whisper+OCR): {extracted}')
cols = Counter()
for p in posts:
for c in p.get('collections', []):
cols[c] += 1
print(f'\nCollections ({len(cols)}):')
for name, count in cols.most_common(15):
ext = sum(1 for p in posts if c in p.get('collections',[]) and p.get('extracted_text'))
print(f' {name}: {count}')
"If no data file exists, proceed directly to Step 2 (first-time sync). If the user only asked for status, stop here.
This fetches all saved posts directly from Instagram's API. Posts arrive fully enriched — captions, author info, media URLs, timestamps, engagement counts, and collection tags. No separate enrichment step needed.
# Sync all saved posts (with media download)
PYTHONUNBUFFERED=1 SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.api_bootstrap sync
# Or sync a specific collection only
PYTHONUNBUFFERED=1 SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.api_bootstrap sync --collection "$ARGUMENTS"
# Metadata only (skip media download for speed)
PYTHONUNBUFFERED=1 SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.api_bootstrap sync --no-mediaRun as a background task. Monitor output:
Fetched N posts (M pages)...Wait for completion. Report the summary to the user.
To list collections without syncing:
SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.api_bootstrap collectionsTo compare API vs local store:
SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.api_bootstrap statsOnly run if posts have local media but no extracted_text field. Sync with media download must complete first since extraction needs local files.
PYTHONUNBUFFERED=1 SOCMED_DATA_DIR="$PROJECT_DIR" $VENV -m socmed.platforms.instagram.media_extractor run --collection "$ARGUMENTS" --save-every 10Run as a background task. Monitor output:
A = audio+OCR, a = audio only, T = OCR only, . = no extractable contentWait for completion. Report the final summary.
Re-run the status snippet from Step 1 to confirm:
Report the final state to the user.
sessionid, csrftoken, etc. from Chrome's cookie database (via browser_cookie3). No login flow needed — if you're logged into Instagram in Chrome, it just works./api/v1/collections/list/ to get collection names, IDs, and post counts. Each collection has a numeric ID (e.g., 17879393448155930)./api/v1/feed/saved/posts/ with cursor-based pagination. Returns 21 posts per page. Each post includes a saved_collection_ids array that maps back to collection names.source: "archive+api".data/media/instagram/{username}/{shortcode}_{hash}.{ext}.extracted_text field per post.JsonStore.patch_items() with file locking. Safe to run while sync is updating.SOCMED_DATA_DIR to control where data is stored. Defaults to current working directory.The virtual environment doesn't have the bundled package installed. Run setup:
SCRIPTS_DIR=$(find ~/.claude -path '*/instagram-pipeline/scripts' -type d 2>/dev/null | head -1)
.venv/bin/pip install -e "$SCRIPTS_DIR"User needs to be logged into Instagram in Chrome. Have them open instagram.com, verify they're logged in, then retry.
Some Instagram API endpoints are strict about User-Agent. The sync endpoint (/api/v1/feed/saved/posts/) does not have this issue. If you see this, you may be calling the wrong endpoint.
A corrupted video file can hang ffmpeg. Kill the process — the pipeline resumes from the last save point (every 10 posts).
Media CDN URLs expire. Run sync again — it will re-fetch fresh URLs and download missing media files.
Grant Terminal (or your IDE) "Full Disk Access" in System Settings > Privacy & Security > Full Disk Access. Chrome's cookie database is in a protected directory.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.