Repository
f2u-cli
Temporary file hosting CLI for AI agents — upload to Cloudflare R2, get a URL, auto-expires
- Value
- Duration
- 5m
- 5 minutes (default)
- 15m
- 15 minutes
- 30m
- 30 minutes
Specs
- ValueDuration
- 5m5 minutes (default)
- 15m15 minutes
- 30m30 minutes
- 1h1 hour
- 6h6 hours
- 12h12 hours
- 24h24 hours (maximum)
- CategoryExtensions
- ImagesImages
- DocumentsDocuments
- AudioAudio
- VideoVideo
- ArchivesArchives
- VariableDescription
- F2U_ENDPOINTWorker API URL
- F2U_API_KEYAPI authentication key
- MethodPath
- POST/upload
- GET/files
- GET/info/:id
- DELETE/:id
- GET/usage
- ComponentRole
- R2R2
- D1D1
- WorkerWorker
- DomainDomain
- LimitValue
- Max file size100 MB (Workers memory constraint)
- Max TTL24 hours
- Default TTL5 minutes
- Cleanup interval1 minute
- List limit100 files per request
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 --version
Quick 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 usage
CLI 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 hours
Response:
{
"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 browser
Architecture
┌─────────┐ 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/health
Custom 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 Cloudflare
Limits
| 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
Install
1
-
# 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 --version
Quick Start
1
-
# 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 usage
CLI Commands
1
-
All commands output JSON to stdout. Errors go to stderr as JSON with non-zero exit code.
f2u auth — Configure credentials
1
-
f2u auth --endpoint https://f2u.goclaw.sh --key YOUR_API_KEY # → {"success":true,"endpoint":"https://f2u.goclaw.sh","message":"Configuration saved."}
f2u up — Upload a file
1
-
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 hours
f2u ls — List active files
1
-
f2u ls # → {"files":[...],"count":3}
f2u info <id> — File details + TTL remaining
1
-
f2u info 62b1bf4e-fd92-46be-8f57-ed73fd58588d # → {"id":"...","ttl_remaining":221,"expired":false,...}
f2u rm <id> — Delete a file
1
-
f2u rm 62b1bf4e-fd92-46be-8f57-ed73fd58588d # → {"id":"...","deleted":true}
f2u usage — Storage stats
1
-
f2u usage # → {"active":{"count":3,"bytes":561197},"all_time":{"count":10,"bytes":1234567}}
TTL Options
1
-
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)
Supported File Types
1
-
Auto-detected MIME types for proper browser preview:
Environment Variables
1
-
Credentials are resolved per-field with the following precedence (high → low):
API Reference
1
-
Base URL: https://f2u.goclaw.sh
Upload via curl
1
-
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)
1
-
curl https://f2u.goclaw.sh/62b1bf4e-fd92-46be-8f57-ed73fd58588d/image.png # Or just open the URL in a browser
Architecture
1
-
┌─────────┐ 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 │ └──────────────────────┘
Prerequisites
1
Setup
1
-
# 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/health
Custom Domain
1
-
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
1
-
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 Cloudflare
Limits
1
-
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
1
-
MIT