Files
blueming3andClaude Opus 5.5 9f9e70ea2d feat: minis launch, cold-start watch and delivery watch skills
Three TikTok Minis skills for Codex and Claude Code, with the cold-start
playbook and five benchmark accounts through 88776-1 (2026-09-30).
install.sh links them into ~/.codex/skills and ~/.claude/skills.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 15:10:54 +08:00

14 KiB

工具调用序列(swads MCP)

令牌在管理台 /operations/mcp-tokens 按业务包授权:「基础」选「可操作」(上传、审核素材)、 「短剧 Minis 投放」选「可操作」(策源、建计划、推送、开停投、改预算)。要删 TikTok 上的计划,再勾 「允许删除 TikTok 上的计划(不可恢复)」;没勾时工具列表里看不到 campaign_delete,硬调返回 capability_denied。 swads_whoami 能看到自己有什么。

下面 A = 账户 external_account_id,T = tenant-global-001(线上会话用清单的 account.tenant_id)。

0. 账户与上下文

intake_list_accounts()                       # 运营选账户用
intake_upload_context(external_account_id=A, minis_id=<MINIS_ID>)
  → upload{tenant_id, game_id, market, language, ratio}
  → minis[]  identities[]
  → product_app_scope{…}                     # 每个文件上传都带它

minis_id 从 minis[] 里的 external_id 取(WISY mn06s5c3fwlgkdsw、WISH mnmq9weqvpsmx81w、SWAVE mnkfrtn8rwalt5qy、 VEYA mnkttq8epikrbri9);asset_inventory_id 每个户不一样,别从别的户抄。身份从 identities[] 取。

1. 上传一个文件(begin → PUT → finish → 轮询)

creative_upload_from_url(
  tenant_id=T, platforms=["tiktok"], platform="tiktok",
  media_kind="video"|"image",
  file_name=<name>, content_type=<mime>, size_bytes=<n>,
  content_sha256=<sha>,                       # 视频带;轮播不带
  game_id=upload.game_id, market=upload.market, language=upload.language,
  ratio="9:16", prompt="Material center ingest: <name>",
  external_account_id=A,                      # 不带会落进未归属池
  product_app_scope=<scope>,
  review_status="approved")                   # 运营自己剪的素材;策源只挂已审核的
  → {upload_id, object_key, upload_url, method, headers, reused, reused_file?}
  • reused: true:库里已有这个素材,reused_file.creative_factory_asset_id 就是 asset id,跳过后两步。
  • upload_url 为空且 reused: false:字节已在存储里(上次没完成的上传,或别的账户传过),不用 PUT,直接 finish。
  • 否则把结果存成 JSON 文件,scripts/upload_local_asset.sh <file> <json> 做 PUT(脚本会自己识别上面两种情况),然后:
creative_upload_from_url(…同 begin 的所有字段…, upload_id=…, object_key=…, external_account_id=A, product_app_scope=<scope>, review_status="approved")
creative_import_status(upload_id=…)          # 轮询到 status=ready → creative_factory_asset_id

入库是异步的:图片几十秒,视频要跑转码和多模态分析,几分钟是正常的。每 15 秒问一次, 20 分钟没 ready 才算失败。finalizing 期间什么都不用做——不要去读 creative-factory 的代码猜它在干什么。

finish 返回 409 且含 not in storage:存储里那个对象是半截的。不带 content_sha256 再 begin 一次拿全新票据,PUT,再 finish。 上传步骤失败就报原文给运营;不要去读代码、查端口、翻 runbook —— 那些不在这条链上。

2. 策源

intake_start_run(
  external_account_id=A,
  prompt=<brief>,                             # references/brief-templates.md
  asset_ids=[…],                              # 轮播按套顺序
  promoted_object={
    "object_type": "minis", "external_id": <MINIS_ID>, "name": <MINIS_NAME>,
    "subtype": "MINI_SERIES",
    "region_codes": ["AU","BR","KR","CA","MX","JP","TH","NZ","ID"],
    "landing_page_url": <剧集页>
  },
  locale="zh")
  → run_id
intake_run_status(run_id, external_account_id=A, wait_seconds=120)  # completed / failed / needs_clarification;没结束就再调
                                             # 不带账户回 403 external_account_id_required
intake_answer_clarification(run_id, request_id, answers={key: recommended_value})

线上会话里剧集页链接来自清单;本地会话开工前自己按剧名查清单,只问 missing 里的剧:

minis_episode_link_list(external_account_id=A, minis_id=<MINIS_ID>, titles=[<剧名>, …])
  → {found: [{title, landing_page_url}], missing: [<剧名>]}

运营在会话里补的链接先记进小程序的「剧→剧集页」清单再用(下一批自动查到):

minis_episode_link_set(external_account_id=A, minis_id=<MINIS_ID>, title=<剧名>, landing_page_url=<剧集页>)

线上会话开投放只看清单的 authorization.enable(见 online.md);campaign_set_delivery 在第 5 节。

