Cloudflare R2
einverne/dotfiles
Guide for implementing Cloudflare R2 - S3-compatible object storage with zero egress fees.
Wavelet 项目专用:当业务需要上传文件、读取已上传文件、在 Worker/任务中程序化摄取字节流、选择存储引擎能力、或排查 wuploads / 文件统计异常时必须使用。本技能指导 storage 与 upload 分层、upload.Ingest 策略选型、前后端接入与禁止旁路写表。
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install Rain-kl/OpenFlare file-upload --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/file-upload .claude/skills/file-upload && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .claude/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-uploadType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install Rain-kl/OpenFlare file-upload --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/file-upload .agents/skills/file-upload && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .agents/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install Rain-kl/OpenFlare file-upload --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/file-upload .cursor/skills/file-upload && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .cursor/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/Rain-kl/OpenFlare.git --path .agents/skills/file-upload--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install Rain-kl/OpenFlare file-upload --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/file-upload .gemini/skills/file-upload && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .gemini/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install Rain-kl/OpenFlare file-uploadInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/file-upload .github/skills/file-upload && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .github/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Rain-kl/OpenFlare --skill file-upload -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install Rain-kl/OpenFlare file-upload --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Rain-kl/OpenFlare.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/file-upload .opencode/skills/file-upload && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "file-upload" agent skill from https://github.com/Rain-kl/OpenFlare/tree/main/.agents/skills/file-upload into .opencode/skills/file-upload/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "file-upload", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
file-uploadWavelet 项目专用:当业务需要上传文件、读取已上传文件、在 Worker/任务中程序化摄取字节流、选择存储引擎能力、或排查 wuploads / 文件统计异常时必须使用。本技能指导 storage 与 upload 分层、upload.Ingest 策略选型、前后端接入与禁止旁路写表。
File Upload is an agent skill from Rain-kl/OpenFlare. Wavelet 项目专用:当业务需要上传文件、读取已上传文件、在 Worker/任务中程序化摄取字节流、选择存储引擎能力、或排查 wuploads / 文件统计异常时必须使用。本技能指导 storage 与 upload 分层、upload.Ingest 策略选型、前后端接入与禁止旁路写表。
Its SKILL.md is about 1.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Backend & APIs, covering File uploads and storage. It works with Cloudflare. The repository describes itself as: OpenFlare is an open-source CDN orchestration and edge security platform. It supports reverse proxy, centralized configuration synchronization, in-network tunneling (Tunnels)… The licence is Apache-2.0.
4 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 7c2304d. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
makegoFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
File Upload loads about 1.7k tokens when it runs. Until then it costs about 40 tokens; SKILL.md has 338 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from Rain-kl/OpenFlare at commit 7c2304d, republished under its Apache-2.0 licence (© Rain-kl). 338 words, ~1,677 tokens.
.claude/skills/file-upload/SKILL.md (or your agent's skills folder).本技能是 Wavelet 文件上传与对象存储的唯一开发指导。开始开发前先阅读仓库根目录 AGENTS.md,遵守项目级核心规则。
Wavelet 将「对象存储」与「上传业务」分为两层,禁止混用职责:
| 层级 | 包路径 | 职责 | 业务是否直接调用 |
|---|---|---|---|
| 对象存储引擎 | internal/infra/objectstore | Backend 接口:Put / Get / Delete / Test;按配置切换 Local / S3 / R2 / OSS / WebDAV | 禁止(仅 upload 域内部使用) |
| 上传域服务 | internal/apps/upload | w_uploads 记录、权限、秒传、统计、文件服务、upload.Ingest | 必须 |
| 上传 HTTP 入口 | internal/apps/upload/handler | POST /api/v1/upload 等 multipart 接口 | 前端 / 用户侧上传 |
| 文件访问 | internal/apps/upload/filesrv | GET /f/:id 流式响应、访问控制、图片 WebP 压缩 | 展示 / 下载 |
业务模块 ──► upload.Ingest / upload.Remove(唯一写入门禁)
├── storage.Backend.Put/Get/Delete
├── repository.CreateUpload(仅 upload 内部)
└── RecordUploadStatsAdd/Remove(ingest 内置,禁止业务直调)以下写法一律禁止:
// ❌ 业务包直接写 blob
storage.Active(ctx); backend.Put(...)
// ❌ 旁路写 w_uploads
db.DB(ctx).Create(&model.Upload{})
repository.CreateUpload(ctx, upload) // 仅 internal/apps/upload 允许
// ❌ 手动维护统计
upload.ApplyUploadStatsAdd(ctx, upload) // 已 Deprecated
// ❌ 业务表存物理路径
invoice.FilePath = "uploads/2026/01/02/123.pdf"正确做法:业务表只存 upload_id(uint64 / JSON string),通过 /f/{id} 或 upload.OpenStoredObject 访问。
根据场景选择 upload.Ingest 的 Policy:
| 场景 | Policy | 哈希命中时 | 未命中时 | 典型调用方 |
|---|---|---|---|---|
| 用户 HTTP 上传(含秒传) | PolicyDedupNewRecord | 复用 path,新建记录 + 统计 | 写 blob + 新建记录 + 统计 | handler.UploadFile(已内置) |
| Worker 生成全新文件 | PolicyCreate | 不查重,始终写 blob + 记录 | 同左 | 报表导出、定时生成 |
| 镜像 / 去重摄取(Pixez) | PolicyResolveExisting | 直接返回已有记录,不建新记录、不加统计 | 写 blob + 新建记录 + 统计 | 异步镜像任务 |
| 业务只需引用已有文件 | 不调 Ingest | — | — | 业务 API 校验 upload_id 即可 |
| 字段 | 含义 |
|---|---|
Created | 是否新建了 w_uploads 记录 |
Stored | 是否写入了新 blob |
Resolved | 是否通过哈希解析到已有记录(仅 PolicyResolveExisting) |
在 logics.go(接受 context.Context,不依赖 *gin.Context)中调用:
import (
"bytes"
"github.com/Rain-kl/Wavelet/internal/apps/upload"
"github.com/Rain-kl/Wavelet/internal/model"
)
func ingestMirrorFile(ctx context.Context, userID uint64, data []byte, hash, filename, mime, ext string) (model.Upload, error) {
accessMode := 1
result, err := upload.Ingest(ctx, upload.IngestRequest{
UserID: userID,
Reader: bytes.NewReader(data),
Size: int64(len(data)),
FileName: filename,
MimeType: mime,
Extension: ext,
Hash: hash, // 必填:SHA-256 hex
Type: "your_biz_type",
AccessMode: &accessMode,
Metadata: model.UploadMetadata{
Extra: map[string]any{"source": "worker"},
},
Policy: upload.PolicyResolveExisting,
})
if err != nil {
return model.Upload{}, err
}
return result.Upload, nil
}| 字段 | 说明 |
|---|---|
Hash | 必填,推荐 SHA-256 hex;用于秒传 / 镜像去重 |
Type | 业务分类(如 avatar、invoice、pixez_mirror),用于筛选与统计 |
AccessMode | nil 时按 type 默认:avatar → 公开(1),其余 → 私有(0) |
SkipExtensionCheck | Worker 场景若已自行校验扩展名,可设为 true |
ObjectKeyFn | 可选自定义存储路径;默认 uploads/YYYY/MM/DD/{id}.{ext} |
| 错误 | 含义 | Handler 映射建议 |
|---|---|---|
upload.ErrIngestStorageReadOnly | 存储迁移维护中 | response.AbortConflict |
ingest.ErrForbidden | 无权删除他人文件 | HTTP 403 |
shared.ErrUnsupportedFormat | 扩展名不在白名单 | response.AbortBadRequest |
// 管理员 / 系统删除
_, err := upload.Remove(ctx, uploadID)
// 用户删除自己的文件
_, err := upload.RemoveOwned(ctx, userID, uploadID)uploadRec, err := repository.GetActiveUploadByID(ctx, uploadID)
obj, err := uploadstorage.OpenStoredObject(ctx, &uploadRec)
defer obj.Body.Close()或通过门面(若已从 exports 暴露 OpenStoredObject)读取。HTTP 对外访问统一走 GET /f/:id。
推荐 两步流程(先上传、后提交业务):
POST /api/v1/upload → 获得 upload.idupload_id,用 repository.GetActiveUploadByID 校验存在且 status 为 activeupload.Type 是否为预期业务类型upload_id 写入业务表字段(如 cover_file_id)禁止在业务 Handler 中重复实现 multipart 解析,除非有极强的特殊协议需求。
使用 frontend/lib/services/upload/:
import { services } from '@/lib/services'
import { getFileUrl } from '@/lib/services/upload'
// 上传
const upload = await services.upload.uploadFile(file, 'invoice', { orderId: '123' })
// 展示
const url = getFileUrl(upload.id) // → /f/{id}
// Base64 图片(头像等)
const res = await services.upload.uploadBase64Image(croppedBase64, 'avatar', 'avatar.png')UploadService / AdminUploadService,在 frontend/lib/services/index.ts 注册getFileUrl(id, quality?) 或 FileImagePreview 组件upload_id,不要提交 blob URL 或 file_pathw_upload_stats 由 upload.Ingest / upload.Remove 自动维护,业务不得手动增量。
若发现 trend / total 与 w_uploads 不一致(常见于历史旁路写表):
upload.RebuildUploadStats(ctx) // 从 w_uploads 全量重建统计排查清单:
upload.Ingest 直接 db.Create(&model.Upload{})?ApplyUploadStatsAdd?upload.Remove(须在软删前扣减统计)?testhelper.SetupTestEnvironment(t) 初始化 DBstorage.MockStorage(...) + storage.IsEnabledFunc = func() bool { return true }uploads/test 路径;本地文件测试用 t.TempDir() 或 mock backend参考:internal/apps/upload/ingest/ingest_test.go
修改 upload handler 后运行:
go test ./internal/apps/upload/...
make code-check若变更 HTTP 接口,运行 make swagger。
将以下模式:
storage.Active(ctx)
backend.Put(ctx, key, reader, size, mime)
db.DB(ctx).Create(&upload)替换为:
upload.Ingest(ctx, upload.IngestRequest{ Policy: upload.PolicyResolveExisting, ... })迁移完成后执行一次 upload.RebuildUploadStats(ctx) 修复历史统计偏差。
完成文件上传相关开发后,确认:
repository.CreateUpload / SoftDeleteUpload 调用storage.Active + Put 直接写文件upload_id,不存 file_pathPolicymake code-check 通过make swagger© Rain-kl, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/file-upload of Rain-kl/OpenFlare.
Open the folder on GitHubat commit 7c2304d
File Upload next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| File Upload this skillRain-kl/OpenFlare | 288 | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| Cloudflare R2einverne/dotfiles | 121 | — | ~2.8k | Automated safety check: Pass | GPL-3.0 | |
| Cloudflare R2sickn33/agentic-awesome-skills | 47k | 2 repos | ~2.5k | Automated safety check: Pass | MIT | |
| Cloudflare 3sundial-org/awesome-openclaw-skills | 663 | — | ~1.5k | Automated safety check: Pass | None | |
| Stripe Projectsfossasia/eventyay | 1.7k | 5 repos | ~2k | Automated safety check: Notes | Apache-2.0 | |
| Golivemikehasa/golive-skill | 1.2k | — | ~13k | Automated safety check: Notes | MIT |
einverne/dotfiles
Guide for implementing Cloudflare R2 - S3-compatible object storage with zero egress fees.
sickn33/agentic-awesome-skills
Manage Cloudflare R2 buckets, lifecycle, and signed URLs. An agent skill from sickn33/agentic-awesome-skills.
sundial-org/awesome-openclaw-skills
Manage Cloudflare Workers, KV, D1, R2, and secrets using the Wrangler CLI.
fossasia/eventyay
A skill your agent uses when the user wants to provision infrastructure or third-party services using Stripe Projects.
mikehasa/golive-skill
Take an agent-written app from repo to live production on the user's OWN accounts, with providers they choose (hosting, database, auth, payments, email, domain/DNS).
FoundatioFx/Foundatio
A skill your agent uses when working with Foundatio infrastructure abstractions for .NET -- caching, queuing, messaging, file storage, distributed locking, or background jobs.
Rain-kl/OpenFlare
Provides comprehensive code review guidance for React 19, Vue 3, Angular 17+, Svelte 5, Rust, TypeScript, Java, PHP, Python, Django, Go, C/.NET, Kotlin, Swift, NestJS, C/C++, and more.
Rain-kl/OpenFlare
在选择日志方案、配置 slog、编写结构化日志语句或决定日志级别时使用。也适用于设置生产日志、为日志添加请求作用域上下文或从 log 迁移到 slog 的场景,即使用户未明确提及日志。不涵盖错误处理策略(参见 go-error-handling)。
Rain-kl/OpenFlare
Wavelet 项目专用:当新增或修改自定义业务 API、新增业务路由、新增 service 层核心逻辑时必须使用。本技能指导包职责划分、推荐文件结构、路由解耦、Swagger 文档生成与质量门禁验证。
Rain-kl/OpenFlare
Wavelet 项目专用:当新增或修改业务缓存(RAM/Redis/DB 三层读路径)、缓存失效、多节点 pub/sub 同步、或评估高频读是否应接入缓存时必须使用。本技能说明系统标准缓存框架、参考实现、禁止写法与分布式一致性要求。
Rain-kl/OpenFlare
Wavelet 项目专用:当新增或修改 ClickHouse 批量写入、接入 internal/infra/persistence/batchwriter、将业务域异步 flush 到分析表、迁移 riskcontrol/节点访问日志/可观测时序写入、或评估 asyncinsert 与背压策略时必须使用。本技能指导分层职责、各域独立 Writer 实例、repository 批量 API…
Rain-kl/OpenFlare
Wavelet 项目专用:当新增或修改数据库表结构、索引、初始化数据、系统配置 seed、模板 seed、默认管理员、goose SQL 迁移、internal/infra/persistence/migrator、ClickHouse 分析库 DDL 或数据库升级流程时必须使用。本技能指导在 internal/infra/persistence/migrator/goose 下编写…
Works with
Categories
Wavelet 项目专用:当业务需要上传文件、读取已上传文件、在 Worker/任务中程序化摄取字节流、选择存储引擎能力、或排查 wuploads / 文件统计异常时必须使用。本技能指导 storage 与 upload 分层、upload.Ingest 策略选型、前后端接入与禁止旁路写表。. File Upload is an agent skill from Rain-kl/OpenFlare.
File Upload fits situations like: tasks that involve File uploads and storage.
Run `npx skills add Rain-kl/OpenFlare --skill file-upload -a claude-code`. Or copy the skill folder (.agents/skills/file-upload in Rain-kl/OpenFlare) into .claude/skills/file-upload in your project. Claude Code loads it when a task matches its description.
Run `npx skills add Rain-kl/OpenFlare --skill file-upload -a codex`. Or copy the skill folder (.agents/skills/file-upload in Rain-kl/OpenFlare) into .agents/skills/file-upload in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Rain-kl/OpenFlare --skill file-upload -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/file-upload, .gemini/skills/file-upload, .github/skills/file-upload and .opencode/skills/file-upload in your project.
Going by SKILL.md and its folder, File Upload needs the command-line tools its instructions call (make and go).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
File Upload is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 1.7k tokens (SKILL.md is roughly 6.7k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with File Upload: Cloudflare R2 (einverne/dotfiles, 121 stars), Cloudflare R2 (sickn33/agentic-awesome-skills, 47k stars), Cloudflare 3 (sundial-org/awesome-openclaw-skills, 663 stars) and Stripe Projects (fossasia/eventyay, 1.7k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Rain-kl (a GitHub user) maintains it in Rain-kl/OpenFlare, which has 288 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on October 8, 2026.
Source: Rain-kl/OpenFlare on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.