f2u-cli
v0.2.0
Published
CLI tool for AI agents to upload temporary files to Cloudflare R2
Downloads
601
Readme
f2u — File-to-URL for AI Agents
Temporary file hosting on Cloudflare R2. Upload a file, get a URL, it auto-expires.
Why? MCP servers cannot handle file uploads. When AI agents need to share a file (screenshot, image, document) as a URL, f2u provides instant upload → URL conversion with automatic cleanup.
Designed for AI agents — all output is JSON, no human formatting.
Install
# From npm (recommended)
npm install -g f2u-cli
# Or with pnpm
pnpm add -g f2u-cli
# Or with yarn
yarn global add f2u-cli
# Verify installation
f2u --versionQuick Start
# 1. Configure (one-time)
f2u auth --endpoint https://f2u.goclaw.sh --key YOUR_API_KEY
# 2. Upload a file (default TTL: 5 minutes)
f2u up -f ./screenshot.png
# → {"id":"abc-123","url":"https://f2u.goclaw.sh/abc-123/screenshot.png","expires_at":"..."}
# 3. Upload with custom TTL
f2u up -f ./report.pdf -t 1h
# 4. Check your uploads
f2u ls
# 5. Get file details
f2u info abc-123
# 6. Delete a file early
f2u rm abc-123
# 7. Check storage usage
f2u usageCLI Commands
All commands output JSON to stdout. Errors go to stderr as JSON with non-zero exit code.
f2u auth — Configure credentials
f2u auth --endpoint https://f2u.goclaw.sh --key YOUR_API_KEY
# → {"success":true,"endpoint":"https://f2u.goclaw.sh","message":"Configuration saved."}Config saved to ~/.config/f2u/config.json (permissions: 0600).
f2u up — Upload a file
f2u up -f ./image.png # Default TTL: 5 minutes
f2u up -f ./video.mp4 -t 1h # Custom TTL: 1 hour
f2u up -f ./document.pdf -t 24h # Max TTL: 24 hoursResponse:
{
"id": "62b1bf4e-fd92-46be-8f57-ed73fd58588d",
"filename": "image.png",
"url": "https://f2u.goclaw.sh/62b1bf4e-fd92-46be-8f57-ed73fd58588d/image.png",
"size": 280591,
"content_type": "image/png",
"ttl": "5m",
"ttl_seconds": 300,
"expires_at": "2026-04-07T13:10:00.000Z",
"created_at": "2026-04-07T13:05:00.000Z"
}f2u ls — List active files
f2u ls
# → {"files":[...],"count":3}f2u info <id> — File details + TTL remaining
f2u info 62b1bf4e-fd92-46be-8f57-ed73fd58588d
# → {"id":"...","ttl_remaining":221,"expired":false,...}f2u rm <id> — Delete a file
f2u rm 62b1bf4e-fd92-46be-8f57-ed73fd58588d
# → {"id":"...","deleted":true}f2u usage — Storage stats
f2u usage
# → {"active":{"count":3,"bytes":561197},"all_time":{"count":10,"bytes":1234567}}TTL Options
| Value | Duration |
|-------|----------|
| 5m | 5 minutes (default) |
| 15m | 15 minutes |
| 30m | 30 minutes |
| 1h | 1 hour |
| 6h | 6 hours |
| 12h | 12 hours |
| 24h | 24 hours (maximum) |
Files are automatically deleted after TTL expires. The cron cleanup runs every minute.
Supported File Types
Auto-detected MIME types for proper browser preview:
| Category | Extensions | |----------|-----------| | Images | jpg, jpeg, png, gif, webp, svg | | Documents | pdf, json, txt, html, css, js, ts, csv, xml, md, yaml | | Audio | mp3, wav, ogg, flac, aac, m4a, wma, opus | | Video | mp4, webm, avi, mov, mkv, flv, wmv, m4v, 3gp | | Archives | zip, gz, tar |
Other file types default to application/octet-stream.
Environment Variables
Credentials are resolved per-field with the following precedence (high → low):
process.env— OS-level, shell-exported, or inline (F2U_API_KEY=… f2u up …).env.localin current working directory.env.${NODE_ENV}in current working directory (e.g..env.production).envin current working directory~/.config/f2u/config.json(saved viaf2u auth)
Partial overrides are allowed — e.g. set F2U_ENDPOINT via env while keeping F2U_API_KEY in the config file.
# Inline (CI/CD)
F2U_ENDPOINT=https://f2u.goclaw.sh F2U_API_KEY=sk_xxx f2u up -f ./file.png
# Shell export
export F2U_API_KEY=sk_xxx
f2u up -f ./file.png
# Project-local .env file (auto-loaded from CWD)
echo "F2U_API_KEY=sk_xxx" >> .env.local
f2u up -f ./file.png| Variable | Description |
|----------|-------------|
| F2U_ENDPOINT | Worker API URL |
| F2U_API_KEY | API authentication key |
API Reference
Base URL: https://f2u.goclaw.sh
All protected endpoints require Authorization: Bearer <API_KEY> header.
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| POST | /upload | Bearer | Upload file (multipart: file + ttl) |
| GET | /:id/:filename | Public | Serve file (410 if expired) |
| GET | /files | Bearer | List active files |
| GET | /info/:id | Bearer | File details + TTL remaining |
| DELETE | /:id | Bearer | Delete file |
| GET | /usage | Bearer | Storage stats |
| GET | /health | Public | Health check |
Upload via curl
curl -X POST https://f2u.goclaw.sh/upload \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@./image.png" \
-F "ttl=5m"Serve file (public — no auth needed)
curl https://f2u.goclaw.sh/62b1bf4e-fd92-46be-8f57-ed73fd58588d/image.png
# Or just open the URL in a browserArchitecture
┌─────────┐ POST /upload ┌──────────────────────┐
│ f2u │ ──────────────────→ │ Cloudflare Worker │
│ CLI │ │ (Hono) │
│ │ ←───── JSON ────── │ │
└─────────┘ │ ┌────────┐ ┌──────┐ │
│ │ R2 │ │ D1 │ │
Browser/Agent ── GET /:id/:fn ──→ │ │ files │ │ db │ │
←── file bytes ──── │ └────────┘ └──────┘ │
│ │
│ Cron (every 1 min): │
│ cleanup expired files │
└──────────────────────┘| Component | Role |
|-----------|------|
| R2 | File storage (auto-cleaned by cron) |
| D1 | SQLite database for file metadata + expiry tracking |
| Worker | API handler + scheduled cron cleanup |
| Domain | f2u.goclaw.sh (custom domain on Cloudflare) |
Self-Hosting
Prerequisites
- Cloudflare account (free tier works) with R2 + D1 enabled
- Wrangler CLI (
npm install -g wrangler) - Node.js 18+
- pnpm
Setup
# Clone and install
git clone https://github.com/nextlevelbuilder/f2u-cli.git
cd f2u-cli
pnpm install
# Create R2 bucket
wrangler r2 bucket create f2u-files
# Create D1 database
wrangler d1 create f2u-db
# Copy the database_id from output into packages/worker/wrangler.toml
# Apply database schema
cd packages/worker
wrangler d1 execute f2u-db --file=src/db/schema.sql --remote
# Set API key secret (enter your chosen key when prompted)
wrangler secret put API_KEY
# Update custom domain in wrangler.toml (optional)
# Edit [[routes]] pattern to your domain
# Deploy
wrangler deploy
# Verify
curl https://your-domain.com/healthCustom Domain
- Your domain must be on Cloudflare DNS (proxied)
- Edit
packages/worker/wrangler.toml:[[routes]] pattern = "your-domain.com" custom_domain = true - Redeploy:
wrangler deploy
Development
pnpm install # Install all dependencies
pnpm dev:worker # Start Worker locally (wrangler dev)
pnpm dev:cli # Run CLI in dev mode (tsx)
pnpm build # Build all packages
pnpm build:cli # Build CLI only
pnpm build:worker # Build Worker only
pnpm deploy # Deploy Worker to CloudflareLimits
| Limit | Value | |-------|-------| | Max file size | 100 MB (Workers memory constraint) | | Max TTL | 24 hours | | Default TTL | 5 minutes | | Cleanup interval | 1 minute | | List limit | 100 files per request |
License
MIT
