documentation-asset-manager
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.
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
Documentation Asset Manager
Purpose
Automates the complete workflow for Tallyfy documentation asset management with Claude Code native vision:
- Upload assets to Cloudflare R2 storage (screenshots bucket)
- Generate AI captions using Claude Code native vision (alt text, descriptive, SEO)
-
Maintain CSV inventory at
$GITHUB_ROOT/documentation/documentation_assets.csv - Build-time integration - Automatic alt text injection during Starlight builds
- Return public URLs immediately (screenshots.tallyfy.com domain)
- 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.jsonwith fields:-
account_id- Cloudflare account ID -
api_token- Cloudflare API token with R2 access
-
Required Packages (auto-check):
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.pyuses subprocess to call claude native
Instructions
Step 1: Validate Prerequisites
# 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:
# 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:
# 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):
# Use Task agents for parallel processing
# See "Batch Vision Captioning" section below
Step 4: Update CSV Inventory
Add asset to master inventory CSV:
# 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:
# 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:
- During build, remark plugin reads
/documentation/documentation_assets.csv - Matches image URLs in markdown to CSV entries
- Auto-injects
ai_caption_altas alt text - Handles URL encoding/decoding automatically
- Falls back gracefully if CSV unavailable
Local Development:
cd /support-docs
# CSV symlinked to ../documentation/documentation_assets.csv
npm run dev # Alt text injected automatically
CI/CD (Netlify):
# package.json prebuild script copies CSV
npm run prebuild # Copies CSV before build
npm run build # Alt text injected during build
Example:
<!-- Before build: -->

<!-- After build: -->

Batch Vision Captioning
For Large-Scale Caption Regeneration:
When regenerating captions for many images (>10), use parallel Task agents for efficiency:
Process:
- Prepare images - Download and resize to max 1800px (Claude vision constraint)
- Launch Task agents - Process in parallel batches of ~48 images
- Consolidate results - Merge all batch outputs
- Update CSV - Apply new captions to master inventory
Example (287 images completed in ~60 minutes):
# 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
# 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
# User: "Replace screenshot at /tallyfy/pro/desktop-light-tasks.png"
# Skill: uploads with same key (overwrites), regenerates captions, updates inventory
Pattern 3: Batch Upload
# User: "Upload all screenshots in /docs/images/"
# Skill: processes each file sequentially with delays to avoid rate limits
Pattern 4: Generate Caption Only
# 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)
# 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
# For quick uploads without AI captions
python3 scripts/orchestrator.py --file screenshot.png --skip-captions
Regenerate Captions for Existing Assets
# 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
# 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
# Check all URLs in inventory are accessible
python3 scripts/asset_inventory.py --verify-urls
Generate Statistics
# 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:
-
Structured (Preferred):
tallyfy/pro/desktop-light-{action}-{context}.png tallyfy/pro/mobile-dark-{feature}.png manufactory/{feature}-{version}.png -
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:
pip3 install pillow requests
"Credentials not found":
cat $GITHUB_ROOT/cloudflare_credentials.json
# Should show account_id and api_token
"Claude Code not available":
# Ensure Claude Code CLI is installed and accessible
which claude # Should return path to claude executable
For external API usage (legacy):
# 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":
# 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:
- Weekly: Verify inventory CSV integrity
- Monthly: Review orphaned assets (consider cleanup)
- Quarterly: Check for missing images (404s) and fix
- 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)
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!