completed 的 result.campaign_id / result.delivery_spec_id 是后面的入口。 失败原文在 failure;agent_output_invalid / repair budget 这类可以原样再发起一次。

2a. 图文配乐搜索(线上会话)

launch_carousel_music_search(keyword=<英文关键词>, external_account_id=A, tenant_id=T)
  → { tracks: [ { music_id, material_id, file_name, author, duration, style, sources, cover_url, url, liked, signature }, … ] }

只读(campaign:read),不消耗策源写权限。一部图文剧最多调 3 次,每次一个新关键词。file_name 是曲名 (name 恒为空,别读它);duration 是秒数;style 是粗粒度风格标签,常常是空的;TikTok 没给的项就是空—— 别编。挑曲、贴清单、等确认的规则见 references/online.md「怎么决定一行做什么」。选中的 id 用下面第 3 节的 campaign_workspace_patch(…fields={"music_id": …}) 逐条广告写。

3. 验形状与补丁

campaign_workspace(campaign_id)
  → campaign_name, current_revision.delivery_spec_id, current_revision.campaign_budget_optimization_enabled,
    groups[0].group_id, groups[0].ads[].{ad_id, creative_variants[]}
campaign_delete_draft(campaign_id)            # 形状不对时(只删没推过的草稿)
campaign_workspace_patch(campaign_id, delivery_spec_id, fields={"campaign_name": "SW-ADS-<产品>-<剧名>-<YYYYMMDD>"})
  # 纯图文计划在日期前多插一节 图文:"SW-ADS-<产品>-<剧名>-图文-<YYYYMMDD>"
campaign_workspace_patch(campaign_id, delivery_spec_id, fields={"campaign_budget_optimization_enabled": true})
campaign_workspace_patch(campaign_id, delivery_spec_id, group_id=G, fields={"daily_budget": 0, "group_budget": 0})
campaign_workspace_patch(campaign_id, delivery_spec_id, group_id=G, ad_id=AD, fields={"music_id": "<id>"})

每次返回 delivery_spec_id 都是新版本,链式传下去。

删已推送的计划(只在运营明确要删时;要 campaign:delete):

campaign_delete(campaign_id, external_account_id=A)   # 本地 + TikTok 一起删,广告组和广告一起没,不可恢复
  → {"campaign_id": …, "deleted": true}
campaign_detail(campaign_id, external_account_id=A)   # 必须 404 campaign not found,再删下一条

一次一条。504 超时不要直接重试:先 campaign_detail,还在再删。全删完 account_sync 一次。 2026-09-27 在 <external_account_id> 删 5 条暂停计划:每条几秒返回,campaign_detail 都 404, TikTok /campaign/get/ 读回 5 条 CAMPAIGN_STATUS_DELETE,同户在投的 5 条不受影响。

4. 推送

campaign_push_preview(campaign_id, delivery_spec_id, external_account_id=A)   # ready_to_push, gates
campaign_push(campaign_id, delivery_spec_id, external_account_id=A)
campaign_detail(campaign_id, external_account_id=A, wait_seconds=120)   # execution_runs 按 created_at 倒序取第一条
  → status ∈ succeeded | failed ;external_reference = TikTok campaign id

external_account_id 在这三步都不能省:账户只按每次调用的参数定,推送 不带账户会 409 campaign revision is bound to a different platform account。

5. 同步与启用

account_sync(external_account_id=A) → sync_run_id
account_sync_status(sync_run_id, wait_seconds=120)      # 到 completed*;推送全部结束后才同步
campaign_set_delivery(campaign_id, status="active", external_account_id=A)   # 三层 ENABLE;失败隔 20 秒重试,最多 4 次

6. 开投以后

campaign_set_budget(campaign_id, daily_budget=<USD>, external_account_id=A)              # 改日预算,直接写 TikTok,不用再同步
campaign_set_ad_delivery(campaign_id, external_ad_id=<TikTok ad_id>, status="stopped"|"active", external_account_id=A)
metrics_catalog(external_account_id=A)                                                   # 挑跑量素材前先看指标名
metrics_semantic_query(query={…}, external_account_id=A)                                # 按广告取花费/展示/点击/变现收入

两个写操作都要求这条计划已经被账户同步读回过,否则 404/409。

追加模式(运营明说「追加」时才用,默认是新建)

上传素材与新建相同(第 1、2 步)。之后不策源,直接在已推送计划上加广告:

campaign_list(external_account_id=A, search=<剧名>)          # 找到 campaign_id,确认 external_campaign_id 非空
campaign_workspace(campaign_id, external_account_id=A)        # 取当前 delivery_spec_id、group_id、一条现有 ad_id 作模板
campaign_workspace_add_ad(
  campaign_id, delivery_spec_id, group_id,
  ad_name="SW-ADS-<产品>-<剧名> Ad <N>",
  clone_from_ad_id=<模板广告 ad_id>,                            # 文案/落地页/CTA/身份照抄
  asset_ids=[...],                                             # 新素材,≤15,全视频或全图
  external_account_id=A)
  → ad_id, delivery_spec_id(新版本)
