Uploads and publishes files or static site folders to OkFile, with direct links, preview URLs, and multipart support. Use when the user asks to upload, publi...
---
name: okfile
description: "Uploads and publishes files or static site folders to OkFile, with direct links, preview URLs, and multipart support. Use when the user asks to upload, publish, or share files or folders."
version: 1.2.3
license: Apache-2.0
---
# OkFile Skill
Official site: `https://www.okfile.com/`
## Overview
OkFile is an agent-first file upload and publish service.
Use this skill when an agent needs to:
- upload images, videos, PDFs, or common files
- fast-path small files with `POST /api/upload/quick` when the file is within the advertised quick-upload limit
- upload a static site folder and publish it to a per-site subdomain
- rely on automatic shared top-level directory stripping for folder-based site uploads
- expose a directory listing when a site has no root `index.html`
- return a direct file URL via `url`
- return a preview or playback URL via `playUrl`
- return a published site URL via `siteUrl` or `entryUrl`
- publish files anonymously or with a user API key
- handle large files with multipart upload and retry missing parts only
- drive repeatable upload or publish workflows from the bundled Python CLI
## When To Use
Choose this skill when the user asks to:
- upload or publish a file
- generate a public file link
- generate an image, video, or PDF preview link
- publish a folder as a static website
- publish a folder that may not contain root `index.html`
- batch-process multiple files
- upload large files with resumable multipart flow
- use a Python CLI for upload, publish, status, or config operations
## Quick Start
### Discover Capabilities First
1. `GET /api/upload/config`
2. read `quickUploadMaxSize`, `multipartThreshold`, and `partSize`
3. choose `POST /api/upload/quick` for small files, or `prepare -> PUT -> complete` for normal and large uploads
### Small File Fast Path
1. `POST /api/upload/quick` with `multipart/form-data`
2. receive the same final response shape as `POST /api/upload/complete`
### Standard File Flow
1. `POST /api/upload/prepare`
2. `PUT uploadUrl` or each `parts[].uploadUrl`
3. `POST /api/upload/complete`
### Static Site Flow
1. `POST /api/site/prepare`
2. upload each file through the normal file upload flow
3. `POST /api/site/complete`
Static site behavior:
- if every uploaded path is under one shared top-level folder, OkFile strips that folder and treats its contents as the site root
- if root `index.html` exists, the site root renders that page
- if root `index.html` does not exist, the site root renders a directory listing with file name, size, and upload time
- images and videos open inline from that listing
- other files should use download links
### Minimal Prepare Request
```bash
curl -X POST "https://www.okfile.com/api/upload/prepare" \
-H "Content-Type: application/json" \
--data '{"filename":"photo.jpg","size":12345,"contentType":"image/jpeg","preferredPartSize":5242880}'
```
### Minimal Quick Upload Request
```bash
curl -X POST "https://www.okfile.com/api/upload/quick" \
-F "file=@photo.jpg"
```
### Minimal Complete Request
```bash
curl -X POST "https://www.okfile.com/api/upload/complete" \
-H "Content-Type: application/json" \
--data '{"id":"a3k7m92x"}'
```
### Status Check
```bash
curl "https://www.okfile.com/api/upload/status/a3k7m92x"
```
### Python CLI Examples
```bash
okfile upload photo.jpg
okfile upload photo.jpg --max-downloads 10
okfile upload photo.jpg --expires-at 2026-12-31T23:59:59Z
okfile publish ./my-site/
okfile publish ./my-site/ --expires-at 2026-12-31T23:59:59Z
okfile status a3k7m92x
okfile status a3k7m92x --verbose
okfile config --key okf_xxxxx
okfile config --clear-origin
okfile --version
```
### Python CLI Install
Prefer installing the latest published PyPI package:
```bash
py -3 -m pip install okfile
okfile --version
```
If you need a pinned install for reproducibility:
```bash
py -3 -m pip install okfile==1.2.3
```
Upgrade an existing install:
```bash
py -3 -m pip install --upgrade okfile
```
If you need a direct static artifact instead of PyPI, install the wheel from OkFile:
```bash
py -3 -m pip install "https://www.okfile.com/downloads/okfile-1.2.3-py3-none-any.whl"
```
Debugging tips:
```bash
okfile upload photo.jpg --origin https://www.okfile.com --verbose
okfile status invalid_id --verbose
```
### Key Rules
- use `GET /api/upload/config` to discover the current quick-upload and multipart thresholds instead of hardcoding them
- prefer `POST /api/upload/quick` for small files when `size <= quickUploadMaxSize`
- `apiKey` is optional and is only sent to `prepare`
- `--max-downloads` and `--expires-at` are supported by the CLI for file uploads; `--expires-at` is also supported for site publish
- `okfile config --clear-origin` removes the stored default origin and falls back to `https://www.okfile.com`
- `--verbose` prints traceback details for debugging request or parsing failures
- `complete` only needs `id`
- if `complete` returns `missingParts`, re-upload only those parts
- prefer returning `url`; return `playUrl` when preview matters
## Authentication Modes
### Anonymous
Use anonymous mode for direct publishing without login.
- no account required
- rate-limited by IP
- good for lightweight or temporary tasks
### API Key
Use API key mode for controlled, long-term, or team-managed usage.
Flow:
1. `POST /api/auth/request-link`
2. open the email verification link
3. create an API key in `/account`
4. include `apiKey` in `POST /api/upload/prepare`
## Endpoints
### `GET /api/upload/config`
Response example:
```json
{
"success": true,
"maxSize": 524288000,
"quickUploadMaxSize": 5242880,
"multipartThreshold": 26214400,
"partSize": 10485760
}
```
Notes:
- use this endpoint before uploads when the client needs dynamic limits
- `quickUploadMaxSize` indicates when `/api/upload/quick` can be used
### `POST /api/upload/prepare`
Request body:
```json
{
"filename": "photo.jpg",
"size": 12345,
"contentType": "image/jpeg",
"preferredPartSize": 5242880,
"apiKey": "okf_..."
}
```
Notes:
- `preferredPartSize` is optional
- current supported range is `5MB` to `100MB`
- response may be `single` or `multipart`
- `expiresIn` refers to the signed `uploadUrl` or `parts[].uploadUrl` lifetime only; it does not describe a separate Worker-side upload-session TTL
- if `complete` says the upload session was not found, first verify that you are using the exact same `id` returned by that specific `prepare` call
Single upload response example:
```json
{
"success": true,
"id": "a3k7m92x",
"mode": "single",
"uploadUrl": "https://upload.example.com/...",
"expiresIn": 3600,
"method": "PUT",
"url": "https://www.okfile.com/i/a3k7m92x",
"playUrl": "https://www.okfile.com/i/a3k7m92x?play=1",
"type": "image"
}
```
Multipart response example:
```json
{
"success": true,
"id": "a3k7m92x",
"mode": "multipart",
"uploadId": "3c4d...",
"partSize": 5242880,
"totalParts": 33,
"parts": [
{ "partNumber": 1, "uploadUrl": "https://..." }
],
"url": "https://www.okfile.com/i/a3k7m92x",
"playUrl": "https://www.okfile.com/i/a3k7m92x?play=1",
"type": "video"
}
```
### `POST /api/upload/quick`
Request:
- send `multipart/form-data`
- include the file in the `file` field
- optional fields such as `expiresAt` and `maxDownloads` follow the normal upload semantics
Success response example:
```json
{
"success": true,
"id": "a3k7m92x",
"url": "https://www.okfile.com/i/a3k7m92x",
"downloadUrl": "https://www.okfile.com/d/a3k7m92x",
"playUrl": "https://www.okfile.com/i/a3k7m92x?play=1",
"type": "image"
}
```
Notes:
- intended for small files only
- the response shape matches the final `complete` response so clients can reuse downstream logic
### `PUT uploadUrl` or `parts[].uploadUrl`
- upload the file body directly to the signed URL
- single mode usually needs one `PUT`
- multipart mode needs one `PUT` per part
- set `Content-Length` explicitly
### `POST /api/upload/complete`
Request body:
```json
{
"id": "a3k7m92x"
}
```
Success response example:
```json
{
"success": true,
"id": "a3k7m92x",
"url": "https://www.okfile.com/i/a3k7m92x",
"playUrl": "https://www.okfile.com/i/a3k7m92x?play=1",
"type": "image"
}
```
Incomplete multipart response example:
```json
{
"success": false,
"error": "Missing parts",
"uploadedParts": 45,
"totalParts": 50,
"missingParts": [4, 12, 28, 44, 49]
}
```
### `GET /api/upload/status/{id}`
Response example:
```json
{
"id": "a3k7m92x",
"status": "uploading",
"progress": "45/50",
"uploadedParts": 45,
"totalParts": 50,
"bytesReceived": 471859200
}
```
### `POST /api/site/prepare`
Request body:
```json
{
"siteName": "docs-site",
"files": [
{ "path": "docs/getting-started.md", "size": 1200, "contentType": "text/markdown; charset=utf-8" },
{ "path": "assets/app.css", "size": 3200, "contentType": "text/css; charset=utf-8" },
{ "path": "images/logo.png", "size": 4200, "contentType": "image/png" }
]
}
```
Notes:
- omit `entryPath` entirely when the uploaded folder has no root `index.html`
- do not generate or upload a synthetic `index.html` just to mimic a directory listing
- when root `index.html` is absent, OkFile generates the directory listing automatically
- use site-relative paths such as `assets/app.css`, not local absolute paths
- nested subdirectories are supported, for example `docs/getting-started.md` or `images/icons/logo.svg`
- `siteToken` is bound to one specific `site/prepare` response and should be passed to the matching `site/complete`; do not mix tokens across runs
Success response example:
```json
{
"success": true,
"siteId": "st_ab12cd34",
"siteToken": "token",
"siteHostname": "st-ab12cd34.ok26.org",
"siteUrl": "https://st-ab12cd34.ok26.org/",
"entryUrl": "https://st-ab12cd34.ok26.org/",
"uploadStrategy": "reuse-file-upload-api"
}
```
### `POST /api/site/complete`
Request body:
```json
{
"siteId": "st_ab12cd34",
"siteToken": "token",
"files": [
{ "relativePath": "docs/getting-started.md", "fileId": "f1a2b3c4" },
{ "relativePath": "assets/app.css", "fileId": "d4e5f6g7" },
{ "relativePath": "images/logo.png", "fileId": "h7i8j9k0" }
]
}
```
Success response example:
```json
{
"success": true,
"siteId": "st_ab12cd34",
"siteHostname": "st-ab12cd34.ok26.org",
"siteUrl": "https://st-ab12cd34.ok26.org/",
"entryUrl": "https://st-ab12cd34.ok26.org/",
"entryPath": "index.html"
}
```
## Output Strategy
Prefer returning:
- `url` for direct consumption, download, embedding, or API use
- `playUrl` for image preview, video playback, or PDF viewing
- `siteUrl` for the root of a published static site
- `entryUrl` for the preferred HTML entry page, or the same value as `siteUrl` when the site uses directory listing
For video or PDF, returning both is usually best.
## Python CLI
Use the CLI when the user wants a local command-line workflow instead of raw HTTP requests.
Recommended commands:
```bash
okfile upload photo.jpg
okfile publish ./my-site/
okfile status a3k7m92x
okfile config --key okf_xxxxx
okfile config --clear-origin
okfile --version
```
Recommended install path:
```bash
py -3 -m pip install okfile
```
Pinned install example:
```bash
py -3 -m pip install okfile==1.2.3
```
Use the CLI when:
- the user wants a copy-pasteable install command
- the user prefers local commands over direct API calls
- the workflow needs repeatable upload or publish commands on Windows
## Supported Types
- images: `JPG`, `JPEG`, `PNG`, `GIF`, `WebP`, `BMP`, `SVG`
- videos: `MP4`, `WebM`, `MOV`, `AVI`, `MKV`
- documents: `PDF`
- other common files are handled as generic files
## Limits
- max file size: `500MB`
- quick-upload path: currently advertised by `GET /api/upload/config`, typically `<= 5MB`
- files above threshold automatically use multipart upload
- anonymous mode is IP rate-limited
- API key mode is controlled by backend quotas
- parallel uploads are supported, but concurrency should be controlled by the client
## Best Practices
- call `GET /api/upload/config` before automation runs that need dynamic thresholds
- use `quick` for small files and reserve `prepare -> PUT -> complete` for larger payloads
- always follow `prepare -> PUT -> complete`
- keep the `prepare` response values (`id`, and for site publishing also `siteId` + `siteToken`) from the same execution context until `complete` finishes
- set a normal `User-Agent` on `prepare` and `complete`
- set `Content-Length` on each `PUT`
- check every part upload for `2xx` status
- retry only `missingParts`, not the whole file
- prefer stable HTTP clients for large files and multipart flows
- include `index.html` at the site root when you want the subdomain homepage to render a page immediately
- if a site is intentionally file-browsing-only, leave root `index.html` out and use the generated listing page
- do not ask the agent to create a synthetic listing `index.html`; upload the real folder tree and let OkFile render the listing automatically
- preserve nested subdirectories exactly as uploaded; published sites support paths like `/docs/guide/` and `/assets/app.css`
## Useful URLs
- home: `https://www.okfile.com/en/`
- upload page: `https://www.okfile.com/en/upload/`
- account: `https://www.okfile.com/account`
- admin: `https://www.okfile.com/admin`
- PyPI package: `https://pypi.org/project/okfile/`
- CLI wheel: `https://www.okfile.com/downloads/okfile-1.2.3-py3-none-any.whl`
- repo CLI entry: `okfile_cli/__main__.py`
don't have the plugin yet? install it then click "run inline in claude" again.
official site: https://www.okfile.com/
upload files, folders, or static sites to okfile and generate shareable links, preview URLs, or published site domains. use this skill when the user asks to upload a file, publish a folder as a website, create a public link to an image or video, or batch-process multiple files. okfile handles small files with a fast path, large files with resumable multipart uploads, and static sites with automatic directory listing when no root index.html exists.
api endpoint
https://www.okfile.com/authentication (optional)
apiKey parameter sent to POST /api/upload/preparePOST /api/auth/request-link, verify email, create key in /accountOKFILE_API_KEY or pass --key okf_xxxxx to okfile configconfiguration discovery
GET /api/upload/config before automation to read current thresholds:quickUploadMaxSize: max bytes for fast-path upload (typically 5MB)multipartThreshold: file size above which multipart is required (typically 25MB)partSize: chunk size for multipart uploads (typically 10MB)maxSize: absolute max file size (typically 500MB)file payload
image/jpeg, video/mp4, text/markdown; charset=utf-8)site metadata (for folder publish)
docs/index.html, assets/app.css)index.html at root (if absent, okfile generates directory listing)python cli (optional)
py -3 -m pip install okfile or py -3 -m pip install okfile==1.2.3 (pinned)input: none
output: config object with quickUploadMaxSize, multipartThreshold, partSize
GET /api/upload/config
store quickUploadMaxSize for decision logic in step 2.
edge case: network timeout or 5xx error. retry with exponential backoff (max 3 attempts, 1s base delay). if all retries fail, assume quickUploadMaxSize = 5242880 (5MB).
input: file <= quickUploadMaxSize, filename, content type
output: upload response with id, url, playUrl, type
only use this when file size is confirmed below threshold.
POST /api/upload/quick
Content-Type: multipart/form-data
file=@<filename>
optional form fields:
expiresAt: ISO 8601 timestamp (e.g. 2026-12-31T23:59:59Z)maxDownloads: integer (e.g. 10)parse response and return url or playUrl directly. skip steps 2b and 2c.
edge case: file exceeds threshold between config check and upload. okfile rejects with 413; fall back to step 2b (prepare).
input: filename, file size, content type, optional apiKey
output: upload session object with id, mode (single or multipart), signed uploadUrl or parts[]
POST /api/upload/prepare
Content-Type: application/json
{
"filename": "video.mp4",
"size": 104857600,
"contentType": "video/mp4",
"preferredPartSize": 10485760,
"apiKey": "okf_..."
}
notes:
preferredPartSize is optional, range 5MB to 100MBapiKey is optional, only sent here (not on PUT or complete)expiresIn (lifetime of signed URLs, typically 1 hour)uploadUrl and one PUTparts[] with individual uploadUrl per partedge case: session expires before all parts upload. timestamps in expiresIn are for signed URL expiry only. if a PUT fails with 403 after url expiry, call prepare again (do not reuse old uploadUrl).
input: uploadUrl (single mode) or parts[].uploadUrl (multipart mode), file data
output: 2xx http status on each PUT
for single mode:
PUT <uploadUrl from prepare>
Content-Length: <exact byte count>
Content-Type: application/octet-stream
<file binary data>
for multipart mode, repeat for each part:
PUT <parts[i].uploadUrl>
Content-Length: <part byte count>
Content-Type: application/octet-stream
<part binary data (bytes offset to offset+partSize)>
notes:
Content-Length explicitlyedge case: partial failure in multipart. upload as many parts as possible. if some parts fail after max retries, proceed to step 3 (complete) and inspect response for missingParts array.
input: id from prepare response
output: final file object with id, url, playUrl, type
POST /api/upload/complete
Content-Type: application/json
{
"id": "a3k7m92x"
}
parse response:
success: true, upload is complete. return url or playUrl to user.success: false and missingParts array exists, re-upload only those parts (go back to step 2c with just the missing part numbers), then retry complete.edge case: upload session not found (404 or "session not found" error). verify you are using the exact id from the same prepare call. if correct, the session expired on the backend (>24h). ask user to restart from step 1.
input: id from prepare
output: status object with progress, uploadedParts, totalParts, bytesReceived
GET /api/upload/status/{id}
use this to poll progress during long uploads or debug incomplete uploads. does not finalize the upload.
input: site name, list of files with relative paths and sizes
output: site session with siteId, siteToken, siteUrl, entryUrl
POST /api/site/prepare
Content-Type: application/json
{
"siteName": "docs-site",
"files": [
{ "path": "index.html", "size": 2048, "contentType": "text/html; charset=utf-8" },
{ "path": "docs/guide.md", "size": 1200, "contentType": "text/markdown; charset=utf-8" },
{ "path": "assets/app.css", "size": 3200, "contentType": "text/css; charset=utf-8" },
{ "path": "images/logo.png", "size": 4200, "contentType": "image/png" }
]
}
notes:
assets/app.css, not /home/user/my-site/assets/app.css)docs/getting-started.md, images/icons/logo.svg)index.html from the file list if the site is file-browsing-only. okfile will auto-generate directory listing.siteId and siteToken. keep both for the matching complete call.edge case: site name collision (slug already taken). okfile returns error. retry with a different siteName.
input: each file from the site file list output: file id for each uploaded file
for each file in the site, perform steps 2b and 2c (or 2a if small enough). collect the returned id for each file.
note: do not call POST /api/upload/complete yet. instead, gather all file ids and proceed to step 5c.
input: siteId, siteToken from step 5a, file id mapping
output: published site object with siteUrl, entryUrl
POST /api/site/complete
Content-Type: application/json
{
"siteId": "st_ab12cd34",
"siteToken": "token",
"files": [
{ "relativePath": "index.html", "fileId": "f1a2b3c4" },
{ "relativePath": "docs/guide.md", "fileId": "d4e5f6g7" },
{ "relativePath": "assets/app.css", "fileId": "e5f6g7h8" },
{ "relativePath": "images/logo.png", "fileId": "h7i8j9k0" }
]
}
response includes siteUrl and entryUrl (same value if directory listing mode, or pointing to index.html if root index.html exists).
edge case: token mismatch or expired. if token was valid at step 5a but complete fails, the session timed out (>24h). restart from step 5a.
input: file or folder path, optional api key, optional expiry or max downloads output: formatted output with file/site url
cli commands:
okfile upload photo.jpg
okfile upload photo.jpg --max-downloads 10
okfile upload photo.jpg --expires-at 2026-12-31T23:59:59Z
okfile publish ./my-site/
okfile publish ./my-site/ --expires-at 2026-12-31T23:59:59Z
okfile status a3k7m92x
okfile status a3k7m92x --verbose
okfile config --key okf_xxxxx
okfile config --clear-origin
okfile --version
first-time setup (optional api key):
okfile config --key okf_xxxxx
clear stored config:
okfile config --clear-origin
debugging:
okfile upload photo.jpg --origin https://www.okfile.com --verbose
okfile status invalid_id --verbose
install:
py -3 -m pip install okfile
py -3 -m pip install okfile==1.2.3 # pinned version
py -3 -m pip install --upgrade okfile # upgrade
py -3 -m pip install "https://www.okfile.com/downloads/okfile-1.2.3-py3-none-any.whl" # direct wheel
notes:
--verbose prints traceback on errors.is the file small enough for quick upload?
quickUploadMaxSize from config (typically 5MB), use step 2a (fast path).does the user have an api key?
apiKey in step 2b (prepare).is the upload for a single file or a site folder?
does the site have a root index.html?
index.html as the homepage.index.html. okfile auto-generates a directory listing page. do not create a synthetic index.html listing.does the multipart upload have missing parts after complete?
missingParts array is present, re-upload only those part numbers (step 2c), then retry complete (step 3).success: true, upload is done.should the user use the python cli or raw http?
network error or timeout during upload?
quickUploadMaxSize = 5MB) if all retries fail.does the user want to expire the file or limit downloads?
expiresAt (iso 8601 timestamp) and/or maxDownloads (integer) in step 2a quick request or step 2b prepare request.single file upload success (steps 2a or 3)
{
"success": true,
"id": "a3k7m92x",
"url": "https://www.okfile.com/i/a3k7m92x",
"playUrl": "https://www.okfile.com/i/a3k7m92x?play=1",
"downloadUrl": "https://www.okfile.com/d/a3k7m92x",
"type": "image"
}
return to user:
url: direct file link (use for api consumption, embedding, download)playUrl: preview or playback link (use for images, videos, pdfs)type: detected file type (image, video, document, or generic)multipart upload incomplete response (step 3)
{
"success": false,
"error": "Missing parts",
"uploadedParts": 45,
"totalParts": 50,
"missingParts": [4, 12, 28, 44, 49]
}
action: re-upload parts in missingParts array, retry complete.
site publication success (step 5c)
{
"success": true,
"siteId": "st_ab12cd34",
"siteHostname": "st-ab12cd34.ok26.org",
"siteUrl": "https://st-ab12cd34.ok26.org/",
"entryUrl": "https://st-ab12cd34.ok26.org/",
"entryPath": "index.html"
}
return to user:
siteUrl: root subdomain (use for sharing the site)entryUrl: preferred entry point (same as siteUrl for directory listing, or points to index.html if present)upload status response (step 4)
{
"id": "a3k7m92x",
"status": "uploading",
"progress": "45/50",
"uploadedParts": 45,
"totalParts": 50,
"bytesReceived": 471859200
}
use for progress reporting during large uploads.
supported file types
limits
expiresIn)file and site url formats
https://www.okfile.com/i/{id}https://www.okfile.com/i/{id}?play=1https://www.okfile.com/d/{id}https://{siteHostname}.ok26.org/user knows the upload succeeded when:
success: true with a valid url and idurl is accessible (http 200) and serves the file or previewplayUrl renders inline previewdownloadUrl triggers downloaduser knows the site published successfully when:
success: true with siteUrlsiteUrl