mcpField
C
community-publish

community-publish

github.com/starchild-ai-agent云与 DevOps304.0k 次安装6 天前更新
代码仓库

关于 community-publish

community-publish 是用于管理项目公开发布、开源代码和社区或服务市场上架的技能,面向需要分享或推广项目的用户。它将 URL 发布、项目广场展示与付费服务上架视为独立操作,并提供各自的状态查询流程。

主要功能

  1. 01发布和撤销公开预览 URL
  2. 02将项目代码推送到 GitHub
  3. 03免费项目上架与撤架
  4. 04创建、审核和发布付费服务
  5. 05查询发布、审核及上架状态
  6. 06关联公开预览与开源代码

适用场景

  1. 01分享正在运行的服务预览
  2. 02将项目代码发布到 GitHub
  3. 03把免费项目展示在项目广场
  4. 04提交付费服务审核并上架

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/starchild-ai-agent/official-skills --skill community-publish

安装后在 Claude Code 中输入/community-publish确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

__init__.py
exports.py
lib/
gateway.py
install.py
manifest.py
validate.py

详细介绍

两个概念:发布(PUBLISH)与上架(LIST)——切勿混淆

此技能涉及两个本质不同的概念。混淆它们是给出错误答案的首要原因。

概念含义函数
发布(PUBLISH)让某项内容可访问——URL 可以正常使用,或代码已在 GitHub 上publish_preview、unpublish_preview、list_published_previews、open_source、remove_open_source、list_open_source、get_open_source、fork、validate_open_source
上架(LIST)让某项内容在市场中可发现/可购买免费:list_in_dashboard、unlist_from_dashboard、delete_listing、get_listing_status
付费:create_paid_service、submit_for_review、get_review_status、publish_service、unpublish_service、list_my_services、get_service、update_service、delete_service、restore_service
封面:upload_cover_image
浏览与消费者:explore_services、get_service_detail、get_service_pricing、get_service_reviews、write_service_review、favorite_service、unfavorite_service、get_favorite_services、get_user_services、get_service_earnings、get_earnings_summary、get_service_tags、get_featured_services
项目查询:explore_projects、my_projects、favorite_projects、get_tab_counts、get_popular_tags、get_user_projects、favorite_project、unfavorite_project

发布不会自动上架。 publish_preview() 只会分配 URL。open_source() 只会推送代码。两者都不会让项目在市场中可被发现——这需要另行主动调用 LIST 函数。

上架有两种流程
流程适用情况需要审核?需要定价?函数
免费上架免费项目,展示在 /projects 项目库中否否list_in_dashboard()
付费上架通过 x402 收取访问费用需要(6 项检查的审核,发布前必须通过)是(平台网络上的 USDC/USDG/USDC(Solana)——默认 Base+Monad+Robinhood+X Layer+Solana,遵循 all)create_paid_service() → submit_for_review()(必需)→ publish_service()

POST /api/services 不再接受 service_type: "free_project"。 免费上架通过 list_in_dashboard() 完成(项目库流程)。付费上架通过 create_paid_service() + 审核 + 发布完成(服务 API 流程)。

限时免费促销 ≠ 此技能的内容

付费服务上架后,所有者可以开展限时免费促销 (free_promo_start / free_promo_end)。这不属于市场上架工作, 此处也未实现。

概念内容位置
免费上架/projects 项目库中的免费项目此技能 → list_in_dashboard()
free_trial_count收费前的 N 次免费调用(仅限 pay_per_use)此技能 → create_paid_service(..., free_trial_count=N)
限时免费促销指定时间段:金额为 0 的验证,不进行结算/扣款x402 技能 → skills/x402/references/selling.md 的 限时免费促销章节

如果用户要求对已付费上架的项目“开限时免费 / free promo / free for N days”: 请阅读 x402 技能(自检 P1–P5,然后 PUT 免费促销)。不要在 community-publish 中编造 API,也不要将其与 free_trial_count 混淆。


可见性模型——回答“其他人能看到吗”之前请先阅读

项目的“公开性”由三个相互独立的开关决定,而不是一个:

开关关闭状态开启状态触发操作
URL 访问权限访问该 URL 会返回 404任何拥有该链接的人都能访问 URLpublish_preview / unpublish_preview
Gallery 可发现性不会显示在 /projects Gallery 中会显示在 Gallery 中list_in_dashboard / unlist_from_dashboard
Marketplace 上架状态不会显示在 Service Marketplace 中可被发现并购买create_paid_service + publish_service / unpublish_service

项目可以处于任意组合状态。切勿把这些状态统称为“是否已经公开”。

状态查询属于只读操作。 每当用户询问:

  • “现在能看到吗 / 已公开吗 / 已经可以被发现了吗?”
  • “上架了吗 / 在 dashboard 上吗 / 别人能看到吗”
  • “上架信息现在生效了吗?”

权威答案只能来自新调用的 get_listing_status(slug)(免费)或 get_review_status(service_id)(付费)。不要根据之前的操作推断。


项目类型——仅有三种

type含义是否符合 publish_preview() 的条件?
task定时 cron/interval 作业否(没有 HTTP 端口)
service长期运行的 HTTP 服务(dashboard、API、页面)是
script一次性脚本否(没有 HTTP 端口)

路由——将用户意图匹配到正确操作

A. 状态意图——用户想了解当前状态
示例说法操作
“现在能看到吗 / 已公开吗 / 已经可以被发现了吗 / 已上线吗?”get_listing_status(slug)
“上架了吗 / 在 dashboard 上吗 / 别人能不能看到”get_listing_status(slug)
“我发布了哪些 URL?” / “我发布了哪些”list_published_previews()
“有哪些代码是开源的?” / “都有哪些开源代码”list_open_source(...)
“我的服务” / “我的服务” / “我的付费服务”list_my_services()
“审核状态” / “审核通过了吗” / “审核状态”get_review_status(service_id)
B. 操作意图——用户想要更改状态
示例表述操作说明
"发布" / "分享" / "公开" / "公开" / "发布"(无限定条件)publish_preview(preview_id)仅分配 URL。不会自动切换上架状态。
"在仪表板上架" / "上架" / "在社区展示" / "设为可发现" / "发到广场"list_in_dashboard(slug)免费上架。预览必须已存在。
"上架付费服务" / "将其设为付费服务" / "上架到服务市场(付费)"create_paid_service(...) → submit_for_review()(推荐)→ publish_service()付费上架。需先配置 x402。
"发布并上架" / "发布并上架"publish_preview(),然后调用 list_in_dashboard()按顺序分两次调用。
"从仪表板移除" / "下架" / "取消上架" / "从展示墙隐藏"unlist_from_dashboard(slug)仅限免费上架。软取消上架(设置 is_public=false、review_status='unlisted',保留统计数据)。预览 URL 仍可访问。
"下架付费服务" / "取消发布服务"unpublish_service(service_id)仅限付费上架。
"开源" / "将代码开源" / "开源代码"open_source(project_dir)将代码推送到 GitHub。不会上架。
"取消发布 URL" / "移除链接" / "停止服务"unpublish_preview(slug)仅停止预览容器服务。不会影响上架状态(is_public/review_status 保持不变)。URL 将无法访问(404)。
"移除开源项目" / "从 GitHub 删除"remove_open_source(slug)
"分叉" / "安装别人的项目"fork(source)
"提交审核" / "提交审核"submit_for_review(service_id)仅限付费服务。必需——发布前必须通过审核。
"发布服务" / "发布我的服务"publish_service(service_id)仅限付费服务,且需处于已批准或已下架状态。
"更新服务" / "更新服务"update_service(service_id, ...)仅限付费服务。
"删除服务" / "删除服务"delete_service(service_id)仅限付费服务。
"删除项目" / "删除上架项目" / "从市场永久移除"delete_listing(slug)仅限免费上架。永久删除上架记录和 community_slugs 记录。URL 将无法访问(404)。同时从探索页和我的项目中移除。若要隐藏但不删除,请使用 unlist_from_dashboard()。
重新阅读后仍有歧义提出一个问题"你是要 (a) 发布公开 URL,(b) 免费上架到广场,(c) 付费上架到服务市场,还是 (d) 开源代码?"

