| name | cloud-uploader |
| description | Uploads promo videos and content to Cloudflare R2 or AWS S3. Use when the user wants to host promo content for social media or distribution. |
| model | sonnet |
| effort | low |
| prerequisites | ["promo-director"] |
| allowed-tools | ["Read","Bash","Glob"] |
| requirements | {"python":["boto3"]} |
Cloud Uploader Skill
Upload promo videos and other album content to cloud storage (Cloudflare R2 or AWS S3).
Purpose
After generating promo videos with /bitwize-music:promo-director, upload them to cloud storage for:
- Hosting on websites
- Sharing via direct links
- CDN distribution
- Backup and archival
When to Use
- After promo videos generated, user wants to upload to cloud
- User says "upload promos to R2" or "upload to S3"
- User says "upload promo videos for [album]"
- Manual invocation only (not automatic)
Position in Workflow
Generate ā Master ā Promo Videos ā **[Cloud Upload]** ā Release
Optional step after promo-director, before release-director.
Prerequisites
Cloud Configuration
Cloud credentials must be configured in ~/.bitwize-music/config.yaml:
cloud:
enabled: true
provider: "r2"
r2:
account_id: "your-account-id"
access_key_id: "your-access-key"
secret_access_key: "your-secret-key"
bucket: "promo-videos"
s3:
region: "us-west-2"
access_key_id: "your-access-key"
secret_access_key: "your-secret-key"
bucket: "promo-videos"
See ${CLAUDE_PLUGIN_ROOT}/reference/cloud/setup-guide.md for detailed setup instructions.
Required Files
- Promo videos generated (run
/bitwize-music:promo-director first)
- Located at:
{audio_root}/artists/{artist}/albums/{genre}/{album}/promo_videos/
- Album sampler at:
{audio_root}/artists/{artist}/albums/{genre}/{album}/album_sampler.mp4
Python Dependencies
~/.bitwize-music/venv/bin/pip install -r ${CLAUDE_PLUGIN_ROOT}/requirements.txt
pip install boto3
The upload script uses ~/.bitwize-music/venv if available, otherwise falls back to system Python.
Workflow
1. Verify Prerequisites
Check config:
cat ~/.bitwize-music/config.yaml | grep -A 20 "cloud:"
Verify:
cloud.enabled: true
- Provider credentials configured (r2 or s3)
- Bucket name set
Check promo videos exist:
ls {audio_root}/artists/{artist}/albums/{genre}/{album}/promo_videos/
ls {audio_root}/artists/{artist}/albums/{genre}/{album}/album_sampler.mp4
If missing:
Error: Promo videos not found.
Generate with: /bitwize-music:promo-director {album}
2. Get Python Command
Call get_python_command() first to get the venv Python path and plugin root. Use these for all bash invocations below.
PYTHON="{python from get_python_command}"
PLUGIN_DIR="{plugin_root from get_python_command}"
3. Preview Upload (Dry Run)
Preview first:
$PYTHON "$PLUGIN_DIR/tools/cloud/upload_to_cloud.py" {album} --dry-run
Output shows:
- Provider and bucket
- Files to upload
- S3 keys (paths in bucket)
- File sizes
4. Upload Files
Upload all (promos + sampler):
$PYTHON "$PLUGIN_DIR/tools/cloud/upload_to_cloud.py" {album}
Upload only track promos:
$PYTHON "$PLUGIN_DIR/tools/cloud/upload_to_cloud.py" {album} --type promos
Upload only album sampler:
$PYTHON "$PLUGIN_DIR/tools/cloud/upload_to_cloud.py" {album} --type sampler
Upload with public access:
$PYTHON "$PLUGIN_DIR/tools/cloud/upload_to_cloud.py" {album} --public
5. Verify Upload
For R2:
- Check Cloudflare dashboard ā R2 ā Your bucket
- Files should appear under
{artist}/{album}/
For S3:
- Check AWS Console ā S3 ā Your bucket
- Or use AWS CLI:
aws s3 ls s3://{bucket}/{artist}/{album}/
5. Report Results
## Cloud Upload Complete
**Provider:** R2 (or S3)
**Bucket:** {bucket}
**Album:** {album}
**Uploaded Files:**
- {artist}/{album}/promos/01-track_promo.mp4
- {artist}/{album}/promos/02-track_promo.mp4
- ...
- {artist}/{album}/promos/album_sampler.mp4
**Total:** 11 files, 125.4 MB
**Next Steps:**
1. Verify files in cloud dashboard
2. If public: Test URLs work
3. Continue to release: /bitwize-music:release-director {album}
Upload Path Structure
IMPORTANT: Cloud paths are FLAT - no genre folder.
The cloud path structure is different from the local content structure:
| Location | Path Structure |
|---|
| Local content | {content_root}/artists/{artist}/albums/{genre}/{album}/ |
| Local audio | {audio_root}/artists/{artist}/albums/{genre}/{album}/ |
| Cloud | {artist}/{album}/ (no genre!) |
Files are organized in the bucket as:
{bucket}/
āāā {artist}/
āāā {album}/
āāā promos/
āāā 01-track_promo.mp4
āāā 02-track_promo.mp4
āāā ...
āāā album_sampler.mp4
Example for album "my-album" by "bitwize" in rock genre:
- Local:
~/music/artists/bitwize/albums/rock/my-album/
- Cloud:
bitwize/my-album/promos/ (NOT bitwize/albums/rock/my-album/)
Command Options
| Option | Description |
|---|
--type promos | Upload only track promo videos |
--type sampler | Upload only album sampler |
--type all | Upload both (default) |
--dry-run | Preview without uploading |
--public | Set files as public-read |
--audio-root PATH | Override audio_root from config |
Invocation Examples
Basic upload:
/bitwize-music:cloud-uploader my-album
Preview only:
/bitwize-music:cloud-uploader my-album --dry-run
Upload promos only:
/bitwize-music:cloud-uploader my-album --type promos
Upload with public access:
/bitwize-music:cloud-uploader my-album --public
Error Handling
"Cloud uploads not enabled"
- Add
cloud.enabled: true to config
- See
${CLAUDE_PLUGIN_ROOT}/reference/cloud/setup-guide.md
"Credentials not configured"
- Add credentials to config file
- For R2: account_id, access_key_id, secret_access_key
- For S3: access_key_id, secret_access_key
"Album not found"
- Check album exists in
{audio_root}/artists/{artist}/albums/{genre}/{album}/
- Verify artist name in config matches
"No files found to upload"
- Generate promo videos first:
/bitwize-music:promo-director {album}
"Access Denied"
- Check credentials are correct
- For R2: Verify API token has write permissions
- For S3: Verify IAM policy allows s3:PutObject
"Bucket not found"
- Create bucket first in cloud dashboard
- Verify bucket name in config
Security Notes
- Credentials stored in config file (ensure proper file permissions)
- Config file should be gitignored in user's content repo
- Default: Files uploaded as private (not public)
- Use
--public flag only for files intended for public access
- Consider using environment variables for CI/CD (future enhancement)
Integration with Other Skills
Handoff FROM
promo-director:
After promo generation:
Promo videos generated successfully.
**Optional:** Upload to cloud storage: /bitwize-music:cloud-uploader {album}
Handoff TO
release-director:
After cloud upload:
Cloud upload complete.
Ready for release workflow: /bitwize-music:release-director {album}
Supported Providers
Cloudflare R2
- S3-compatible API
- No egress fees
- Global CDN integration
- Good for high-traffic content
AWS S3
- Industry standard
- Fine-grained IAM permissions
- CloudFront CDN available
- Good for AWS ecosystem integration
Future Enhancements
- Environment variable credentials (for CI/CD)
- Multiple bucket support
- Automatic CDN invalidation
- Progress bar for large uploads
- Resume failed uploads
- Bucket creation if missing
- Additional providers (Backblaze B2, DigitalOcean Spaces)
Related Documentation
${CLAUDE_PLUGIN_ROOT}/reference/cloud/setup-guide.md - Detailed setup instructions
${CLAUDE_PLUGIN_ROOT}/skills/promo-director/SKILL.md - Generate promo videos
${CLAUDE_PLUGIN_ROOT}/skills/release-director/SKILL.md - Release workflow
Model Recommendation
Sonnet 4.5 - This skill runs scripts and coordinates workflow. No creative output from LLM.
Version History
- v0.14.0 - Initial implementation
- R2 and S3 support via boto3
- Dry-run mode
- Public/private upload options
- Path organization by artist/album