OkFile
Agent-first file upload and publish service built on Cloudflare Pages Functions, R2, and D1.
- Website:
https://www.okfile.com - Repository:
https://github.com/okfilecom/okfile - License:
Apache-2.0
Python CLI
The published Python package name is okfile.
Install the latest release from PyPI:
py -3 -m pip install okfile
okfile --version
Install a pinned version when you need reproducible environments:
py -3 -m pip install okfile==2.1.1
Upgrade to the latest release:
py -3 -m pip install --upgrade okfile
Fallback wheel install:
py -3 -m pip install "https://okfile.pckee.com/downloads/okfile-2.1.1-py3-none-any.whl"
If okfile is not on PATH yet, use one of these repo-local fallbacks first:
py -3 -m pip install -e .
okfile --version
py -3 -m okfile_cli --version
py -3 -m okfile_cli publish ./my-site/
Do not use py -m okfile. The published package exposes the okfile console command, while the module entrypoint is okfile_cli.
- PyPI:
https://pypi.org/project/okfile/ - CLI skill doc:
./SKILL.md
Common CLI examples:
okfile upload photo.jpg
okfile upload video.mp4 --multipart-concurrency 3
okfile upload video.mp4 --stream
okfile upload video.mp4 --stream --stream-account-id <account_id> --stream-token <token>
okfile upload photo.jpg --retries 5 --retry-delay 3
okfile upload archive.zip --multipart-concurrency 6 --max-downloads 10
okfile upload photo.jpg --expires-at 2026-12-31T23:59:59Z
okfile publish ./my-site/
okfile publish ./my-site/ --retries 5 --retry-delay 2
okfile publish ./my-site/ --state-file .okfile-state.json
okfile publish ./my-site/ --fail-fast
okfile publish ./my-site/ --expires-at 2026-12-31T23:59:59Z
okfile status a3k7m92x
okfile status <stream_video_id> --stream
okfile config --key okf_xxxxx
okfile config --stream-account-id <account_id> --stream-token <token>
Help examples:
okfile upload --help
okfile publish --help
okfile status --help
Notes:
okfile uploaddefaults to--multipart-concurrency 3for multipart uploads- larger values can improve throughput for bigger files, but small files may not benefit
okfile uploadandokfile publishnow retry failed file uploads by default with--retries 3 --retry-delay 2- retry delay uses exponential backoff per file, so later retries wait longer than earlier ones
okfile publishcontinues uploading other files after an individual file failure and reports a failed-file summary at the endokfile publishwrites a local resume file by default at<site>/.okfile-publish-state.jsonand reuses already uploaded files on the next run when size and mtime still match- the publish state file is deleted automatically after a fully successful site publish
- use
--fail-fastwhen you wantpublishto stop immediately on the first file failure instead of collecting a failure summary okfile upload --streamsends video files to Cloudflare Stream with the tus resumable upload protocol; without Cloudflare credentials it uses OkFile hosted transcoding automatically--streamrequires a Cloudflare account ID and API token withStream Write; use command flags,okfile config, orCLOUDFLARE_ACCOUNT_IDplusCLOUDFLARE_STREAM_API_TOKENokfile status --stream <video_uid>queries Cloudflare Stream video status and playback URLs--max-downloadsonly applies to OkFile file storage and cannot be combined with--stream--expires-atmaps to Cloudflare Stream scheduled deletion when--streamis used
MCP Server
@okfilecom/okfile-mcp is a Model Context Protocol server (stdio, Node 18+) exposing OkFile as agent tools: okfile_upload_file, okfile_publish_site, okfile_upload_video_stream, okfile_get_status, okfile_get_limits. Register it with one command in Claude Code (claude mcp add okfile -- npx -y @okfilecom/okfile-mcp), Claude Desktop, or Cursor; optional env vars OKFILE_API_KEY, OKFILE_SERVER, and OKFILE_MCP_ROOT (restricts which local paths may be published). The source lives in mcp-server/; a self-contained build is served at https://www.okfile.com/okfile-mcp.mjs (node okfile-mcp.mjs).
What It Does
OkFile is designed for Agents, scripts, and lightweight manual upload use cases.
It supports:
- anonymous uploads
- authenticated uploads with user API keys
- video-to-streaming-media transcoding via hosted Cloudflare Stream (
okfile upload video.mp4 --streamorPOST /api/stream/prepare), returning watch/HLS/DASH playback URLs with no Cloudflare account required - direct file URLs for download or embedding
- preview/playback URLs for image, video, and PDF
- anonymous single-file uploads up to
1GB - API Key uploads up to
1TBper file - temporary retention for anonymous uploads, with current default expiry at
24 hours - a default
10-download cap on anonymous uploads (on the/d/{id}download route); override withmaxDownloads, or authenticate for uncapped uploads - multipart upload for larger authenticated files
- phase-1 site directory upload with nested subdirectories and per-site subdomain publish URLs
- automatic shared top-level directory stripping for folder-based site uploads
- directory listing fallback when a published site does not contain root
index.html - retrying only missing parts after incomplete multipart uploads
- email magic-link login and account management
- localized home, upload, and account pages
Main User Flows
1. Anonymous Publish
POST /api/upload/preparePUT uploadUrlor eachparts[].uploadUrlPOST /api/upload/complete- return
urland optionallyplayUrl - current single-file limit is
1GB, and uploaded files expire after24 hours
2. API Key Publish
- request a magic link and log in
- create an API key in
/account - call
POST /api/upload/preparewithX-API-Keyheader - upload file data to signed URLs
- call
POST /api/upload/complete - current single-file limit is
1TBwhen a valid API key is used
3. Manual Upload
Users can also use:
/zh/upload//en/upload/
This path is kept as a fallback entry, while API integration remains the recommended flow.
4. Site Directory Publish
- select a whole folder in
/zh/upload/or/en/upload/ - the uploader preserves nested relative paths
- if every file sits under one shared top-level folder, that folder is stripped and treated as the site root
- if the site contains root
index.html,/renders that page - if root
index.htmldoes not exist,/renders a directory listing with file name, size, and upload time - image and video entries open inline, while other files use download links
Architecture
Runtime
- Cloudflare Pages Functions for routing and API handling
- Cloudflare Worker route for
*.ok26.org/*site subdomains - Cloudflare R2 for file storage
- Cloudflare D1 for auth and API key metadata
- Resend for email magic links
Frontend
- static
index.htmlfor homepage - static
upload.htmlfor manual upload - server-side localization and SEO injection in
worker-app.js
Backend Responsibilities
- issue presigned R2 upload URLs
- complete multipart uploads
- activate public file routes
- resolve published site subdomains from request
Host - manage sessions, magic links, and API keys
- enforce anonymous and per-key quota limits
Core Routes
Pages
/zh/and/en/: localized home pages/zh/upload/and/en/upload/: manual upload pages/account: redirects to localized account page/zh/account/and/en/account/: localized account pages/admin: admin console
Upload APIs
POST /api/upload/preparePOST /api/upload/completeGET /api/upload/status/{id}POST /api/stream/prepareandGET /api/stream/status/{uid}for hosted video-to-streaming transcoding- authenticated automation should send
X-API-Key: okf_...
Authenticated prepare example:
curl -X POST "https://www.okfile.com/api/upload/prepare" \
-H "Content-Type: application/json" \
-H "X-API-Key: okf_..." \
--data '{"filename":"photo.jpg","size":12345,"contentType":"image/jpeg"}'
Auth APIs
POST /api/auth/request-linkGET /auth/verify?token=...GET /api/account/mePOST /api/account/api-keys
File URLs
/i/{id}: direct file URL/i/{id}?play=1: preview/playback page/d/{id}: controlled download route
Site URLs
https://{subdomain}.ok26.org/: site root or directory listinghttps://{subdomain}.ok26.org/path/to/file: published site asset or documenthttps://{subdomain}.ok26.org/path/to/file?download=1: force download for a site file
Repository Layout
.
|- worker-app.js # main Pages Function entry (re-exports src/router.js)
|- src/ # worker implementation modules
| |- router.js # route dispatch + scheduled handler
| |- constants.js # shared constants and limits
| |- utils.js # responses, ids, formatting, cookies, rate limiting
| |- seo.js # robots/sitemap/SEO + localized static pages
| |- policy.js # VIP tiers, size limits, expiry rules
| |- db.js # D1 schema bootstrap / lazy migrations
| |- storage.js # R2 presign, metadata, multipart, file serving
| |- auth.js # users, sessions, magic links, API keys
| |- account.js # account data + /api/account handlers
| |- sites.js # site publish, releases, directory listing
| |- uploads.js # upload prepare/quick/complete/status
| |- admin.js # admin APIs + scheduled cleanup
| |- pages-account.js # account/login/admin console pages
| |- pages-viewer.js # file viewer pages + raw/controlled downloads
|- index.html # homepage
|- upload.html # manual upload page
|- schema.sql # D1 schema
|- wrangler.toml # Cloudflare config
|- SKILL.md # root skill document
|- .trae/skills/okfile/SKILL.md # Trae skill definition
|- okfile-upload-pitfalls.md # upload pitfalls and debugging notes
Local Development
Install dependencies:
npm install
Run local development:
npx wrangler pages dev .
Deploy to Cloudflare Pages:
npx wrangler pages deploy . --project-name okfile --branch main
CI/CD
.github/workflows/ci.yml runs on every push and pull request:
- test: Python CLI unit tests (
tests/) plus esbuild bundle checks for the main worker and the admin worker - deploy (push to
mainonly): deploys all three targets from the same commit  the Pages project (www.okfile.com), the sites worker (*.ok26.org), and the admin worker (admin.okfile.com)  then runs a post-deploy smoke check
Required repository secrets (Settings → Secrets and variables → Actions):
CLOUDFLARE_API_TOKEN: token with Pages Edit + Workers Scripts Edit + D1 Edit for the accountCLOUDFLARE_ACCOUNT_ID: the Cloudflare account id
Deploying all three targets together prevents the Pages project and the classic workers (which share worker-app.js) from drifting apart.
Configuration
Store secrets in Cloudflare, not in the repository.
Secrets
R2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYRESEND_API_KEY
Plain-Text Vars
R2_ACCOUNT_IDRESEND_FROM_EMAILADMIN_EMAILS
Database
The D1 schema is defined in schema.sql and includes:
usersmagic_linkssessionsapi_keysapi_key_usage_windows
Upload Notes
See these repo docs for integration details:
SKILL.mdSITE_UPLOAD_DESIGN.md.trae/skills/okfile/SKILL.mdokfile-upload-pitfalls.md
The pitfalls doc includes practical notes such as:
- Cloudflare requiring a normal
User-Agentfor some requests - explicit
Content-Lengthon R2 PUT - multipart retry strategy
- large-file client recommendations on Windows
For site publishing:
- use root
index.htmlwhen you want the subdomain root to render a page - if you upload a single wrapper folder such as
my-site/..., OkFile stripsmy-site/automatically - if no root
index.htmlexists, users land on a browsable directory listing instead of downloading an arbitrary file
Articles
Published and outward-facing articles are archived in docs/:
- docs/README.md
- docs/devto-agent-delivery-publish-file-or-site-test-guide.md
- docs/aliyun-workbuddy-agent-file-site-publish-test-guide.md
Contributing
Please read CONTRIBUTING.md before opening pull requests.
Security
Please read SECURITY.md for reporting instructions and secret-handling rules.
Changelog
See CHANGELOG.md for release notes tracked in-repo.
License
Apache-2.0
Metadata
Release files for okfile 2.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| okfile-2.1.1.tar.gz | 30.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| okfile-2.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.5 kB
Release files / okfile-2.1.1.tar.gz
| Download URL | okfile-2.1.1.tar.gz |
|---|---|
| Size | 30.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6bb3408e6255f35f12bdf33fed715d9a72268a968f4758770357248391d1e130
|
|
BLAKE2b-256 checksum How to use checksums |
008877886310c3eac39df8a580df93ca598d1ee763f77e6a299eeb4c0362ea40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|
Release files / okfile-2.1.1-py3-none-any.whl
| Download URL | okfile-2.1.1-py3-none-any.whl |
|---|---|
| Size | 27.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
925c840aae91830706b14fe4ad83c0fced4340dcfb8ac5ff6e92a9c0d62e48c1
|
|
BLAKE2b-256 checksum How to use checksums |
eb0cde2527e815861f2aae952003b99d2869b89685655f2bda0a284764b573c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.15
|