Install
openclaw skills install @gavin-yyc/artifact-shareUse when you need to share static web content (HTML/CSS/JS/images) via a publicly accessible URL — uploading generated files, creating shareable pages, or deploying single-page web artifacts
openclaw skills install @gavin-yyc/artifact-shareArtifact Share 是面向 Agent 的静态资源上传与分享服务。上传 HTML/CSS/JS/图片等文件,立即获取可分享的公开 URL。
BASE_URL 值为 https://artifact-share.youthol.top。
下文所有 {BASE_URL} 均指此配置值。
首次使用必须注册,获取 API Key 后才能进行任何上传操作。注册是一次性的,之后所有操作复用同一个 API Key。
Agent 场景下无需邮箱和密码,使用设备 ID(device_id)注册即可。用户后续可在 Web 平台绑定邮箱和设置昵称。
Web 管理页面地址为 BASE_URL。
Agent 在注册前需要生成一个设备标识。推荐方式:
username@hostname(通过 whoami + hostname 命令获取)~/.artifact-share-device-id,后续复用device_id 规则:4-64 字符,仅允许字母、数字、下划线、点、连字符和 @。
curl -s -X POST {BASE_URL}/api/v1/register \
-H "Content-Type: application/json" \
-d '{"device_id": "yangyc@macbook-pro", "nickname": "Yang"}'
nickname 为可选字段,用于 Web 平台展示,最多 50 字符。
{
"user_id": "uid_xxxx",
"api_key": "ak_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
用户还会获得一个自动生成的 slug(路径标识),用于分享 URL。如注册后 GET /api/v1/me 可查看完整信息包括 slug。
如果使用相同的 device_id 再次注册,会返回错误:
{
"error": {
"code": "DEVICE_ALREADY_REGISTERED",
"message": "该设备已注册,请使用已有的 API Key"
}
}
注册成功后必须立即保存 API Key,它是后续所有操作的唯一凭证。
唯一存储位置:~/.config/artifact-share/config.yml
device_id: yangyc@macbook-pro
api_key: ak_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
base_url: https://artifact-share.youthol.top
注册成功后,Agent 必须将 device_id、api_key 和 base_url 写入此文件。后续所有操作从该文件读取 api_key。
写入命令:
mkdir -p ~/.config/artifact-share
cat > ~/.config/artifact-share/config.yml << EOF
device_id: {YOUR_DEVICE_ID}
api_key: {YOUR_API_KEY}
base_url: {BASE_URL}
EOF
⚠️ 注意事项:
在执行任何操作之前,先查询本地配置文件获取 API Key:
cat ~/.config/artifact-share/config.yml
判断逻辑:
api_key → 读取 api_key 值,用于后续 API 调用的 X-API-Key header示例:
用户要求上传文件时,Agent 应先检查
~/.config/artifact-share/config.yml:
- 有 api_key → 直接使用该 key 上传
- 没有 api_key → 告知用户"还未注册,我先帮你注册",然后注册并保存到 config.yml
创建项目并获取分享 URL。文件可选——可以只填项目名先建空项目、稍后再上传文件;也可以同时上传单个文件或 ZIP 压缩包。默认创建的项目不带密码。
仅名称创建(占位项目,稍后上传):
curl -s -X POST {BASE_URL}/api/v1/projects \
-H "X-API-Key: {YOUR_API_KEY}" \
-F "name=my-page"
响应 url 为项目根 {BASE_URL}/s/{slug}/{pid};在上传文件前访问会 404,上传文件(见第 2 节)后即可访问。
单文件上传:
curl -s -X POST {BASE_URL}/api/v1/projects \
-H "X-API-Key: {YOUR_API_KEY}" \
-F "file=@/local/path/to/aa.html"
ZIP 包上传(多文件项目):
curl -s -X POST {BASE_URL}/api/v1/projects \
-H "X-API-Key: {YOUR_API_KEY}" \
-F "file=@/local/path/to/project.zip"
带密码上传(可选):
curl -s -X POST {BASE_URL}/api/v1/projects \
-H "X-API-Key: {YOUR_API_KEY}" \
-F "password=my-secret-password" \
-F "file=@/local/path/to/project.zip"
name 与 password 均为可选字段:
name 在带文件上传时不传会自动从文件名派生(如 aa.html → 项目名 aa.html);不带文件时必填。项目名仅作展示,不参与分享 URL——URL 直接以本地文件名为结尾,本地叫什么、访问路径就是什么。password 不传或为空则项目公开访问;设置了密码则访问者需先输入密码才能查看。响应:
{
"project_id": "pid_xxxx",
"name": "aa.html",
"url": "{BASE_URL}/s/{slug}/pid_xxxx/aa.html"
}
url 末尾就是上传文件的原始文件名;project_id 是当前项目的唯一标识,后续要在同一项目下反复修改文件时复用它(见第 2 节)。
项目名规则: 1-60 字符;自动去除首尾空格;不允许控制字符(含制表符/换行/NUL 等)。带文件上传时可选(从文件名派生),仅建空项目时必填。仅作展示,不在 URL 中出现。
支持文件类型: html, css, js, png, jpg, jpeg, gif, svg, webp, ico, bmp, woff, woff2, ttf, otf, eot
免费限制: 每用户最多 1 个项目,每项目最多 5 个文件,项目总大小不超过 5MB(单次上传不超过 3MB)。
替换或新增项目中的文件。
curl -s -X PUT {BASE_URL}/api/v1/projects/{PROJECT_ID}/files \
-H "X-API-Key: {YOUR_API_KEY}" \
-F "file_path=css/style.css" \
-F "file=@/local/path/to/new-style.css"
响应:
{
"project_id": "pid_xxxx",
"name": "aa.html",
"url": "{BASE_URL}/s/{slug}/pid_xxxx/aa.html"
}
响应回显 project_id 与 name,便于调用方在同一个对话里持续编辑:只要复用同一个 project_id 并保持 file_path 不变,重新上传后 URL 保持不变、内容被替换——无需新建项目。
GET /api/v1/projects/{PROJECT_ID}/files查看某个项目内的所有文件及其分享 URL(每个文件的 URL 末尾即其原始路径)。
curl -s {BASE_URL}/api/v1/projects/{PROJECT_ID}/files \
-H "X-API-Key: {YOUR_API_KEY}"
响应:
{
"files": [
{
"id": "file-uuid",
"file_path": "aa.html",
"url": "{BASE_URL}/s/{slug}/{PROJECT_ID}/aa.html",
"size": 1234,
"mime_type": "text/html; charset=utf-8",
"access_count": 0,
"created_at": "2026-06-23T12:00:00Z"
}
]
}
DELETE /api/v1/projects/{PROJECT_ID}/files/{FILE_ID}删除项目中的单个文件(同时清理存储与记录,并重算项目大小/文件数)。FILE_ID 来自第 3 节列表响应的 id。操作不可恢复。
curl -s -X DELETE {BASE_URL}/api/v1/projects/{PROJECT_ID}/files/{FILE_ID} \
-H "X-API-Key: {YOUR_API_KEY}"
响应:
{
"message": "deleted"
}
查看当前用户的所有项目。
curl -s {BASE_URL}/api/v1/projects \
-H "X-API-Key: {YOUR_API_KEY}"
响应:
{
"projects": [
{
"id": "pid_xxxx",
"name": "my-project",
"url": "{BASE_URL}/s/{slug}/pid_xxxx",
"has_password": false,
"size": 1234,
"file_count": 3,
"created_at": "2026-06-23T12:00:00Z"
}
]
}
删除项目及其所有文件,操作不可恢复。
curl -s -X DELETE {BASE_URL}/api/v1/projects/{PROJECT_ID} \
-H "X-API-Key: {YOUR_API_KEY}"
响应:
{
"message": "deleted"
}
PUT /api/v1/projects/{PROJECT_ID}/password设置或取消项目的访问密码。空字符串表示取消密码保护(公开访问)。
# 设置密码
curl -s -X PUT {BASE_URL}/api/v1/projects/{PROJECT_ID}/password \
-H "X-API-Key: {YOUR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"password": "new-secret"}'
# 取消密码(改为公开访问)
curl -s -X PUT {BASE_URL}/api/v1/projects/{PROJECT_ID}/password \
-H "X-API-Key: {YOUR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"password": ""}'
响应:
{
"message": "密码已更新"
}
分享 URL 格式:{BASE_URL}/s/{slug}/{pid}/{filename}
{slug} 是用户的路径标识(注册时自动生成,暂不支持修改){pid} 是项目唯一标识(如 pid_xxxx,全局唯一,不暴露内部 user_id){filename} 是上传文件的原始路径——本地叫什么,URL 就是访问根地址 {BASE_URL}/s/{slug}/{pid} 时,服务器动态挑选入口文件返回(优先 index.html,否则第一个 .html,否则第一个文件)。直接访问 {BASE_URL}/s/{slug}/{pid}/{filename} 则返回该文件本身;HTML 里的相对资源引用会自然解析到同前缀的兄弟文件,无需额外重写。
/s/{slug}/{pid},覆盖该项目下所有文件),后续访问自动放行所有资源都走 /s/{slug}/{pid}/... 同一前缀代理转发,用户始终只看到 {BASE_URL}/s/... 的干净路径,七牛 CDN 链接不会暴露。
密码验证接口:POST /s/{slug}/{pid}/verify(仅接受 JSON 请求,body {"password":"..."},成功返回 {"redirect":"/s/{slug}/{pid}"} 并下发 HttpOnly cookie)
GET /api/v1/me获取当前登录用户的信息,包括邮箱绑定状态。
curl -s {BASE_URL}/api/v1/me \
-H "X-API-Key: {YOUR_API_KEY}"
响应:
{
"id": "uid_xxxx",
"device_id": "yangyc@macbook-pro",
"nickname": "Yang",
"email": "",
"slug": "7e3e7bb2",
"plan": "free",
"has_bound_email": false,
"created_at": "2026-06-23T12:00:00Z"
}
slug 是用户在分享 URL 中的路径标识,注册时自动生成,暂不支持修改。
POST /api/v1/bind-email/send向指定邮箱发送 6 位数字验证码(5 分钟有效,60 秒内不可重复发送)。
curl -s -X POST {BASE_URL}/api/v1/bind-email/send \
-H "X-API-Key: {YOUR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
响应:
{
"message": "验证码已发送",
"expires": "2026-06-23T12:05:00Z"
}
前置条件: 当前用户未绑定邮箱。如已绑定,返回 EMAIL_ALREADY_BOUND。
POST /api/v1/bind-email/verify验证验证码并绑定邮箱。验证成功后 has_bound_email 变为 true。
curl -s -X POST {BASE_URL}/api/v1/bind-email/verify \
-H "X-API-Key: {YOUR_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com", "code": "123456"}'
响应:
{
"message": "邮箱绑定成功",
"email": "user@example.com"
}
限制: 验证码最多尝试 5 次,超过后需重新发送。
GET /api/v1/qr?url=...把任意文本/URL 编码成 base64 PNG 二维码(用于让用户扫码在手机上调试分享页面)。公开接口,无需 API Key。
curl -s "{BASE_URL}/api/v1/qr?url=https://artifact-share.youthol.top/s/{slug}/{pid}/aa.html"
响应:
{
"qr_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
}
qr_base64 是可直接内联的 data URI,在 Markdown/HTML 里以  渲染即可扫码。限制: 内容最长 2000 字符,超出返回 INVALID_INPUT。
1. 查询 API Key → cat ~/.config/artifact-share/config.yml
├─ 有 api_key → 直接使用,进入步骤 3
└─ 无 api_key → 执行步骤 2 注册
2. 注册 → POST /api/v1/register {device_id, nickname} → 获取 API Key → 写入 ~/.config/artifact-share/config.yml
3. 登录 → GET /api/v1/me → 检查 has_bound_email
4. 绑定邮箱(如果 has_bound_email=false,可选):
a. 发送验证码 → POST /api/v1/bind-email/send {email}
b. 验证并绑定 → POST /api/v1/bind-email/verify {email, code}
5. 上传 → POST /api/v1/projects → 获取 project_id + name + 分享 URL(可仅传 name 建空项目稍后上传,或带 file 直接上传;URL 以本地文件名结尾)
6. 分享 → 将 URL 与项目名返回给用户 → 调 GET /api/v1/qr?url=<URL> 取 qr_base64 一并返回(扫码调试)→ 同时附上 Web 管理后台地址 {BASE_URL}(用 API Key 登录可在线管理)→ 用户在浏览器中打开
7. 更新 → 复用同一 project_id 调用 PUT /api/v1/projects/{id}/files → 内容替换、URL 保持不变
8. 删除 → DELETE /api/v1/projects/{id} → 移除项目
上传成功后,从响应中提取分享 URL 并明确展示给用户,同时告知当前项目名与 project_id,并提醒用户可在同一项目下反复修改文件,以及在线管理后台地址:
create_project 的 JSON 响应url、name、project_id 字段url 即为分享链接,无需手动拼接)GET /api/v1/qr?url=<分享URL>(见第 12 节,公开免鉴权),取 qr_base64,以  一并返回给用户,方便手机扫码调试{BASE_URL},提示用户可用自己的 API Key 登录在浏览器中在线管理项目与文件(上传/替换/删除、设置访问密码、查看用量等)示例 — Agent 上传后应返回给用户的信息:
✅ 已上传成功!你的页面已上线: 🔗 {BASE_URL}/s/{slug}/pid_xxxx/aa.html 📁 当前项目:aa.html(project_id: pid_xxxx) 📱 扫码在手机上预览:
🌐 在线管理后台:{BASE_URL}(用你的 API Key 登录,可在浏览器中上传/替换/删除文件、设置访问密码、查看用量)
💡 后续如需修改/修复这个页面,无需重新创建项目——直接把新版本上传到同一项目即可,URL 保持不变:
PUT /api/v1/projects/pid_xxxx/files -F file_path=aa.html -F file=@新版本.html
带密码项目:
✅ 已上传成功!你的页面已上线: 🔗 {BASE_URL}/s/{slug}/pid_xxxx/aa.html 📁 当前项目:aa.html(project_id: pid_xxxx) 🔒 访问密码:my-secret-password 📱 扫码在手机上预览:
🌐 在线管理后台:{BASE_URL}(用你的 API Key 登录,可在浏览器中管理项目与文件)
💡 修改页面请复用同一 project_id 重新上传,URL 不变。
如果项目设置了密码,应告知用户访问者需要输入密码才能查看。
| Error Code | 含义 | HTTP Status |
|---|---|---|
| INVALID_FILE_TYPE | 文件类型不在白名单 | 400 |
| FILE_TOO_LARGE | 单次上传文件超过 3MB | 400 |
| PROJECT_LIMIT_EXCEEDED | 项目数超过 1 个 | 403 |
| INVALID_API_KEY | API Key 无效或缺失 | 401 |
| PROJECT_NOT_FOUND | 项目不存在 | 404 |
| PROJECT_NOT_OWNER | 不是项目所有者 | 403 |
| EMAIL_EXISTS | 邮箱已绑定 | 409 |
| DEVICE_ALREADY_REGISTERED | 该设备已注册 | 409 |
| EMAIL_ALREADY_BOUND | 当前账号已绑定邮箱 | 409 |
| EMAIL_BOUND_BY_OTHER | 邮箱已被其他账号绑定 | 409 |
| CODE_INVALID | 验证码错误 | 400 |
| CODE_EXPIRED | 验证码已过期 | 400 |
| CODE_MAX_ATTEMPTS | 验证码尝试次数超限 | 400 |
| CODE_SEND_TOO_FREQUENT | 验证码发送过于频繁 | 429 |
| INVALID_INPUT | 输入验证失败 | 400 |
| WRONG_PASSWORD | 访问密码不正确 | 401 |
| RATE_LIMIT_EXCEEDED | 请求频率超限 (>60/min) | 429 |
| Mistake | Fix |
|---|---|
| 未注册就尝试上传 | 先检查 ~/.config/artifact-share/config.yml,无 api_key 则先注册 |
| 丢失 API Key | 注册后立即写入 config.yml,同一 device_id 只能注册一次 |
| device_id 格式错误 | 仅允许字母、数字、下划线、点和连字符,长度 4-64 |
| 上传不支持的文件类型 | 检查白名单:html/css/js/png/jpg/jpeg/gif/svg/webp/ico/bmp/woff/woff2/ttf/otf/eot |
| 项目名含大写/特殊字符 | 项目名 1-60 字符(自动 trim、拒控制字符);带文件上传时可省略(从文件名派生),仅建空项目时必填 |
| 项目超过大小限制 | 项目总大小 ≤ 5MB(5 文件以内);单次上传 ≤ 3MB |
| 每次修改都新建项目 | 复用 project_id 走 PUT /projects/{id}/files,URL 不变;只有需要全新独立页面时才新建 |
| 上传后未返回分享链接给用户 | 必须提取 URL 并明确展示给用户 |