Setup Guide: Upload to Spaces Skill
This is part of my Postbox workflow — when I’m writing and need to include a screenshot, I don’t want to leave the terminal. Open a browser, upload somewhere, copy a URL, paste it back… that breaks the flow.
So I made a small skill that uploads a file to DigitalOcean Spaces and gives me a public URL I can drop straight into Markdown. Upload, get link, keep writing.
This guide covers the technical setup: configuring s3cmd and creating the Claude Code skill.
What follows is the step-by-step setup.
Quick note on commands, skills, and MCP
When I started setting this up, Claude called these commands. Since then, it looks like commands have been folded into skills in Claude Code. I wrote more about creating these in Creating Reusable Prompts in Claude.
I’m still trying to figure out the practical difference between skills and MCP servers, and where each one really shines. That mental model is still forming for me. (I touch on how I use MCP servers in My current coding workflow.)
For now, this upload flow works well as a skill, so that’s what I went with.
Part 1: Install and Configure s3cmd
s3cmd is a lightweight CLI for interacting with S3-compatible storage, which includes DigitalOcean Spaces.
Step 1: Install s3cmd
On macOS:
brew install s3cmd
Verify it’s installed:
s3cmd --version
Step 2: Get Your Spaces Credentials
- Go to DigitalOcean Control Panel → API → Spaces Keys
- Click Generate New Key
- Copy both the Access Key and Secret Key
You can scope the key to:
- All Spaces, or
- A specific bucket (recommended)
Both options work for this setup.
Step 3: Configure s3cmd
Run the interactive configuration wizard:
s3cmd --configure
Example values for a bucket in nyc3 (adjust if you’re using another region):
| Prompt | What to Enter |
|---|---|
| Access Key | <your-spaces-access-key> |
| Secret Key | <your-spaces-secret-key> |
| Default Region | nyc3 |
| S3 Endpoint | nyc3.digitaloceanspaces.com |
| DNS-style bucket+hostname | %(bucket)s.nyc3.digitaloceanspaces.com |
| Encryption password | Leave blank |
| Path to GPG program | Leave blank |
| Use HTTPS protocol | Yes |
| HTTP Proxy server name | Leave blank |
Save the configuration when prompted.
Step 4: Test the Configuration (Important Gotcha)
During setup, s3cmd will try to list all buckets in your account. If your key is scoped to a specific bucket, you’ll likely see:
ERROR: Test failed: 403 (AccessDenied): Access Denied.
ERROR: Are you sure your keys have s3:ListAllMyBuckets permissions?
This is expected.
Scoped keys can’t list all buckets, but they can still access the bucket you allowed. Save the configuration anyway.
Step 5: Verify Access to Your Bucket
Test access directly against your bucket:
s3cmd ls s3://postbox/
If this works, your Spaces setup is complete.
Part 2: Create the Claude Code Skill
Now we wire this into Claude Code so uploads feel like a single command.
Step 1: Create the Command File
Create a new file:
~/.claude/commands/upload-to-spaces.md
Add the following content:
# Upload to Spaces
Upload a file to DigitalOcean Spaces and return the public URL.
## Arguments
$ARGUMENTS
## Instructions
1. Parse the arguments to find the file path to upload
2. Verify the file exists
3. Generate a unique filename by prepending a short UUID (8 chars) to the original filename
4. Upload the file using:
s3cmd put "<filepath>" "s3://postbox/<unique-filename>" -P
5. Construct and return the public URL:
https://postbox.nyc3.digitaloceanspaces.com/<unique-filename>
6. Display the URL prominently so it can be copied
Notes:
- The
-Pflag makes the file publicly accessible - The UUID prefix avoids filename collisions
- Adjust the bucket name and region to match your setup
Step 2: Use the Skill
In Claude Code, you can now run:
/upload-to-spaces /path/to/image.png
Or describe it naturally:
upload this screenshot to spaces: ~/Desktop/screenshot.png
Claude will upload the file and return the public URL, ready to paste into Markdown.
Configuration Reference
Example setup used in this guide:
- Bucket:
postbox - Region:
nyc3 - Endpoint:
nyc3.digitaloceanspaces.com - Public URL format:
https://postbox.nyc3.digitaloceanspaces.com/<filename>
Useful s3cmd Commands
# List files in a bucket
s3cmd ls s3://postbox/
# Upload a file (public)
s3cmd put myfile.png s3://postbox/ -P
# Upload with a custom name
s3cmd put myfile.png s3://postbox/custom-name.png -P
# Delete a file
s3cmd del s3://postbox/filename.png
# Inspect a file
s3cmd info s3://postbox/filename.png
That’s it.
You now have a small, reusable building block: upload a file from Claude and immediately get a public URL, without leaving the flow you’re already in.