pinme-share
Upload any file or directory to PinMe (public IPFS) and get back a short
*.pinit.eth.limo URL.
- Version: 1.0.1
- License: MIT
- Author: Evan Song · github.com/Songhonglei
- Repository: https://github.com/Songhonglei/html-tool-suite
⚠️ Public-data warning — read before first use
- PinMe runs on public IPFS: anything you upload is world-readable; anyone with the URL can open it.
- CIDs are effectively undeletable: IPFS nodes cache content;
--rmonly removes the pin from your account — third-party copies may still exist. - 🚫 Never upload: internal company docs / client data / credentials / private info / unreleased material.
- Every
uploadinvocation prints a warning to stderr; pass--yesto skip it in automation.
🔑 First-time setup — configure your AppKey
PinMe v2.x requires authentication. The lookup order is:
PINME_APPKEYenv variable (highest priority, doesn't persist — good for CI / one-shot)pinmeCLI already has an AppKey set → reuse directly- Local file
~/.local/share/pinme-share/appkey.jsonexists → auto-applied topinmeCLI - Otherwise → script returns
error_type: auth_requiredand tells the user to grab an AppKey from https://pinme.eth.limo
Configure / replace the AppKey (persistent)
python3 scripts/upload_to_pinme.py --set-appkey <YOUR_KEY>
Writes the key to both the pinme CLI and ~/.local/share/pinme-share/appkey.json (mode 0600).
The local file is never committed to git or shipped in the published skill bundle.
Override the storage path (advanced)
export PINME_APPKEY_FILE=/custom/path/appkey.json
# or honour $XDG_DATA_HOME automatically:
export XDG_DATA_HOME=$HOME/my-xdg-data # → $HOME/my-xdg-data/pinme-share/appkey.json
Inspect current configuration
python3 scripts/upload_to_pinme.py --show-appkey
📤 Upload
# Any single file
python3 scripts/upload_to_pinme.py /path/to/file.html
python3 scripts/upload_to_pinme.py /path/to/report.pdf
# A whole directory (no index.html required)
python3 scripts/upload_to_pinme.py /path/to/dist/
# Add --verbose to see progress for large files
python3 scripts/upload_to_pinme.py /path/to/video.mp4 --verbose
# Skip the privacy warning (for cron / automated pipelines)
python3 scripts/upload_to_pinme.py /path/to/file.html --yes
# Custom timeout (default: 60s + 2s/MB, floor 180s, ceiling 1800s)
python3 scripts/upload_to_pinme.py /path/to/big.zip --timeout 900
Output — the last line of stdout is always a single JSON object:
{"success": true, "url": "https://xxxx.pinit.eth.limo", "size_bytes": 12345, "timeout_used": 180}
📜 Browse upload history
python3 scripts/upload_to_pinme.py --list
python3 scripts/upload_to_pinme.py --list --limit 5
python3 scripts/upload_to_pinme.py --list --raw # don't parse; return raw CLI text
Structured output:
{"success": true, "count": 3, "history": [
{"name": "foo.html", "cid": "Qm...", "url": "https://xxxx.pinit.eth.limo", "size": "12 KB", "time": "2026-05-21 09:30"}
]}
🗑️ Unpin (remove from your pin list)
python3 scripts/upload_to_pinme.py --rm <CID>
⚠️ Public IPFS copies cannot be truly deleted; this only removes the pin from your account.
💰 Wallet / quota
python3 scripts/upload_to_pinme.py --wallet
PinMe provides a free quota (~500 uploads). Past that it may charge — see https://pinme.eth.limo console.
🚪 Logout
python3 scripts/upload_to_pinme.py --logout
Clears both the pinme CLI session and ~/.local/share/pinme-share/appkey.json.
🧰 stdout / stderr contract
| Stream | Purpose |
|---|---|
| stdout | Always exactly one JSON object on the final line — safe to pipe into jq |
| stderr | Progress lines, privacy warnings, debug output — never breaks JSON parsing |
Example:
URL=$(python3 scripts/upload_to_pinme.py /tmp/foo.html | jq -r '.url')
📋 Error code reference (for agent routing)
error_type |
Trigger | Suggested handling |
|---|---|---|
auth_required |
AppKey missing / pinme reports login failure | Prompt user to run --set-appkey or grab an AppKey |
invalid_path |
Path missing / unreadable | Ask user to confirm the path |
oversize |
Single file > 200 MB or directory > 1 GB | Split or use different storage |
cli_missing |
pinme CLI install failed / not found |
Check Node.js / network / npm permissions |
network |
Timeout / DNS failure / connection refused / 5xx | Retry or verify outbound connectivity |
quota_exceeded |
PinMe quota / wallet empty | Top up via PinMe console or switch account |
url_not_found |
Upload OK but no parseable URL | Inspect raw output (CLI format may have changed) |
usage |
No operation specified | Show --help and ask the user what they want to do |
invalid_appkey |
AppKey passed to --set-appkey looks malformed (length < 20) |
Ask user to recheck and re-enter |
conflicting_args |
Multiple mutually-exclusive operations passed at once (e.g. path + --list) | Call them separately, one operation per invocation |
unknown |
Fallback | error field includes raw stderr |
Exit codes: 0 success / 1 generic failure / 2 structured failure (read JSON error_type).
📦 Constraints & dependencies
- Single file ≤ 200 MB, directory ≤ 1 GB (PinMe server limit)
- Static files only (no server-side processing)
- Node.js ≥ 16.13.0 (auto-checked)
pinmeCLI (auto-installed vianpm install -g pinmeif missing)- PinMe AppKey (required)
🛠️ Pasted-content workflow
If the user pastes HTML content directly into chat, the agent should:
- Write it to
/tmp/pinme_user_<timestamp>.html - Invoke this script with that path
- Return the resulting URL
🔧 Environment variables
| Variable | Purpose | Example |
|---|---|---|
PINME_APPKEY |
One-shot / CI override (highest priority, no persist) | export PINME_APPKEY=abc123... |
PINME_APPKEY_FILE |
Override AppKey storage path | export PINME_APPKEY_FILE=$HOME/.config/pinme/key.json |
XDG_DATA_HOME |
Honoured for default storage path | export XDG_DATA_HOME=$HOME/my-xdg-data |
Default storage: ${XDG_DATA_HOME:-$HOME/.local/share}/pinme-share/appkey.json.
🪪 Acknowledgements
- PinMe for the IPFS pinning service and
pinmeCLI - Part of the html-tool-suite — HTML generation, publishing, and sharing skills
Changelog
v1.0.1
- Fix (silent-failure): passing multiple mutually-exclusive operations (e.g.
<path>+--list) now returnsconflicting_argsinstead of silently running only the first matched branch and dropping the rest. - Fix (security):
--set-appkeywith a too-short key no longer echoes the key fragment (key[:20]) into the error output; it now reports only the length.
v1.0.0
- Initial open-source release (XDG-compliant storage, English docs, full-English CLI).