campaign_push_preview(campaign_id, delivery_spec_id, external_account_id=A)   # 看 counts.add.ads == 1
campaign_push(campaign_id, delivery_spec_id, external_account_id=A, scope="additions")
campaign_detail → execution_runs[0].status = succeeded
account_sync(A) → account_sync_status 到 completed
campaign_set_delivery(campaign_id, status="active", external_account_id=A)   # 级联 ENABLE,新广告才开始投

混搭时追加视频广告(SKILL.md「同组混搭」):模板取最后一条图文广告,加完立刻清掉复制来的配乐再推:

campaign_workspace_add_ad(…, ad_name="SW-ADS-<产品>-<剧名> Video 1", clone_from_ad_id=<最后一条图文广告>, asset_ids=[<视频>])
campaign_workspace_patch(campaign_id, delivery_spec_id, group_id=G, ad_id=<新 ad_id>, fields={"music_id": ""})
campaign_push_preview(…)   # counts.add.ads == 1
campaign_push(…, scope="additions")

追加必须 scope="additions":同步过的计划,工作台草稿里已有平台写回的值(状态、预算模式, Smart+ CBO 计划的日预算甚至会读回成 0),预览会列出 campaign/group/ad 的 update 行,ready_to_push 也会因 campaign_remote_drift_pending 是 false——这些都不是追加要管的。additions 只推那条 add, 不碰已有实体,也不等差异处理。预览里只核对 counts.add.ads 等于你追加的条数。

模板广告按 campaign_workspace 里广告的 platform_status 选(Smart+ 是 TikTok 的素材状态 active、stopped、 reviewing、blocked):有 active 的取一条;没有就取已在 TikTok 上、不是 blocked 的最后一条(常见于目标 计划本身还是暂停状态),核对表写明模板是回退取的;全是 blocked 就不追加——文案照抄过来大概率再被拒。超过 15 个素材就分成两条广告,Ad <N> 递增。核对表按广告列:新广告的 TikTok id、 素材数、状态。

线上会话在追加模式这里(第 5 步为止)不调 campaign_set_delivery(references/online.md):加完广告、 推送成功就停。是否开投放看清单的 authorization.enable——false 时线上会话从头到尾都没有这个工具,开投放是 操作员在「广告活动」页自己做的事;true 时白名单才多这一项,而且只在「全部做完」的核对之后、对这一轮刚建成的 每条计划(含这里追加的目标计划)各调一次,不是在追加模式这里单独调,也不重开前几轮已经开过的。

常见报错 → 含义

报错 含义 / 处理
authorization failed(策源) 素材没带 product_app_scope,重新上传
Creative asset is not approved(策源) 上传时没传 review_status="approved";用 creative_review_asset(decision="approved") 逐个补审,或重传
策源返回带 content_warnings(flagged by the content check 或 could not complete) 只提示不拦截,策源已发起;处理见 SKILL.md 第 3 步
素材的图被打了码 画面里有别人的头像/昵称,系统自动打码后投新版本;设计行为,核对表提一句
creative_asset_not_approved(追加) asset_ids 里有没过审的素材;上传时 review_status="approved",或 creative_review_asset 补审
campaign revision is bound to a different platform account 推送/详情没带 external_account_id;补上重调,不用重建
remote_identity_conflict(同步后工作台阻塞) Smart+ 广告有 ad_id 与 smart_plus_ad_id 两个 id;新建模式不受影响,写进报告即可。追加模式若因它 409,停下来写进核对表——是产品缺陷,不是重试能解决的
missing requested region BR 平台国家表偶发残缺被缓存;告诉运营重启 sidecar 或稍后重试
Unsupported image size. Please upload another image.(推送,视频) 视频尺寸不是标准 9:16,TikTok 取封面失败;照 SKILL.md「视频尺寸」把这几条放大裁成 1080×1920 重新上传。追加模式里失败的那条新增广告要先从工作台删掉再重加
asset_ids must be unique 轮播复用帧按字节复用了;去掉 content_sha256 重传那部剧
campaign_remote_drift_pending(推送) 工作台有未处理的平台差异;先 campaign_workspace 看,一般是运营在后台改过
not linked to a TikTok remote campaign(启用) 没同步;先 account_sync
Allowlist not enabled.(广告组) 平台侧瞬时闸门;同一载荷稍后重推
campaign_already_on_platform(删除) campaign_delete_draft 只删草稿;运营要删推过的计划就改用 campaign_delete
capability_denied / required_capability: campaign:delete 令牌没勾「计划·删除」;请运营在 /operations/mcp-tokens 勾上后重试,别换别的路子删
Campaign has been deleted(campaign_delete) 这条早在 TikTok 后台删了,只剩本地记录;account_sync 后工作台会出现待处理的平台删除,报给运营在控制台接受