通过 publisher: 绑定进行交叉链接

同一个项目同时拥有公开 URL 和开源代码时,你需要将两者配对,这样前端就会在上架卡片上显示“查看源代码”,并在代码卡片上显示“访问在线演示”。此技能通过在 project.yaml 中显式设置一次绑定来完成配对。

如何声明绑定

在 project.yaml 中添加 publisher: 块:

name: my-app
type: service
version: 1.0.0
publisher:
  code_slug: my-app               # OPTIONAL — defaults to manifest.name
  public_slug: my-app-pub         # OPTIONAL — URL suffix; defaults to code_slug

两个字段均为可选项。若省略,两者默认使用 manifest.name。

任一侧都可以先发布

网关会保留待处理条目,直到另一侧出现。没有顺序要求,也不需要手动链接。

顺序后续操作
先调用 open_source → 再调用 publish_previewopen_source 记录待处理条目;publish_preview 使用该条目并完成链接
先调用 publish_preview → 再调用 open_sourcepublish_preview 记录待处理条目(需要 publisher_code_slug 参数);open_source 使用该条目并完成链接
手动修复(少见)

如果配对配置错误(例如重命名后),请使用:

link_to_listing(listing_slug="2004-my-app-pub", code_slug="my-app")

架构

                community.iamstarchild.com (single gateway domain)
                              │
            ┌─────────────────┼─────────────────────┐
            │                 │                     │
   ┌────────▼─────────┐  ┌───▼────────────┐  ┌─────▼──────────┐
   │  /api/register   │  │/api/code-      │  │ /api/services  │
   │  /api/unregister │  │ projects/*     │  │ /api/projects- │
   │  /api/list       │  │ (GitHub-backed)│  │ query/*        │
   └────────┬─────────┘  └───┬────────────┘  └─────┬──────────┘
            │                │                     │
   ┌────────▼─────────┐  ┌───▼────────────┐  ┌─────▼──────────┐
   │ DB: route table  │  │ GitHub:        │  │ DB:            │
   │ + project_       │  │ community-     │  │ service_       │
   │   listings       │  │ projects repo  │  │ listings       │
   └──────────────────┘  └────────────────┘  │ (paid services)│
     publish_preview()    open_source()      └────────────────┘
                                              list_in_dashboard()
                                              create_paid_service()

发布:publish_preview() — 公共 URL

publish_preview(preview_id, slug="", title="", publisher_code_slug="")

将运行中的服务映射到 https://community.iamstarchild.com/{user_id}-{slug}。

  • preview_id:来自 preview(action='serve')。状态必须为 status=running。
  • slug:仅作为 URL 后缀(小写字母数字字符和连字符,3-50 个字符)。系统会自动添加 user_id 前缀。
  • title:列表项的显示名称。
  • publisher_code_slug:可选,用于与代码项目的 slug 建立交叉链接绑定。

返回 {"ok": True, "url": "...", "publisher": {...}, "hint": "...", "x402_detected": bool};当 x402_detected 为 true 时,还会附带 next_step 警告(完成付费列表项流程)。

限制:

  • publish_preview 不会创建付费列表项。 如果端点通过 x402 收费(返回 402),则发布流程尚未完成,除非你还运行 create_paid_service → submit_for_review(推荐)→ publish_service;否则,市场中不会显示任何内容,或会显示为“免费”。检测到计费时,返回值会标记这一点(x402_detected: true + next_step)。
  • 每位用户最多可发布 20 个预览(超出时网关会返回 429)。
  • 服务必须处于运行状态。容器停止后,服务将无法使用。
  • 仅在 Starchild Fly 容器内有效(需要 FLY_MACHINE_ID)。
  • 列表项默认不可见(is_public=false)。 publish_preview 成功后会分配 URL,但不会让该列表项可被发现。要让其可被发现,必须单独调用 list_in_dashboard()。

配套工具:

  • unpublish_preview(slug) — 停止预览容器服务。URL 将无法访问(404)。不会影响列表项状态(is_public/review_status 保持不变)。
  • list_published_previews() — 列出此用户当前发布的所有预览 URL。

发布:open_source() — 将代码推送到 GitHub

open_source(project_dir, version_bump="patch", message="")

将项目源代码推送到 GitHub 上的 community-projects/projects/{user_id}/{slug}/。

  • project_dir:例如 output/projects/my-task
  • version_bump:patch | minor | major | none
  • message:描述此版本更改内容的提交消息正文。 你(Agent)应始终根据本次会话中实际进行的代码更改撰写此消息;如果你知道更改了什么,就不要留空。尽量用一到三行简短描述面向用户的更改。

这只是发布操作,不会在市场中列出任何内容。 若要让项目可被发现,请在发布后单独调用 list_in_dashboard()(免费)或 create_paid_service()(付费)。

配套工具:

  • fork(source, dest_dir=None) — 在本地安装他人开源的项目
  • list_open_source(type=None, tag=None, user=None, q=None) — 浏览 GitHub 目录
  • get_open_source(source) — 获取某个项目的完整元数据
  • remove_open_source(slug) — 从 GitHub 目录中删除项目目录(仅限所有者)
  • validate_open_source(project_dir) — 发布前检查
项目结构

output/projects/{slug}/ 下的每个项目:

project.yaml      # metadata (name, version, type, env_required, sc_proxy, publisher)
PROJECT.md        # required sections: What / Required env / How to start / Outputs / Troubleshooting
.env.example      # all env vars with placeholder values
.gitignore        # secrets blacklist
src/
  ├── run.py       # for type=task (must start: # -*- task-system: v3 -*-)
  ├── index.html   # for type=service (or app.py + frontend)
  └── main.py      # for type=script

列出(免费):list_in_dashboard() — 显示在 /projects 展示页

list_in_dashboard(slug, name=None, description="", cover_url=None, tags=None)

让已发布的预览可在 https://community.iamstarchild.com/projects 公共展示页中被发现。若不执行此操作,预览 URL 虽然有效,但除了已知晓该 URL 的人,其他人都看不到。

  • slug:publish_preview() 返回的完整 slug(即 {user_id}-{suffix})。
  • name:展示页卡片的显示名称。默认为 slug。
  • description:不超过 500 个字符。
  • cover_url:必须位于 storage.googleapis.com、image.thum.io 或 api.microlink.io。要上传用户提供的图片,请先调用 upload_cover_image(slug, file_path) — 它会处理预签名 → GCS 上传 → 返回公开 URL。请参阅下文的封面图片上传。
  • tags:最多 5 个标签,每个不超过 20 个字符。

返回 {"ok": True, "listing": {...}, "url": "...", "dashboard_url": "..."}。

限制条件:

  • 必须先对同一个 slug 调用 publish_preview(),否则返回 404。
  • 幂等:再次调用时使用不同的名称或标签,会更新现有条目。
  • 无审核、无定价 — 这是免费列出流程。

配套方法:

  • unlist_from_dashboard(slug) — 将条目从展示页中隐藏(设置 is_public=false、review_status='unlisted',并保留浏览量和收藏数)。URL 仍然有效。要重新列出,请再次调用 list_in_dashboard()。
  • delete_listing(slug) — 永久删除条目行和 community_slugs 记录(移除浏览量和收藏数)。URL 将无法访问(404)。同时从探索页和“我的项目”中移除。若只需隐藏而不删除,请使用 unlist_from_dashboard()。
  • get_listing_status(slug) — 只读检查:返回 {ok, exists, is_public, listing}。

列出(付费):在服务市场列出付费服务

付费服务通过 x402 收取访问费用(在平台已启用的网络上进行链上 USDC/USDG 结算 — 默认包括 Base + Monad + Robinhood + X Layer + Solana,遵循 all 模式)。发布前必须通过自动化的 6 项审核 — 服务必须通过所有检查(获批),publish_service() 才能正常工作。API 调用示例可选,但建议提供。

多链支付网络(plans-280)

每项付费服务都有一个 networks_mode,用于决定买家可以在哪些链上付款:

networks_mode行为使用场景
"all"(默认)接受所有平台主网上的付款(目前包括 Base + Monad + Robinhood + X Layer + Solana;新增链会自动纳入,无需更改代码)。网关将 supported_networks 存储为 NULL,并在读取时展开。常见情况——不传入参数或设置 networks_mode="all"。
"custom"仅接受 supported_networks 中所列链上的付款(非空的 CAIP-2 ID 列表,例如 ["eip155:8453"])。不会随平台扩展而自动更新。用户明确表示“仅限 Base”/“仅限 Monad”/某个特定子集。

规则:

  • 默认值为 all。 切勿将单条链(如 ['eip155:8453'])硬编码为默认值,否则会重新引入旧版仅限 Base 的行为。
  • custom 必须提供非空的 supported_networks;空列表会被拒绝。
  • provider_wallet 是一个在所有已启用链上使用的 EVM 地址(Starchild facilitator 会在每条链上结算至同一地址)。它并非仅用于 Base。
  • 买家会看到 402 accepts 数组(每条已启用链对应一个条目,价格相同),并且每笔付款选择一条链——这是标准的 x402 多接受项,不是协议变更。
  • 结算所需的 Gas 由平台(Starchild facilitator)支付,而不是由服务提供方支付。
  • 要将现有服务切回 all:update_service(service_id, networks_mode="all")。
  • 要限制为某个子集:update_service(service_id, networks_mode="custom", supported_networks=["eip155:8453"])。

这与 x402 技能中 monetize 的默认值(all)一致。这两项技能采用相同的发布节奏——如果网关 402 accepts 和市场列表显示的链不同,则其中一方配置为了 custom,而另一方仍为 all。

服务生命周期与审核状态(审核仅供参考)
  create ──▶ published ──▶ submit_for_review ─▶ pending ─▶ approved / rejected
                │            (required before publishing — must pass to go live)
                │                                    │ fix via update_service(), re-check
                ▼                                    ▼
           publish_service() ─────────────────▶ listed ◀─▶ unlisted (owner takedown / re-list)
                                                     │
                                                     ▼
                                          unavailable ──▶ restore ──▶ listed

审核是自检,不是门槛:submit_for_review() 会运行 5 项自动检查(api_reachable、pricing_consistency、x402_payment、response_match、doc_completeness、examples_provided),并为所有者保存一份报告。 publish_service() 要求服务处于 approved 状态(重新上架时则为 unlisted)。发布前必须通过审核——先运行 submit_for_review(),以便在买家付款前发现失效的端点。rejected 报告不会阻止上架;对已处于 listed 状态的服务运行检查,也绝不会将其下架。

⚡ 场景选择决策树 — 创建任何付费服务前必须遵循

步骤 1:该服务是否有 Starchild 项目页面(通过 publish_preview() 发布)?

  • 是,且页面可免费浏览 → 流程 D。使用 service_type="paid_project" + project_slug。免费页面通过 publish_preview() 发布,付费 API 则位于 /api/* 路由后,由 x402 保护。上游应用在 / 提供免费介绍页,在 /api/* 提供付费 API。
  • 是,但整个页面都需要付费才能访问 → 流程 B(表单 1)。使用 service_type="paid_project" + project_slug。用户自行实现访问控制(付费墙 + 凭据验证)。请参阅 x402 技能中的“付费项目:两种形式”部分。
  • 否(独立 API,没有项目页面) → 流程 C 或 E。使用 service_type="paid_api",不带 project_slug。不要创建 index.html 或发布预览 — 没有免费页面。公开 URL 根路径会显示 x402 402 挑战或网关信息。

步骤 2:用户是否需要多个定价不同的 API 端点?

  • 是 → 在一次 create_paid_service() 调用中使用 api_endpoints 数组(流程 E)。不要创建多个独立服务。
  • 否 → 单个端点,仅使用 api_endpoint。

步骤 3:组合以上答案:

用户需求免费页面?多个端点?流程service_typeproject_slugapi_endpoints
付费订阅项目(整个网站都由付费墙保护)是否Bpaid_project必填—
独立付费 API(没有网页)否否Cpaid_api省略—
免费介绍页 + 付费 API是否Dpaid_project必填—
免费介绍页 + 多个付费 API是是D+Epaid_project必填必填
多个付费 API(没有网页)否是Epaid_api省略必填
⚠️ 常见的 Flow 混淆错误(来自真实事件)
错误问题所在正确做法
用户说“编写一个介绍页 AND 一个付费 API”,但 Agent 使用 paid_api 并另建一个项目预览服务和项目彼此脱节——市场中显示两个条目,一个免费(空白),一个付费使用 paid_project + project_slug(Flow D)。介绍页和 API 是同一个服务。
用户说“纯付费 API”,但 Agent 创建了 index.html 并发布预览多余的免费项目页面使市场杂乱;介绍页可能显示为空白/JSON不要创建 index.html 或调用 publish_preview。使用 paid_api(Flow C)。x402 网关的 402 响应就是 API 的自我说明。
用户说“多个 API 端点”,但 Agent 创建了 N 个独立服务市场中出现 N 个卡片,而非 1 个;端口冲突;上游混淆使用 api_endpoints 数组创建一个服务(Flow E)。
Agent 重用了另一个服务已占用的上游端口网关代理到了错误的上游——响应来自另一个服务每个服务必须使用唯一的上游端口。检查 .x402/services.json 是否存在冲突。
Agent 创建了带有 /docs 路由的 start.py,与上游的 /docs 路由冲突Flask AssertionError: View function mapping is overwriting an existing endpoint不要在 start.py 和上游应用中同时定义 /、/docs 或 /index.html 路由——只在其中一处定义。

关键规则:

  • 独立付费 API 不要传入 project_slug。 project_slug 仅适用于 paid_project——包括“免费网页 + 付费 API”模式(Flow D,使用 paid_project)。为独立的 paid_api 传入预览 slug 或不存在的 slug 会产生虚假关联——后端会静默清除它,但你一开始就不应该传入。
  • 路由规则:服务关联到项目页面 → paid_project;paid_api 仅用于没有项目页面的独立 API。 如果你的 API 有已发布的 Starchild 项目(落地页/仪表板),供用户免费浏览,请使用 service_type="paid_project" + project_slug——这会将服务合并到市场中的项目卡片。如果没有免费项目页面,请使用 paid_api,并且不要设置 project_slug。传入 paid_api + project_slug 时,create_paid_service() 会自动升级为 paid_project(响应中会附带 project_slug_warning)——最终列表项始终是 paid_project。
  • project_slug 必须是包含用户前缀的完整已发布 slug(例如 33-my-app),并且必须对应 project_listings 中的现有行(即必须先调用 publish_preview() + list_in_dashboard())。
  • api_endpoints 适用于具有多个不同价格端点的服务;每个端点都有自己的 path、price 和可选的 label。
  • 设置了 project_slug 的项目不会显示在“免费”选项卡中——它会移至“全部”和“付费”选项卡。
  • 合并到项目卡片后的可见性: 当已上架服务的 project_slug 指向一个公开项目时,该服务会折叠到统一市场视图中的项目卡片内。因此,该服务不会作为独立条目出现在 explore_services() 或 list_my_services() 中——这是预期行为,不代表上架失败。用户仍可通过项目卡片、get_service(service_id) 和 get_user_services(user_id) 使用并购买该服务,而且可通过 explore_marketplace()(统一信息流)发现该服务。要确认已合并的服务已上架,请检查 get_service() → review_status == "listed",而不是查看 explore_services() 的结果。
  • 用户要求提供多个 API 时,创建一个带有 api_endpoints 的服务——不要创建多个独立服务。参见 Flow E。
标签 — 用于市场筛选的预定义标签标识

创建付费服务时,传入 tags,并从下方预定义列表中选择 1–3 个标签标识。Agent 应根据服务的名称和描述选择最相关的标签。标签用于市场筛选和发现,可替代旧的 category 字段。

预定义标签标识(选择 1–3 个最相关的标签):

领域标签
DeFi 与交易defi、trading、dex、dex-swap、lending、lending-yield、yield、staking、derivatives、bridge
链上数据onchain-data、token-analytics、price-feed、wallet、wallet-portfolio、nft
AI 与 MLai-inference、llm-inference、text-analysis、image-generation、text-to-speech、video-transcription、translation
Web 与数据web-search、web-scraping、screenshot-pdf、news-feed、seo、data-service、data-storage、analytics
安全与合规aml-sanctions、security、privacy、threat-detection、agent-safety、agent-trust
基础设施smart-contract、oracle、zk-proofs、layer2、mev、compute、storage、developer-tools、identity、payment、payments
社交与媒体social、social-media、gaming、metaverse
金融(传统金融)stock-equity、sec-edgar、real-estate、insurance、prediction-market
其他dao、governance、email-sms、weather、geolocation、healthcare、agriculture、astrology-fortune、rwa、research-academic、legal-gov、launchpad

示例:DeFi 价格 API → tags=["defi", "price-feed", "trading"]

流程 B — 付费项目上架

付费项目会对访问收费。有两种形式——两者都使用 service_type="paid_project" + project_slug:

形式 1:整个页面位于付费墙后 — 页面本身需要付费才能访问。 用户自行实现访问控制(带凭据验证的类登录组件)。平台提供 x402 支付协议; 用户实现付费墙 UI 和凭据逻辑。实现详情请参阅 x402 技能中的“付费项目:两种形式”部分,以及“如何使用 Agent 付款” 文档模板。

形式 2:免费页面 + 付费 API — 页面可免费浏览,API 调用需要付费。 这就是下面的流程 D。上游应用在 / 提供免费的介绍页面,并在 /api/* 提供付费 API。

两种形式采用相同的模式——唯一的区别在于用户需要实现什么(形式 1 需要实现付费墙拦截器,形式 2 无需额外实现)。

  1. 准备一个正在运行的项目,并提供一个公开 URL(通过 publish_preview())。
  2. 使用 x402 技能为项目的访问端点配置收费。 未付款时,端点必须返回 402 Payment Required,付款后返回 200 + 数据。
  3. 创建服务记录:
create_paid_service(
    name="Premium Trading Signals",
    description="Real-time trading signals with on-chain confirmation.",
    service_type="paid_project",
    tags=["trading", "onchain-data"],
    project_slug="33-premium-signals",  # FULL published slug WITH user prefix (the URL path segment)
    api_endpoint="https://community.iamstarchild.com/33-premium-signals",
    provider_wallet="0xAbC...yourEvmWallet",  # EVM address for Base/Monad/Robinhood/X Layer; Solana address auto-fetched from Privy wallet
    pricing_model="monthly",
    price=10,
    service_description="Subscribers get a dashboard with live trading signals.",
)

付费项目必填字段:name、description、service_type、 project_slug、api_endpoint、provider_wallet、pricing_model、price、 service_description。推荐填写:tags(用于市场筛选的 1–3 个预定义标签 slug)。

⚠️ project_slug 必须是包含用户前缀的完整已发布 slug (例如 33-premium-signals,必须与项目 URL https://community.iamstarchild.com/<slug>/ 中的路径段完全一致)。当未设置 api_endpoint 时,网关会将 API 端点推导为 publicUrl + "/" + project_slug,因此,不带前缀或错误的 slug 会导致端点推导失败,并破坏 项目↔服务关联。可通过 update_service(service_id, project_slug="<full-slug>") 修复现有记录——无需重新上架。

  1. 必需:运行自动审核 — 付费服务必须通过审核 才能发布。若市场上列出的端点不可用,你可能会在察觉之前就收到买家的款项:
submit_for_review(service_id)   # kicks off 6 automated checks asynchronously
get_review_status(service_id)   # poll until no longer pending, then show the
                                # report to the user — THEY decide what to fix

rejected 报告会阻止发布。阅读 review_feedback + latest_task.checks,使用 update_service() 修复,然后 重新运行 submit_for_review(),直到审核通过。

  1. 审核通过后(approved)即可发布:
publish_service(service_id)

对已上架的服务也可以稍后再次运行该检查——它绝不会将服务下架。

流程 C — 付费 API 上架

付费 API 是已经实现 x402 收费的外部 API 服务。

⚠️ 独立付费 API 不要传入 project_slug。 project_slug 仅适用于 paid_project(必填),或“免费网页 + 付费 API” 模式(流程 D,其中存在已发布的 Starchild 项目页面)。对于没有关联免费项目页面的独立 paid_api,请完全省略 project_slug。 后端会根据 project_listings 验证 project_slug,并会静默清除不存在的 slug,但你本就不应该传入它。

⚠️ 如果 API 属于已发布的 Starchild 项目,请选择 paid_project。 如果你的 API 有通过 publish_preview() 发布的着陆页 / 仪表板(即它作为项目存在于 community.iamstarchild.com),请使用 service_type="paid_project"

  • project_slug=<full published slug WITH user prefix>(流程 B)——不要使用 paid_api。project_slug 用于 将服务关联到项目卡片(价格标签、交叉导航)。paid_api 上架项没有项目关联,因此项目卡片仍会显示“免费”。 仅当 API 确实是外部 / 独立 API,且没有 Starchild 项目时,才使用 paid_api。 忘记关联了吗?使用 update 更新服务记录中的 project_slug——无需重新上架。
  1. 提供启用了 x402 的 API — 未付款时,端点必须返回 402;收到有效的 X-PAYMENT 标头后,返回 200 和数据。如果需要,请使用 x402 skill 实现。

    确保 Starchild 记录购买信息

    为了让 Starchild 市场跟踪购买、收益和使用统计信息,请根据你的 facilitator 设置选择以下两种方式之一:

    选项 A — 使用 Starchild facilitator(推荐)

    将 x402 中间件的 facilitator URL 设置为:

    https://starchild-x402-facilitator.fly.dev
    

    结算成功后,Starchild facilitator 会自动回调 community-gateway 以记录购买信息。无需额外设置 — 使用默认的 create_paid_service() 调用继续执行第 2 步。

    选项 B — 使用自己的 facilitator + 代理模式

    如果你使用自己的 facilitator(或第三方 facilitator),Starchild 将无法接收结算回调。创建服务记录时(第 2 步),请改为传入 source="manual":

    create_paid_service(
        ...,
        source="manual",   # ← enables proxy mode
    )
    

    这会让市场为你的 API 生成一个代理 URL:

    https://community.iamstarchild.com/proxy/{service_id}/...
    

    用户通过此代理 URL 访问你的 API。代理会透明地将请求转发到你的真实 api_endpoint,并在付款成功时(HTTP 200 且带有 payment-signature 标头)自动在 Starchild 数据库中记录购买信息。你无需更改 facilitator URL,也无需设置任何回调。

    402 响应要求(审核时检查):

    • 402 响应正文必须包含 pricingModel 字段(平台格式)。
    • payTo 必须是你的实际收款 EVM 钱包地址(在所有启用的链上使用)。
    • accepts 数组中每条启用的链对应一个条目(多种接受方式);买家每笔付款选择一条链。每个条目的 amount(USDC,6 位小数)相同 — 此版本的平台不支持按链设置不同价格。
    • 响应必须是客户端能够解析的有效 x402 挑战。
  2. 创建服务记录(service_type = "paid_api"):

create_paid_service(
    name="On-chain Whale Tracker API",
    description="REST API returning real-time whale wallet movements across 12 chains.",
    service_type="paid_api",
    tags=["onchain-data", "wallet-portfolio", "trading"],
    api_endpoint="https://api.example.com/v1/whales",
    provider_wallet="0xAbC...yourEvmWallet",  # EVM address for Base/Monad/Robinhood/X Layer; Solana address auto-fetched from Privy wallet
    pricing_model="pay_per_use",
    price=0.01,
    free_trial_count=3,
    api_documentation="# Whale Tracker API\n\n## GET /v1/whales\n\nReturns recent whale transactions.\n\n### Parameters\n| name | type | required | description |\n|---|---|---|---|\n| chain | string | no | Filter by chain id (default: all) |\n| limit | int | no | Max results (default: 50, max: 200) |\n\n### Response\n```json\n[{\"hash\":\"0x...\",\"from\":\"0x...\",\"to\":\"0x...\",\"value\":\"1000000\",\"token\":\"USDC\",\"chain\":\"base\",\"ts\":1700000000}]\n```",
    example_request="curl https://api.example.com/v1/whales?chain=base&limit=10",
    example_response='[{"hash":"0xabc...","from":"0x111...","to":"0x222...","value":"5000000","token":"USDC","chain":"base","ts":1700000000}]',
)

付费 API 必填字段:name、description、service_type、api_endpoint、provider_wallet、pricing_model、price、api_documentation。 推荐字段(可选):example_request、example_response(可提升买家体验)。 可选字段:free_trial_count(仅适用于 pay_per_use)、 source(代理模式下设为 "manual" — 参见上文第 1 步选项 B;Starchild facilitator 默认模式下省略)、 cover_url(自定义封面图片 URL — 必须位于 storage.googleapis.com 或其他允许的域名上;如果未提供,Agent 应根据服务名称和描述自动生成合适的封面图片,通过图片上传服务上传,并传入生成的 URL)。

付费服务的封面图片

付费服务不会自动生成封面图片(与会自动截取屏幕截图的免费项目不同)。在 create_paid_service() 中传入 cover_url — 图片必须位于 storage.googleapis.com(或 image.thum.io / api.microlink.io)。

⚠️ 必须:当用户提供图片,或你需要设置封面时,调用 upload_cover_image(slug, file_path)。 此函数会处理完整流程:预签名 URL → 压缩 → 上传到 GCS → 返回 storage.googleapis.com 公共 URL。请勿使用 imgur、数据 URI 或任何其他托管服务 — 网关会验证域名。

如果用户未提供图片,请生成一张(例如使用图片生成 skill),将其保存在本地,然后调用 upload_cover_image()。

之后也可以使用 update_service(cover_url=...) 更改封面。

完整参考请参见封面图片上传。

  1. 运行审核 → 与流程 B 第 4 步相同(发布前必须完成)。
  2. 发布 → 与流程 B 第 5 步相同(状态必须为已批准)。
流程 D — 免费网页 + 付费 API(混合模式)

你的项目有一个免费落地页(通过 publish_preview() 发布),还有一个付费 API 端点。用户可以免费浏览项目页面,但 API 调用需要付费。 市场会显示一张合并卡片,其中包含“访问项目”和“调用 API”按钮。

  1. 发布项目:通过 publish_preview() 发布,这会创建免费落地页。
  2. 为 API 端点配置 x402 收费(例如,/api/random 返回 402)。
  3. 创建服务记录,并设置 service_type="paid_project" + project_slug:
create_paid_service(
    name="Random9 API",
    description="Random 9-digit number API. Free docs page + paid API calls.",
    service_type="paid_project",
    tags=["developer-tools"],
    project_slug="33-random9-api",  # FULL slug WITH user prefix — links to the free project page
    api_endpoint="https://community.iamstarchild.com/33-random9-api/api/random",
    provider_wallet="0xAbC...yourEvmWallet",  # EVM address for Base/Monad/Robinhood/X Layer; Solana address auto-fetched from Privy wallet
    pricing_model="pay_per_use",
    price=0.01,
    service_description="Paid access to the Random9 API endpoint; the docs page stays free.",  # required for paid_project
    api_documentation="# Random9 API\n## GET /api/random\nReturns a random 9-digit number.",
    example_request="curl https://community.iamstarchild.com/33-random9-api/api/random",
    example_response='{"random":"482917365","digits":9}',
)

project_slug 会将此服务合并到项目卡片中。项目页面(/) 保持免费;只有 API 端点(/api/random)需要付费。

注意:如果同时传入 service_type="paid_api" 和 project_slug, create_paid_service() 会自动将其升级为 paid_project,并返回 project_slug_warning——存储的列表项始终为 paid_project。直接传入 paid_project(如上所示)是规范写法。

  1. 发布 + 可选的自检——与流程 B 的步骤 4–5 相同。
流程 E — 多端点 API

你的服务有多个价格不同的 API 端点(例如,基础版 $0.01,高级版 $0.10)。 每个端点都会在市场详情视图中单独列出。

⚠️ 当用户要求提供多个 API 时,请创建一个包含 api_endpoints 的服务——不要创建多个独立服务。 例如,如果用户说“开发三个付费 API 并将它们上架”,不要调用 create_paid_service() 三次。应创建一个服务,其 api_endpoints 数组中包含所有三个端点。 这样用户就能在一张统一的市场卡片中查看并购买各个端点。 只有当这些 API 确实无关时(领域、受众或定价模式不同),才创建多个服务。

  1. 配置 x402 收费,并为每个路由单独定价:

    # Default networks_mode is "all" (Base + Monad). Omit --networks to follow
    # the platform mainnet set; pass --networks eip155:8453 only if the user
    # explicitly wants to restrict to a single chain.
    python3 skills/x402/scripts/monetize.py --name my-api --upstream-port 5173 \
      --mode pay_per_use --price 0.01 \
      --route "GET /api/basic=$0.01" --route "GET /api/premium=$0.10" \
      --route "POST /api/batch=$0.50" \
      --facilitator $FAC
    
  2. 创建服务记录,并设置 api_endpoints:

create_paid_service(
    name="Data API Service",
    description="Multiple API endpoints at different prices.",
    service_type="paid_api",
    tags=["data-service"],
    api_endpoint="https://example.com/api/basic",  # primary endpoint for review
    api_endpoints=[
        {"path": "GET /api/basic", "price": 0.01, "label": "Basic Query"},
        {"path": "GET /api/premium", "price": 0.10, "label": "Premium Query"},
        {"path": "POST /api/batch", "price": 0.50, "label": "Batch Process"},
    ],
    provider_wallet="0xAbC...yourEvmWallet",  # EVM address for Base/Monad/Robinhood/X Layer; Solana address auto-fetched from Privy wallet
    pricing_model="pay_per_use",
    price=0.01,  # price of the primary/default endpoint
    api_documentation="# Data API\n## GET /api/basic\nBasic data.\n## GET /api/premium\nPremium analytics.",
    example_request="curl https://example.com/api/basic",
    example_response='{"data":"basic market info"}',
)

你可以结合流程 D 和流程 E:使用 service_type="paid_project" + project_slug 并搭配 api_endpoints,将免费项目页面与多端点定价关联起来。 市场会显示一张合并的项目卡片,并在详情视图中列出各个端点。

  1. 发布 + 可选的自检——与流程 B 的步骤 4–5 相同。
审核检查(6 项自动检查——发布必需)

submit_for_review() 会针对 api_endpoint 运行这些检查;服务必须通过所有检查才能获批发布。针对已上架服务运行检查不会将其下架:

#检查验证内容
1api_reachable未发送 X-PAYMENT 标头时,端点会返回 402 Payment Required
2pricing_consistency402 响应中 accepts 的 amount 与你声明的 price 一致(以 USDC 基础单位计)。使用多链 accepts(每条已启用的链对应一个条目)时,每个条目都必须携带相同的 amount——当前版本的平台不支持按链定价。
3x402_payment完成有效的 x402 支付后,端点会返回 200 + 数据
4response_match实际响应的关键字段与 example_response 一致
5doc_completenessapi_documentation 包含参数说明、响应格式和至少一个示例

检查 #5 会通过关键词匹配:文档必须包含一个“Response”(或“响应格式”) 章节,且标题下方有实际正文——空章节无法通过审核。 service_description(paid_project)和 api_documentation / example_request / example_response(paid_api)会在调用时由 create_paid_service() 强制校验; 如果这些字段缺失,会在创建无法审核的记录之前报错。

常见的驳回原因:

  • 402 响应的 amount 与声明的 price 不一致(小数位错误/单位错误)。
  • 端点完全不返回 402(未接入 x402,或向未经身份验证的请求返回 200)。
  • example_response 与 API 在支付后实际返回的内容不一致。
  • 文档缺少参数表或响应架构。
定价模式

所有付费服务均使用 x402 exact 支付方案(通过平台已启用的网络在链上结算 USDC/USDG——默认情况下为 Base + Monad + Robinhood + X Layer + Solana,遵循 networks_mode="all")。结算 Gas 费由 Starchild facilitator 支付,而非服务提供方。

pricing_model含义x402 行为典型用途
pay_per_use按次收费每个携带有效 X-PAYMENT 的请求 → 结算(扣费)API 调用
lifetime一次性买断首次付款时结算;后续请求验证此前的结算记录,不再扣费一次性购买
monthly月度订阅每个计费月结算一次;到期后重新扣费Web 订阅、API 月度套餐
weekly周度订阅每 7 天结算一次;到期后重新扣费短期订阅
quarterly季度订阅每 90 天结算一次;到期后重新扣费季度套餐
yearly年度订阅每 365 天结算一次;到期后重新扣费年度套餐(通常有折扣)
prepaid预付余额用户通过 deposit-settle 存入资金(一次链上交易),之后每次调用都从链下余额中扣款(无 Gas 费)高频小额支付

free_trial_count 仅适用于 pay_per_use——允许先免费调用 N 次,再开始收费。 它不是按日历时间计算的免费促销。限时免费(free_promo_*)→ x402 技能(selling.md → 限时免费促销)。

多种方案(多种定价选项)

一项服务可以同时提供多种定价方案(例如:按周 + 按月 + 按年)。创建服务时传入 pricing_options 数组:

create_paid_service(
    ...,
    pricing_options=[
        {"pricing_model": "weekly", "price": 3, "is_default": True, "label": "Weekly"},
        {"pricing_model": "monthly", "price": 10, "label": "Monthly"},
        {"pricing_model": "yearly", "price": 90, "label": "Yearly (Save 42%)"},
    ],
)

规则:

  • pay_per_use 不能与其他定价模式组合。
  • 订阅模式(按周/按月/按季度/按年)可以自由组合。
  • lifetime 和 prepaid 可以与订阅模式组合。
  • 必须将一个选项标记为 is_default: True(或者自动将第一个选项标记为默认选项)。
  • 服务的 pricing_model 和 price 字段会自动与默认选项同步。

多方案的 402 要求:服务的 x402 中间件必须支持 X-Pricing-Model 标头——当客户端发送 X-Pricing-Model: yearly 时,402 响应必须返回按年方案的价格。审核会逐一验证每个方案的 402 金额。

参考:完整规范见 x402-facilitator/docs/pricing-models.md。

限制可使用的支付链(自定义网络)

默认的 networks_mode="all" 会使用平台的主网集合(Base + Monad + Robinhood + X Layer + Solana)。只有当用户明确提出要求(“只接受 Base”“不接受 Monad 支付”等)时,才限制为部分网络:

# Create a service that ONLY accepts Base USDC (not Monad)
create_paid_service(
    ...,
    networks_mode="custom",
    supported_networks=["eip155:8453"],   # CAIP-2 chain id; non-empty required
)

# Switch an existing service from all → custom (only Monad)
update_service(service_id, networks_mode="custom", supported_networks=["eip155:143"])

# Switch back to all (follow platform mainnets; clears the custom list)
update_service(service_id, networks_mode="all")

不要默认使用 custom + ['eip155:8453']。 这会重新引入旧版仅支持 Base 的行为。默认值为 all;只有用户明确要求限制时才使用 custom。


服务示例(API 调用示例)——建议提供,但非必需

API 调用示例非必需,但强烈建议提供。示例会展示 API 的返回内容——在服务详情页中以可折叠的请求/响应对呈现。没有示例的服务仍可通过审核,但审核报告会注明缺少示例。

建议的列表顺序:

1. create_paid_service(...)                     → creates the service
2. set_service_examples(service_id, examples)   → recommended (improves buyer experience)
3. submit_for_review(service_id)                → required before publishing
4. publish_service(service_id)                  → go live (requires approved)

添加示例:

set_service_examples("service-uuid", [
    {
        "title": "Query BTC Price",
        "description": "Get current Bitcoin price in USD",
        "request": 'curl -X GET "https://api.example.com/v1/price?symbol=BTC"',
        "response": '{"symbol": "BTC", "price": 67234.56, "currency": "USD"}'
    },
    {
        "title": "Query ETH Price",
        "request": 'curl -X GET "https://api.example.com/v1/price?symbol=ETH"',
        "response": '{"symbol": "ETH", "price": 3456.78, "currency": "USD"}'
    }
])

清除示例(较少需要——set_service_examples 会替换全部示例):

clear_service_examples("service-uuid")

最佳实践:

  • 添加 2-5 个示例,涵盖最常见的使用场景
  • 使用能说明场景的描述性标题
  • 加入实际的请求参数和响应数据
  • 展示简单和复杂的使用模式
  • set_service_examples() 会替换全部示例——每次都传入完整列表

这取代了传入 create_paid_service() 的旧版单一 example_request / example_response 字段。包含旧版字段的服务仍可通过审核(向后兼容),但新服务应使用 set_service_examples() 展示更丰富的多场景示例。

付费服务管理函数
函数用途
create_paid_service(...)创建服务记录(已发布状态)
set_service_examples(service_id, examples)设置 API 调用示例(可选,建议提供)——替换全部示例
clear_service_examples(service_id)移除全部 API 调用示例
submit_for_review(service_id)运行包含 6 项检查的自动审核(发布前必需)
get_review_status(service_id)轮询审核进度和各项检查详情
publish_service(service_id)正式上线(需要处于已批准或未列出状态)
unpublish_service(service_id)下架(已列出 → 未列出)
list_my_services(cursor, limit)列出你的服务(分页)
get_service(service_id)按 ID 获取一项服务
update_service(service_id, **fields)更新服务字段(例如,修正被拒绝后的问题)
delete_service(service_id)永久删除一项服务
restore_service(service_id)将不可用的服务恢复为已列出状态
市场浏览和消费者功能

这些函数可让 Agent 浏览服务市场、阅读评论、撰写评论、管理收藏并查看收益,与 Web 前端的功能相同。

函数用途
explore_marketplace(search, paid_only, ...)⭐ 统一浏览——首先使用此函数查找付费服务/API。 项目卡片和独立服务显示在同一信息流中(与 Web 上的 All/Paid 标签页相同);这是唯一能搜索并显示合并到公开项目卡片中的服务的途径。条目包含 type:service(使用 id)或 project(付费卡片包含 service_id)——将其传入 get_service_detail()
explore_services(search, sort, tags, ...)仅浏览独立服务条目(服务 API)。⚠️ 合并到公开项目卡片中的服务不会显示在此处——如需完整覆盖范围,请使用 explore_marketplace()
get_service_detail(service_id)获取已发布服务的公开详情(包含文档,并增加浏览量)
get_service_pricing(service_id)获取经过验证的定价,并进行实时 x402 检查
get_service_reviews(service_id, sort)列出服务评论(公开)
write_service_review(service_id, rating, comment)提交或更新评论(必须先购买或使用过服务)
get_user_services(user_id)获取用户已发布的付费服务(公开,用于个人资料展示)
favorite_service(service_id)将服务添加到收藏夹
unfavorite_service(service_id)从收藏夹中移除服务
get_favorite_services(cursor, limit)列出当前用户收藏的服务
get_service_purchase_status(service_id)检查当前用户是否已购买或使用过服务
get_service_earnings(service_id)单项服务的收益统计(仅限所有者)
get_earnings_summary()所有服务的收益汇总(仅限所有者)
get_service_onchain_records(service_id)链上 USDC 结算记录(仅限所有者)

在 bash 代码块中使用

python3 - <<'EOF'
import sys
# Prefer the registered skill tools (read this SKILL.md via read_file to
# load them) over hand-written imports of exports.py. If you DO need a
# direct import: the directory name has a HYPHEN, so dotted imports
# (`from skills.community_publish import ...`) raise ModuleNotFoundError.
# Use this sys.path pattern (or importlib.util.spec_from_file_location).
sys.path.insert(0, "/data/workspace/skills/community-publish")
from exports import (
    # PUBLISH: public URL
    publish_preview, unpublish_preview, list_published_previews,
    # PUBLISH: open source code
    open_source, remove_open_source, fork,
    list_open_source, get_open_source, validate_open_source,
    # LIST: free (project gallery)
    list_in_dashboard, unlist_from_dashboard, get_listing_status,
    # LIST: paid (service marketplace)
    create_paid_service, submit_for_review, get_review_status,
    publish_service, unpublish_service,
    list_my_services, get_service, update_service, delete_service,
    restore_service, set_service_examples, clear_service_examples,
    # MARKETPLACE: browse + consumer actions
    explore_marketplace, explore_services, get_service_detail,
    get_service_pricing, get_service_reviews, write_service_review,
    get_user_services, favorite_service, unfavorite_service,
    get_favorite_services, get_service_purchase_status,
    get_service_earnings, get_earnings_summary, get_service_onchain_records,
    # Manual repair (rare)
    link_to_listing,
)

# Step 1: Publish the URL
print(publish_preview(preview_id="my-app-a3f1", slug="my-app"))

# Step 2a: Free listing — show on gallery
print(list_in_dashboard(slug="33-my-app", name="My App", description="A cool app"))

# OR Step 2b: Paid listing — create service + review + publish
res = create_paid_service(
    name="My Paid App",
    description="Premium features",
    service_type="paid_project",
    tags=["developer-tools"],
    project_slug="33-my-app",  # full published slug WITH user prefix
    api_endpoint="https://community.iamstarchild.com/33-my-app",
    provider_wallet="0xAbC...",
    pricing_model="monthly",
    price=5,
    service_description="Subscribers get premium features.",
)
print(res)
# Then: publish_service(res["service_id"]) — optionally submit_for_review() first for a self-check report
EOF

行为规则

  • 在 open_source() 之前显示差异。在 validate_open_source 之后,总结即将推送的内容并请求确认。例外情况:用户明确要求“无需确认直接发布”,或重新发布已知正常的项目。
  • 分叉时绝不自动运行 setup.sh。显示命令,让用户确认。
  • 分叉时始终一次性收集所有环境变量。读取项目的 env_required,与 workspace/.env 进行比较,然后仅针对缺失的键调用一次 request_env_input。
  • 发布必须经过审核。publish_service() 要求状态为 approved——始终先运行 submit_for_review()。向用户展示报告;如果被拒绝,则通过 update_service() 修正并重新运行 submit_for_review()。对已上架服务运行检查不会将其下架。
  • api_endpoint 必须是 x402 收费端点。对于付费项目,这是项目的公开 URL。对于付费 API,这是外部 API URL。审核人员会访问此 URL,并预期收到 402。
  • 价格单位为 USDC。402 响应中的 accepts.amount 使用基础单位(USDC 为 6 位小数)。$0.01 的价格对应 amount: "10000"。此处不匹配是审核失败的首要原因。
  • 不要捏造审核结果。始终调用 get_review_status() 进行检查——绝不要因为提交了审核就假定审核已通过。
  • 不要混淆发布与上架。publish_preview() 会分配一个 URL。list_in_dashboard() / create_paid_service() 会使服务可被发现。这是两个独立且需明确执行的步骤。
  • Slug 规则:小写字母、数字和连字符,长度为 3-50 个字符,且不能以连字符开头或结尾。
  • 版本规则(open_source):严格遵循语义化版本规范。重新发布相同版本会被拒绝。
  • URL ≠ 代码 ≠ 上架条目:公开 URL 失效不会移除开源代码或市场上架条目,反之亦然。它们彼此独立。
  • 独立的 paid_api 服务不要传入 project_slug。project_slug 仅适用于 paid_project——包括“免费网页 + 付费 API”模式(Flow D 使用 paid_project;传入 paid_api + project_slug 会自动升级为 paid_project,并产生 project_slug_warning)。为独立 API 传入预览 slug 或不存在的 slug 会创建虚假关联。后端会静默清除不存在的 slug,但除非用户明确希望将免费项目页面与付费 API 关联,否则不应传入 project_slug。
  • 用户要求多个 API 时,创建一个包含 api_endpoints 的服务。不要为相关 API 多次调用 create_paid_service()。使用 api_endpoints 数组在单个服务中列出所有端点(Flow E)。只有当这些 API 确实互不相关时(域名、受众或定价模式不同),才创建多个服务。
  • 支付网络默认设为 all。绝不要将单条链(例如 ['eip155:8453'])硬编码为默认值——这会重新引入旧版仅支持 Base 的行为。省略 networks_mode / supported_networks(或传入 networks_mode="all"),让服务遵循平台的主网集合(Base + Monad + Robinhood + X Layer + Solana;新增链会自动启用)。仅当用户明确要求限制为部分网络(“仅 Base”“仅 Monad”等)时,才使用 networks_mode="custom" + 非空的 supported_networks。
  • provider_wallet 是一个在所有已启用 EVM 链上使用的 EVM 地址。Starchild facilitator 在每条 EVM 链上都会将结算款发送到同一地址;它并非仅用于 Base。不要向用户将其描述为“Base 钱包”。对于 Solana 支付,平台会自动使用用户的 Privy Solana 钱包地址(provider_sol_wallet)。如果用户未明确提供 Solana 地址,create_paid_service() 会自动从 Privy 钱包获取。没有 Solana 地址的服务将不接受 Solana 支付(Solana 不会包含在 402 accepts 列表中)。
  • 结算 Gas 费用由平台支付,而非服务提供者。不要告知服务提供者需要准备 ETH/MON 来支付结算 Gas。

Common gotchas

症状原因修复方法
publish_preview:Preview not foundpreview_id 错误,或服务已停止检查 /data/previews.json,使用 preview(action='serve') 重启
publish_preview:429 Too many published previews已达到每位用户 20 个的网关上限先使用 unpublish_preview() 取消发布一个旧预览
publish_preview:FLY_MACHINE_ID not set在本地运行,而不是在 Starchild 容器中运行只有在生产容器中才能发布 URL
list_in_dashboard:404 No preview found此 slug 尚未运行 publish_preview()先调用 publish_preview()
open_source:400 Validation failed: env names not in .env.example在 env_required 中列出了 MY_KEY,但忘了在 .env.example 中添加将缺少的密钥添加到 .env.example
open_source:400 Possible secret detected密钥扫描器发现了看起来像真实密钥的 API 密钥将其移至环境变量;.env.example 中的值应为 your-key-here
发布后,市场显示服务为免费或未显示只运行了 publish_preview()——发布 URL ≠ 发布付费服务完成整个流程:create_paid_service → publish_service
create_paid_service:400 Free services should be published through the Project publish flow尝试使用了 service_type: "free_project"免费项目请使用 list_in_dashboard(),而不是 create_paid_service()
publish_service:400 not in a publishable state服务已上架、不可用或已删除检查 get_service() 状态;如果为 unavailable,则使用 restore_service()
submit_for_review:400 Free services do not require review服务记录创建为 FREE 类型——付费载荷是手动构建的(缺少 service_type/钱包/定价),而不是通过 create_paid_service() 创建的删除后使用 create_paid_service() 重新创建(所有付费字段都是必需的位置参数,因此通过该函数不会出现此问题)
审核被拒:pricing_consistency 未通过402 响应中的 amount 与声明的 price 不匹配确保 amount = price * 1000000(USDC 为 6 位小数)
审核被拒:api_reachable 未通过端点未返回 402先在端点接入 x402 收费
create_paid_service 响应中包含 project_slug_warning为 paid_api 传入了 project_slug,但该 slug 不存在于 project_listings 中后端已自动将其清除。如果这是独立 API,请勿传入 project_slug。如果你想使用 Flow D,请先对项目运行 publish_preview() + list_in_dashboard(),然后使用正确的 slug 调用 update_service()。
删除再创建同名服务多次后,create_paid_service 返回 500 Failed to create service已删除的服务仍会保留其 slug(软删除),而 slug 生成只会尝试有限数量的后缀——反复删除并用同一名称重建会耗尽这些后缀不要等待后重试——该名称将永久无法使用。请改用不同的服务名称,或使用 restore_service(service_id) + update_service(),而不是删除后重建
用户要求“多个 API”,却创建了多个服务每个 API 都调用了一次 create_paid_service(),而不是使用 api_endpoints使用 Flow E:调用一次 create_paid_service() 并传入 api_endpoints=[...] 数组。只有在 API 确实互不相关时才拆分为多个服务。
外部 API(使用自有 facilitator)的购买未被记录创建服务时未设置 source="manual",因此不会生成代理 URL,Starchild 也无法观测到付款改用 Starchild facilitator(选项 A),或使用 source="manual" 重新创建服务(选项 B)
source="manual" 服务的代理 URL 返回 502Starchild 服务器无法访问 api_endpoint URL确认外部 API 可公开访问,且未被防火墙拦截
市场显示的链与 402 accepts 中的链不一致(反之亦然)服务的 networks_mode 与 x402 网关的 accepts 不同步——例如,上架设置为 all(Base+Monad),但 x402 网关使用 --networks eip155:8453(自定义,仅 Base)进行收费重新运行 x402 技能的 monetize,不带 --networks(以遵循 all);或者使用 update_service(service_id, networks_mode="custom", supported_networks=[...]) 以匹配网关。两者必须一致。
create_paid_service / update_service 因“supported_networks must be a non-empty list”而拒绝请求传入了 networks_mode="custom",但 supported_networks 缺失、为空或为 None传入非空的 CAIP-2 id 列表(例如 ["eip155:8453"]),或切换到 networks_mode="all"(默认值)以接受所有平台主网。
买家无法在 Monad 上付款(402 中没有 Monad accepts),但上架信息显示 Monadx402 网关在多链版本发布前就已设置收费,或使用了 --networks eip155:8453重新运行 monetize,不带 --networks,这样 402 的 accepts 数组就会包含每条平台主网。上架的 all 模式没有问题;网关侧的配置已过时。
在一条链上结算失败,但在另一条链上正常Starchild facilitator 的结算器在该链上 Gas 不足(Base 需要 ETH,Monad 需要 MON)这是平台侧问题(Gas 由平台补贴)。另一条链仍可正常使用。请向运维团队报告——不要要求服务提供方补充 Gas。

封面图片上传流程

⚠️ 必须 — 每次需要设置或更改封面图片时,都要阅读本节。

网关会验证 cover_url 的域名。仅接受 storage.googleapis.com、image.thum.io 和 api.microlink.io。不要使用 imgur、数据 URI 或任何其他托管服务。

快速路径:upload_cover_image()
from skills.community_publish.exports import upload_cover_image

result = upload_cover_image("my-slug", "/path/to/image.png")
# result = {"ok": True, "public_url": "https://storage.googleapis.com/..."}

# Then use the URL:
list_in_dashboard("my-slug", name="My Project", cover_url=result["public_url"])
# or:
create_paid_service(..., cover_url=result["public_url"])
# or:
update_service(service_id, cover_url=result["public_url"])
upload_cover_image() 的内部操作
  1. 获取预签名 URL — 使用 slug、content_type、file_size 调用 POST /api/projects/cover/presign(通过 Authorization: Bearer $CONTAINER_JWT 传入容器 JWT)
  2. 上传 — 将原始图片字节 PUT 到 GCS V4 签名 URL
  3. 返回 — storage.googleapis.com 上的 public_url
支持的格式
  • image/png、image/jpeg、image/webp
  • 最大 2MB — 如有需要,请在上传前压缩
如果用户提供了大尺寸图片
# Compress first (PIL example)
from PIL import Image
import io

img = Image.open("/path/to/large.png")
img.thumbnail((1200, 630))  # reasonable cover dimensions
buf = io.BytesIO()
img.save(buf, format="JPEG", quality=85)
buf.seek(0)

# Save compressed version
compressed_path = "/tmp/cover_compressed.jpg"
with open(compressed_path, "wb") as f:
    f.write(buf.getvalue())

# Upload
result = upload_cover_image("my-slug", compressed_path)
常见错误
错误失败原因修正方法
将 imgur URL 用作 cover_url域名不在允许列表中(项目/内部路由会以 400 拒绝请求)使用 upload_cover_image() → GCS URL
将数据 URI 作为 cover_url 传入网关返回 500(URL 过长/不是有效 URL)保存到文件,然后使用 upload_cover_image()
使用 thum.io 截取预览页面的屏幕截图无法从公网访问内部端口上的预览页面使用实际图片文件调用 upload_cover_image()
未阅读知识库文档缺少 GCS 配置、路径约定和域名规则相关背景信息务必查阅 starchild-knowledge/starchild-community-gateway/service-cover-upload.md

前端展示 — 项目与服务

Web 前端为社区内容提供了两个独立的弹窗:

弹窗内容类型展示内容查询函数
ProjectMarketplaceModal免费项目卡片网格:封面图片、名称、描述、标签、浏览量、收藏量explore_projects()、my_projects()、favorite_projects()、get_tab_counts()、get_popular_tags()、get_user_projects()、favorite_project()、unfavorite_project()
MarketplaceModal付费服务(x402)服务卡片:定价、评分、购买按钮explore_services()、list_my_services()、get_service_detail()、get_service_tags()、get_featured_services()

两者也会显示在 AgentProfile 中(“项目”标签页/“服务”标签页)和着陆页上。

每个项目都有一个直接 URL(基于路径的 /{slug} 或子域名 {slug}.community.iamstarchild.com)。/projects 和 /services 页面是由前端渲染的浏览页面。

项目查询函数
函数数据范围用途
explore_projects(search, tag, sort, limit, cursor)公开浏览所有公开项目。排序方式:all(最新)或 trending。
my_projects(tag)个人列出当前用户已发布的项目及其统计数据。
favorite_projects(tag, limit, cursor)个人列出当前用户收藏的项目。
get_tab_counts()个人获取各标签页的计数(explore、mine、favorites、purchased、services_mine、services_favorites)。
get_popular_tags()公开获取热门项目标签,用于筛选。
get_user_projects(user_id, limit)公开获取特定用户的公开项目(用于个人资料页面)。
favorite_project(slug)个人将项目添加到当前用户的收藏夹。
unfavorite_project(slug)个人将项目从当前用户的收藏夹中移除。
服务查询函数
函数数据范围用途
explore_services(search, sort, tags, ...)公开仅浏览独立付费服务。
list_my_services(cursor, limit)个人列出当前用户的付费服务。
get_service_detail(service_id)公开获取已发布服务的公开详情。
get_service_pricing(service_id)公开获取经过验证的定价信息(实时 x402 验证)。
get_service_reviews(service_id, sort, cursor, limit)公开列出服务的评价。
write_service_review(service_id, rating, comment, is_anonymous)个人提交或更新评价(upsert)。
get_service_tags()公开获取带有 i18n 名称的预定义服务标签。
get_featured_services()公开获取用于首页展示的精选服务。
get_user_services(user_id, limit)公开获取特定用户已发布的付费服务。
favorite_service(service_id)个人将服务添加到收藏。
unfavorite_service(service_id)个人将服务从收藏中移除。
get_favorite_services(cursor, limit)个人列出当前用户收藏的服务。
get_service_purchase_status(service_id)个人检查用户是否购买或使用过某项服务。
get_service_earnings(service_id)个人获取服务的收入统计数据(仅限所有者)。
get_earnings_summary()个人获取所有服务的收入汇总。
get_service_onchain_records(service_id, cursor, limit)个人获取链上交易记录(仅限所有者)。

参考资料

  • lib/manifest.py — project.yaml 解析器/写入器及 semver 辅助函数
  • lib/validate.py — 本地发布前验证(与网关侧检查一致)
  • lib/install.py — 特定类型的安装处理程序(task/service/script)
  • lib/gateway.py — 用于 /api/register(URL)、/api/code-projects/*(代码)、/api/projects-query/*(免费列表 + 浏览)、/api/services/*(付费列表)、/api/projects/cover/presign(封面上传)的 HTTP 客户端

评论

支持 Markdown