Skip to content
Back to skills

Documentation Asset Manager

ASecurity

Manages Tallyfy documentation assets on Cloudflare R2. Uploads images, generates AI captions using Claude Code native vision, maintains CSV inventory with build-time integration. Use when managing docs screenshots or media files.

  • 666 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added February 8, 2026
documentationpythongobashgitapici/cdsecuritydocumentation

Works with

  • claude code
  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill documentation-asset-manager --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Documentation Asset Manager?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Documentation Asset Manager
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-documentation-asset-manager/badge)](https://www.skillsdirectory.com/skills/majiayu000-documentation-asset-manager)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: documentation-asset-manager
description: Manages Tallyfy documentation assets on Cloudflare R2. Uploads images, generates AI captions using Claude Code native vision, maintains CSV inventory with build-time integration. Use when managing docs screenshots or media files.
version: 2.0.0
author: Tallyfy Dev Team
tags: [documentation, assets, r2, cloudflare, inventory, ai-captions, screenshots, vision, build-integration]
dependencies: [pillow, requests]
---

# Documentation Asset Manager

## Purpose

Automates the complete workflow for Tallyfy documentation asset management with Claude Code native vision:

1. **Upload assets** to Cloudflare R2 storage (screenshots bucket)
2. **Generate AI captions** using Claude Code native vision (alt text, descriptive, SEO)
3. **Maintain CSV inventory** at `$GITHUB_ROOT/documentation/documentation_assets.csv`
4. **Build-time integration** - Automatic alt text injection during Starlight builds
5. **Return public URLs** immediately (screenshots.tallyfy.com domain)
6. **Track asset usage** across documentation files

## Recent Updates (v2.0.0)

**✅ Completed:**
- **287 images captioned** with vision-based analysis (100% coverage for native images)
- **Claude Code native** - No external API key needed
- **Build-time integration** - Remark plugin auto-injects alt text from CSV
- **Parallel Task agents** - Batch processing support
- **Path portability** - Auto-detection, works on any developer machine

## Activation Triggers

- "upload documentation asset"
- "upload screenshot to R2"
- "add image to docs"
- "manage documentation media"
- "generate image caption"
- "update documentation screenshot"
- When user provides image/asset path for documentation

## Prerequisites

**Required Credentials** (in parent directory):
- `$GITHUB_ROOT/cloudflare_credentials.json` with fields:
  - `account_id` - Cloudflare account ID
  - `api_token` - Cloudflare API token with R2 access

**Required Packages** (auto-check):
```bash
pip3 install pillow requests
```

**Claude Code Native** (Recommended):
- **No external API key needed** - Uses Claude Code's native vision capabilities
- For batch operations: Use Task agents (see Batch Vision Captioning section)
- For single images: `image_captioner.py` uses subprocess to call claude native

## Instructions

### Step 1: Validate Prerequisites

```bash
# Check credentials exist
test -f $GITHUB_ROOT/cloudflare_credentials.json || echo "❌ Credentials missing"

# Check Anthropic API key
test -f ~/.anthropic/api_key || echo "⚠️ Set ANTHROPIC_API_KEY or create ~/.anthropic/api_key"

# Check Python packages
python3 -c "import anthropic, PIL, requests" 2>/dev/null || echo "⚠️ Run: pip3 install anthropic pillow requests"
```

### Step 2: Upload Asset to R2

Use the R2 uploader script to upload any file:

```bash
# Single file upload
python3 ~/.claude/skills/documentation-asset-manager/scripts/r2_uploader.py \
    --file /path/to/screenshot.png \
    --key "tallyfy/pro/desktop-light-new-feature.png" \
    --credentials $GITHUB_ROOT/cloudflare_credentials.json

# Returns JSON with public URL:
# {
#   "success": true,
#   "url": "https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-new-feature.png",
#   "key": "tallyfy/pro/desktop-light-new-feature.png",
#   "size": "125.4KB"
# }
```

### Step 3: Generate AI Captions

Generate all three caption types using Claude Code native vision:

**For Single Images:**
```bash
# Generate captions using Claude Code native (no API key needed)
python3 ~/.claude/skills/documentation-asset-manager/scripts/image_captioner.py \
    --url "https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-new-feature.png" \
    --output /tmp/captions.json

# Returns:
# {
#   "captions": {
#     "alt_text": "Task assignment interface showing user selection dropdown",
#     "descriptive": "Tallyfy task assignment screen with dropdown menu...",
#     "seo": "Tallyfy task assignment feature showing how to assign tasks..."
#   }
# }
```

**For Batch Operations (Recommended for >10 images):**
```bash
# Use Task agents for parallel processing
# See "Batch Vision Captioning" section below
```

### Step 4: Update CSV Inventory

Add asset to master inventory CSV:

```bash
# Add to inventory
python3 ~/.claude/skills/documentation-asset-manager/scripts/asset_inventory.py \
    --action add \
    --r2-key "tallyfy/pro/desktop-light-new-feature.png" \
    --url "https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-new-feature.png" \
    --captions /tmp/captions.json \
    --article-ids "pro-tasks-assign,pro-getting-started"
```

### Step 5: Complete Workflow (Orchestrator)

For one-command complete workflow:

```bash
# Upload + Caption + Inventory in one go
python3 ~/.claude/skills/documentation-asset-manager/scripts/orchestrator.py \
    --file /path/to/screenshot.png \
    --key "tallyfy/pro/desktop-light-new-feature.png" \
    --article-ids "pro-tasks-assign" \
    --credentials $GITHUB_ROOT/cloudflare_credentials.json

# Complete output:
# ✅ Uploaded: https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-new-feature.png
# ✅ Alt text: "Task assignment interface showing user selection dropdown"
# ✅ Added to inventory: $GITHUB_ROOT/documentation/documentation_assets.csv
```

## Build-Time Integration

**Automatic Alt Text Injection:**

The master CSV is integrated with Starlight documentation builds via a remark plugin:

**Location:** `/support-docs/src/plugins/remark/inject-alt-text.ts`

**How It Works:**
1. During build, remark plugin reads `/documentation/documentation_assets.csv`
2. Matches image URLs in markdown to CSV entries
3. Auto-injects `ai_caption_alt` as alt text
4. Handles URL encoding/decoding automatically
5. Falls back gracefully if CSV unavailable

**Local Development:**
```bash
cd /support-docs
# CSV symlinked to ../documentation/documentation_assets.csv
npm run dev  # Alt text injected automatically
```

**CI/CD (Netlify):**
```bash
# package.json prebuild script copies CSV
npm run prebuild  # Copies CSV before build
npm run build     # Alt text injected during build
```

**Example:**
```markdown
<!-- Before build: -->
![](https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-tasks.png)

<!-- After build: -->
![Task list showing assignees and due dates](https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-tasks.png)
```

## Batch Vision Captioning

**For Large-Scale Caption Regeneration:**

When regenerating captions for many images (>10), use parallel Task agents for efficiency:

**Process:**
1. **Prepare images** - Download and resize to max 1800px (Claude vision constraint)
2. **Launch Task agents** - Process in parallel batches of ~48 images
3. **Consolidate results** - Merge all batch outputs
4. **Update CSV** - Apply new captions to master inventory

**Example (287 images completed in ~60 minutes):**
```bash
# See /temporary/asset-inventory/ for reference implementation:
# - prepare_images_for_vision.py (download + resize)
# - Task agents launched in parallel (6 batches of ~48 images)
# - consolidate_and_update.py (merge results → CSV)
```

**Why Task Agents:**
- Native Claude Code vision (no API keys)
- Parallel processing (6x speedup)
- Automatic retry and error handling
- Real-time progress tracking

## Workflow Patterns

### Pattern 1: Upload New Screenshot

```bash
# User: "Upload this screenshot to docs"
# Skill detects image file path, generates reasonable R2 key from filename
# Executes: upload → generate captions → update inventory → return URL
```

### Pattern 2: Replace Existing Screenshot

```bash
# User: "Replace screenshot at /tallyfy/pro/desktop-light-tasks.png"
# Skill: uploads with same key (overwrites), regenerates captions, updates inventory
```

### Pattern 3: Batch Upload

```bash
# User: "Upload all screenshots in /docs/images/"
# Skill: processes each file sequentially with delays to avoid rate limits
```

### Pattern 4: Generate Caption Only

```bash
# User: "Generate caption for existing image at https://screenshots.tallyfy.com/..."
# Skill: skips upload, generates captions using Claude Code native, updates inventory
```

### Pattern 5: Regenerate All Captions (Completed)

```bash
# All 287 native images now have vision-based captions (completed 2025-11)
# Location: /documentation/documentation_assets.csv (columns: ai_caption_alt, ai_caption_descriptive, ai_caption_seo)
# Build integration: Auto-injected during Starlight builds via remark plugin
```

## Temporary Assets

**Working Directory:** `$GITHUB_ROOT/temporary/asset-manager/`

**Files Created:**
- `upload_result.json` - R2 upload response
- `captions_alt.json` - Alt text caption
- `captions_descriptive.json` - Descriptive caption
- `captions_seo.json` - SEO caption
- `asset_metadata.json` - Combined metadata
- `processing.log` - Processing log

**Cleanup:** Temporary files auto-cleaned after successful completion

## Master Asset Inventory

**Location:** `$GITHUB_ROOT/documentation/documentation_assets.csv`

**CSV Columns:**
- `filename` - Asset filename
- `r2_key` - Full R2 bucket key
- `production_url` - Public URL (screenshots.tallyfy.com)
- `source_type` - native|orphaned|external|missing
- `file_type` - File extension
- `file_size` - Human-readable size
- `file_size_bytes` - Size in bytes
- `url_exists` - Boolean (URL accessible)
- `article_ids` - Comma-separated article IDs
- `article_count` - Number of articles referencing
- `last_modified` - R2 last modified timestamp
- `etag` - R2 ETag
- `ai_caption_alt` - Alt text caption
- `ai_caption_descriptive` - Detailed caption
- `ai_caption_seo` - SEO-optimized caption
- `needs_caption` - yes|no (based on file type)

**Auto-Update:** CSV automatically updated on any upload/delete/caption operation

## Error Handling

### Scenario 1: Credentials Missing

```
ERROR: Credentials file not found
ACTION: Check $GITHUB_ROOT/cloudflare_credentials.json exists
PROMPT: "Cannot find Cloudflare credentials. Ensure file exists with:
         - account_id
         - api_token"
```

### Scenario 2: R2 Upload Fails

```
ERROR: R2 upload failed (API error)
ACTION: Retry once after 5s, then notify user
PROMPT: "Upload to R2 failed: {error_message}
         Retrying once..."
```

### Scenario 3: Caption Generation Fails

```
ERROR: Claude API error (rate limit, network, etc)
ACTION: Complete upload, skip caption, mark for later
PROMPT: "File uploaded successfully to {url}
         Caption generation failed: {error}
         You can generate captions later with:
         python3 scripts/image_captioner.py --url {url}"
```

### Scenario 4: Rate Limit Hit

```
ERROR: Anthropic API rate limit
ACTION: Wait 60s, retry once, then defer
PROMPT: "Rate limit reached. Waiting 60s before retry...
         If persistent, use --skip-captions flag to upload without captions"
```

### Scenario 5: Inventory CSV Locked

```
ERROR: CSV file in use (another process)
ACTION: Wait 2s, retry 3 times, then warn
PROMPT: "Inventory CSV busy. Retried 3 times. Upload succeeded but inventory not updated.
         Run: python3 scripts/asset_inventory.py --sync to update manually"
```

## Advanced Usage

### Skip Caption Generation

```bash
# For quick uploads without AI captions
python3 scripts/orchestrator.py --file screenshot.png --skip-captions
```

### Regenerate Captions for Existing Assets

```bash
# Regenerate all captions for specific asset
python3 scripts/image_captioner.py \
    --url "https://screenshots.tallyfy.com/tallyfy/pro/desktop-light-tasks.png" \
    --update-inventory
```

### Bulk Operations

```bash
# Process all images in directory
for img in /docs/screenshots/*.png; do
    python3 scripts/orchestrator.py --file "$img" --batch-mode
    sleep 3  # Delay between uploads
done
```

### Verify Inventory Integrity

```bash
# Check all URLs in inventory are accessible
python3 scripts/asset_inventory.py --verify-urls
```

### Generate Statistics

```bash
# Get inventory statistics
python3 scripts/asset_inventory.py --stats

# Output:
# Total assets: 812
# Active (used in docs): 290
# Orphaned (not referenced): 499
# Missing (404s): 23
# Images with captions: 288
```

## R2 Bucket Configuration

**Bucket Name:** `screenshots`
**Account ID:** `ac9046789c9ad74c8704a143b442f918`
**Public Domain:** `screenshots.tallyfy.com`
**API Endpoint:** `https://api.cloudflare.com/client/v4/accounts/{account_id}/r2/buckets/screenshots/objects`
**CDN:** Cloudflare global edge cache

## Naming Conventions

**Recommended R2 Key Patterns:**

1. **Structured (Preferred):**
   ```
   tallyfy/pro/desktop-light-{action}-{context}.png
   tallyfy/pro/mobile-dark-{feature}.png
   manufactory/{feature}-{version}.png
   ```

2. **Legacy (Auto-generated):**
   ```
   file-{random_id}.png
   ```

**Examples:**
- `tallyfy/pro/desktop-light-assign-task.png`
- `tallyfy/pro/desktop-light-sidebar-numerated.png`
- `manufactory-triggers-v2.png`

## Security Notes

- Credentials stored in parent directory (not in skill)
- No API keys embedded in skill files
- Anthropic API key from environment or user's ~/.anthropic/
- R2 bucket is private with public domain mapping
- All uploads go through Cloudflare API authentication

## Troubleshooting

**"Module not found" errors:**
```bash
pip3 install pillow requests
```

**"Credentials not found":**
```bash
cat $GITHUB_ROOT/cloudflare_credentials.json
# Should show account_id and api_token
```

**"Claude Code not available":**
```bash
# Ensure Claude Code CLI is installed and accessible
which claude  # Should return path to claude executable
```

**For external API usage (legacy):**
```bash
# Not recommended - use Claude Code native instead
export ANTHROPIC_API_KEY="your-api-key-here"
```

**"R2 upload succeeds but URL 404":**
- Check bucket name is "screenshots"
- Verify custom domain screenshots.tallyfy.com is configured
- Wait 30-60s for CDN cache

**"CSV inventory out of sync":**
```bash
# Rebuild inventory from R2 + documentation
python3 scripts/asset_inventory.py --rebuild
```

## See Also

- `references/r2_api_reference.md` - Complete Cloudflare R2 API docs
- `references/supported_formats.md` - Supported file types and limits
- `references/examples.md` - Usage examples and tutorials
- `$GITHUB_ROOT/documentation/CLAUDE.md` - Documentation repo guidelines

## Maintenance

**Regular Tasks:**
1. Weekly: Verify inventory CSV integrity
2. Monthly: Review orphaned assets (consider cleanup)
3. Quarterly: Check for missing images (404s) and fix
4. As needed: Regenerate captions for improved quality

**Inventory Location:**
- Primary: `$GITHUB_ROOT/documentation/documentation_assets.csv` (version controlled)
- Working Directory: `$GITHUB_ROOT/temporary/asset-inventory/asset_inventory_master.csv` (generated master)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.