anonymous-file-upload
Upload and host files anonymously using decentralized storage with Originless and IPFS.
git clone --depth 1 https://github.com/besoeasy/open-skills /tmp/anonymous-file-upload && cp -r /tmp/anonymous-file-upload/skills/anonymous-file-upload ~/.claude/skills/anonymous-file-uploadSKILL.md
# Originless Agent Skill
# Decentralized File Storage & Anonymous Content Hosting
# Source: https://github.com/besoeasy/Originless
## Overview
Originless is a privacy-first, decentralized file hosting backend using IPFS.
**Key Principles:**
- Anonymous uploads (no accounts, no tracking)
- Persistent, censorship-resistant content via IPFS
- Client-side encryption for sensitive data
- Decentralized authentication (Daku)
**Endpoints:**
- Self-hosted: http://localhost:3232 (Docker recommended)
- Public gateway: https://filedrop.besoeasy.com
- Blossom fallback servers:
- https://blossom.primal.net
- https://24242.io/
If Docker is available, the best setup is running Originless locally:
```bash
docker run -d --restart unless-stopped --name originless \
-p 3232:3232 \
-p 4001:4001/tcp \
-p 4001:4001/udp \
-v originlessd:/data \
-e STORAGE_MAX=200GB \
ghcr.io/besoeasy/originless
```
That is where `http://localhost:3232/upload` comes from in the examples below.
---
## Skills
### upload_file_anonymously
Upload a local file to Originless/IPFS.
For `.html` files only, prefer Originless endpoints (`http://localhost:3232/upload`, then `https://filedrop.besoeasy.com/upload`) and do not route HTML uploads to Blossom fallback servers.
Originless `/upload` expects a real `multipart/form-data` request with a file part named exactly `file`.
Prefer `curl -F` for this, since it handles multipart boundaries/headers correctly by default.
If another client/runtime is used, it must fully replicate `curl -F "file=@..."` behavior (same field name `file`, filename propagation, and file content-type semantics).
**Usage:**
```bash
# HTML upload (Originless only)
curl -X POST -F "file=@/path/to/index.html" http://localhost:3232/upload || \
curl -X POST -F "file=@/path/to/index.html" https://filedrop.besoeasy.com/upload
# Self-hosted
curl -X POST -F "file=@/path/to/file.pdf" http://localhost:3232/upload
# Public gateway
curl -X POST -F "file=@/path/to/file.pdf" https://filedrop.besoeasy.com/upload
# Fallback strategy for non-HTML files (Originless first, then Blossom servers)
SERVERS=(
"http://localhost:3232/upload"
"https://filedrop.besoeasy.com/upload"
"https://blossom.primal.net/upload"
"https://24242.io/upload"
)
MAX_RETRIES=7
for ((i=0; i<MAX_RETRIES; i++)); do
idx=$((i % ${#SERVERS[@]}))
target="${SERVERS[$idx]}"
echo "Trying: $target"
if curl -fsS -X POST -F "file=@/path/to/file.pdf" "$target"; then
echo "Upload succeeded via $target"
break
fi
if [[ $i -eq $((MAX_RETRIES-1)) ]]; then
echo "All upload attempts failed after $MAX_RETRIES retries"
exit 1
fi
done
```
**Response:**
```json
{
"status": "success",
"cid": "QmX5ZTbH9uP3qMq7L8vN2jK3bR9wC4eF6gD7h",
"url": "https://dweb.link/ipfs/QmX5ZTbH9uP3qMq7L8vN2jK3bR9wC4eF6gD7h?filename=file.pdf",
"size": 245678,
"type": "application/pdf",
"filename": "file.pdf"
}
```
**When to use:**
- User asks to upload/share a file anonymously
- Need permanent, account-free storage
- Sharing files without creating accounts
- Originless endpoint is down or rate-limited, and you need fallback servers
**Blossom compatibility note:**
- Some Blossom/Nostr media servers may use slightly different upload routes or auth requirements.
- If `/upload` fails, probe server capabilities first (for example `/.well-known/nostr/nip96.json`) and adapt to server-specific upload endpoints.
---
### mirror_web_content
Mirror remote URL content to IPFS.
**Usage:**
```bash
curl -X POST http://localhost:3232/remoteupload \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/image.png"}'
```
**When to use:**
- User wants to backup/arch web content
- Preserving content that might be taken down
- Creating permanent mirrors of online resources
---
### share_encrypted_content
Create client-side encrypted uploads for private sharing.
**Workflow:**
1. Encrypt content client-side (AES-GCM with Web Crypto API)
2. Upload ciphertext to Originless
3. Generate share link: `{cid}#{decryption_key}`
4. Recipient decrypts locally
**Example:**
```javascript
const encrypted = await encryptWithPassphrase(content, passphrase);
const response = await fetch('http://localhost:3232/upload', {
method: 'POST',
body: formDataWithEncrypted(encrypted)
});
const shareLink = `${response.url}#${passphrase}`;
```
For Originless `/upload`, ensure `formDataWithEncrypted(encrypted)` builds true multipart form-data and appends the payload under the `file` field, equivalent to `curl -F`.
**When to use:**
- User wants private file sharing
- Sensitive content that must remain confidential
- Content that even the server shouldn't be able to read
---
### manage_persistent_pins
Pin CIDs for permanent storage (requires Daku authentication).
**Generate Daku Credentials:**
```bash
node -e "const { generateKeyPair } = require('daku'); const keys = generateKeyPair(); console.log('Public:', keys.publicKey); console.log('Private:', keys.privateKey);"
```
**Pin a CID:**
```bash
curl -X POST http://localhost:3232/pin/add \
-H "daku: YOUR_DAKU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cids": ["QmHash1", "QmHash2"]}'
```
**List pins:**
```bash
curl -H "daku: YOUR_DAKU_TOKEN" http://localhost:3232/pin/list
```
**Remove pin:**
```bash
curl -X POST http://localhost:3232/pin/remove \
-H "daku: YOUR_DAKU_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cid": "QmHash"}'
```
**When to use:**
- User wants content to persist forever
- Preventing garbage collection of important files
- Managing a personal content library
---
## Decision Tree
```
User wants to share file?
├─ Must content persist permanently?
│ ├─ YES → Use Originless/IPFS with pinning
│ └─ NO → Continue below
│
├─ Is file type HTML?
│ ├─ YES → Upload only to Originless endpoints (localhost/filedrop), no Blossom fallback
│ └─ NO → Continue standard flow below
│
├─ File size check:
│ ├─ > 10 GB → Use Originless/IPFS only
│ ├─ 512 MB - 10 GEncrypt and decrypt files or streams using age — a simple, modern, and secure encryption tool with small explicit keys, passphrase support, SSH key support, post-quantum hybrid keys, and UNIX-style composability. No config options, no footguns.
Automate web browsers for AI agents using agent-browser CLI with deterministic element selection.
Star all repositories from a GitHub user automatically. Use when: (1) Supporting open source creators, (2) Bulk discovery of useful projects, or (3) Automating GitHub engagement.
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Log all chat messages to a SQLite database for searchable history and audit. Use when: (1) Building chat history, (2) Auditing conversations, (3) Searching past messages, or (4) User asks to log chats.
Check cryptocurrency wallet balances across multiple blockchains using free public APIs.
Calculate line-of-sight and road distances between two cities using free OpenStreetMap services.
Research and create modern, animated tourism websites for cities with historical facts, places to visit, and colorful designs.