About fast-ship
fast-ship is an agent skill for querying and managing project issues through the Fast Ship API, including workflow status, collaboration details, and pull request links. It uses a script to read the API key and documents endpoint permissions and write verification requirements.
Key features
- 01Query and create issues
- 02Update workflow status
- 03Record collaboration consensus and summaries
- 04Link and sync pull requests
- 05Read screenshot annotations and crops
- 06Send API requests with a key-handling script
Use cases
- 01Filter and work on project issues
- 02Record decisions or completion summaries
- 03Link implementation pull requests and refresh their status
- 04Review interface feedback through screenshot annotations
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ gitbobobo/ skills --skill fast-shipAfter installing, type/fast-shipin Claude Code to confirm it loaded.
Bundled filesreferences/api.mdscripts/fast-ship-api.mjs
Details
From the project READMEFast Ship API
| 想做什么 | 实际调用 |
|---|---|
| 在 issue 上留言/发评论/写完成总结 | PUT /api/issues/:iid/collab/summary(API Key 发评论必 40301) |
| 标记完成 | PUT /api/issues/:iid/internal-meta 置 workflow_status=done(不是 state) |
| 关闭 issue | 不可——仅 JWT,API Key 传 state 必 40301 |
| 开始做了 | PUT /api/issues/:iid/internal-meta 置 in_progress |
| 记录共识/决策 | PUT /api/issues/:iid/collab/consensus |
按 INT-xxx 找 issue | GET /api/projects/:pid/issues?q=INT-56 换 UUID(路径参数只认 UUID) |
| 查 Fast Ship 自身日志 | GET /api/self-logs(列表)、/aggregate、/trace(request_id 或 run_id 二选一);与项目日志 /projects/:id/logs 无关;fsr_ 令牌 40301 |
| 把 PR 挂到 issue | POST /api/issues/:iid/pull-requests,body {"url":"<PR链接>"} |
| 刷新 PR 状态 | POST /api/issues/:iid/pull-requests/sync(合并后调,逐行失败看 failures[]) |
| 摘掉某个 PR | DELETE /api/issues/:iid/pull-requests/:lid(:lid 是关联行 id,即 api.md 里的 {id}) |
调用任何写接口前先读 references/api.md 对应小节,不要凭记忆构造请求体。
Fast Ship 附加块(提示词尾部的引用块)
Fast Ship「启动线程」生成的提示词 = 用户模板正文 + 结尾的 > 引用块。看到引用块里带
项目ID / 问题ID,就按这两个 ID 用技能查询并处理该问题,不需要再追问是哪条 issue:
> 以下信息由 Fast Ship 附加。请使用 fast-ship 技能查询并处理该问题。
> 若当前环境未安装 fast-ship 技能,先征得用户同意,再执行:
> `npx skills add https://github.com/gitbobobo/fast_ship --skill fast-ship`
> 项目ID:<project_id>
> 问题ID:<issue_id>
> 推荐理由:<reason> ← 可能出现
当前环境未安装本技能时,先征得用户同意,再执行 npx skills add https://github.com/gitbobobo/fast_ship --skill fast-ship。
T3 绑定(Agent 辅助配置)
Fast Ship 项目与 T3 项目是显式绑定,Agent 可辅助完成「发现 → 比对 → 绑定」:
GET /api/environments/t3-projects:列出各环境及其 T3 项目(含workspace_root)。- 用自身仓库路径比对各项目的
workspace_root,确定自己对应哪个 T3 项目。 PUT /api/projects/{id}/t3-bindings/{environmentId},body{"t3_project_id":"..."}完成绑定;解绑用DELETE同路径。
这四个接口是对 API Key 开放的 T3 只读面(不含凭证、不含线程内容);线程相关端点仍仅 JWT。字段细节见 references/api.md。
上表的 :pid 在 api.md 里是 {id},:iid 是 {iid};:lid 是 PR 关联行 id(api.md 里 pull-requests 路径下的 {id})。
认证配置
Fast Ship 使用 API Key 进行程序化认证。Key 格式为 fsk_ 开头的随机字符串。
请求方式(硬性规则)
- 禁止把 API Key 读出来写进命令、参数、环境变量赋值或任何输出——
curl -H "Authorization: Bearer fsk_..."这类写法会把 Key 留在会话记录和进程列表里。 - 所有请求一律走技能自带脚本。脚本自行读取 config 并附加认证头,Key 不出现在命令行:
node <技能目录>/scripts/fast-ship-api.mjs <METHOD> <path> [body.json] [--verify [读回路径]]
- 需要请求体时,把 JSON 写成 UTF-8 文件,以
body.json位置参数传入。 --verify [读回路径]:写请求成功(2xx)后再发一次 GET,输出{ "response": …, "verify": … },用于写后读回校验。缺省对同一路径 GET;没有对应 GET 路由的写端点(如internal-meta、recommendation、collab的 PUT;批量PUT /api/issues/internal-meta的缺省读回会命中GET /issues/:iid而 404)必须显式给出读回路径(如对 Issue 本身GET /api/issues/:iid)。对 DELETE,读回 404 视为确认删除。- 脚本不可用时的兜底:把
Authorization: Bearer <api_key>整行写入临时头文件,用curl -H @<header文件>引用,用完立即删除该文件。
首次使用(配置持久化)
如果 ~/.config/fast-ship/config.yaml 不存在,必须向用户询问以下信息:
- Base URL:Fast Ship 服务地址,例如
http://localhost:8080或https://fast-ship.example.com - API Key:从 Fast Ship Web 界面「设置 → API Key」创建的密钥(
fsk_开头)
然后将配置写入文件:
# ~/.config/fast-ship/config.yaml
base_url: "https://fast-ship.example.com"
api_key: "fsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
注意:
~/.config目录在 macOS/Linux 上通常已存在;如果不存在,请先创建目录。
后续使用
脚本会自行读取 ~/.config/fast-ship/config.yaml 中的 base_url 和 api_key,不再询问用户。Agent 不要把 Key 读出来写进命令或输出。
请求头
脚本自动为所有请求携带以下请求头(无需手工添加):
Authorization: Bearer <api_key>
Content-Type: application/json; charset=utf-8
核心工作流
未说明来源时创建 source: "internal"。只有用户明确要求同步 GitHub 时才用 source: "github"。API Key 只能建 internal。
字段一律见 references/api.md,这里只留端点。
GET /api/projects,确定project_id。- 打标前先
GET /api/projects/{id}/issues/repo-labels。项目没配 GitHub 仓库或标签为空时,改GET /api/projects/{id}/issues/filter-options。 POST /api/projects/{id}/issues创建。后续路径只用响应里的id(UUID)。给用户的页面是{base_url}/projects/{project_id}/issues/{id}。- 要打标就
PUT /api/issues/{iid},标签名必须已经存在。不要靠创建请求里的workflow_status推进进度。 - 推进用
PUT /api/issues/{iid}/internal-meta,值为todo、in_progress或done。 - 查一条用
GET /api/issues/{iid}。列表用GET /api/projects/{id}/issues。
截图标注(AI 评审闭环)
截图页画布上的矩形框选标注挂在具体截图上,供人/AI 交换评审意见。API Key 可读全部标注、拉裁剪图、标为已解决;不能创建/删除标注或批量处理(40301),改文字/关联 Issue/重开也要 JWT。
- 列表:
GET /api/projects/{id}/screenshot-annotations→{items:[...]},query 可按status(open/resolved)、outdated(true/false)、issue_id、screen_id、platform/locale/theme(逗号多值,__none__= 未标注桶)过滤。 - Issue 维度:
GET /api/issues/{iid}的screenshot_annotations[]内嵌关联到该 Issue 的标注(无则缺省)。 - 每条标注带:
image_url(所在截图原图)、crop_url(框选区域裁剪图,PNG,四周带外边距)、比例坐标x/y/width/height(0~1)、像素坐标pixel_rect(尺寸未知时为 null)、screen_key/screen_title/screen_platform/screen_locale/screen_theme、outdated(截图被覆盖更新后待确认)、status。 crop_url/image_url是<img>直链路径:脚本调用带 Authorization 头即可,Web 端<img>才需要?token=<jwt>。- 标已解决:
PUT /api/screenshot-annotations/{aid},body 整包只传{"status":"resolved"}——带其他字段或open会被 40301。 - 原图超过解码像素上限(约 64MP)时 crop 返回 40004(
尺寸超出可处理范围),此时用image_url拉原图自行缩放。
AI 评审闭环(字段细节见 api.md screenshots 章):
GET /api/issues/{iid}读screenshot_annotations,或按维度过滤 +status=open拉项目标注。- 按
crop_url拉裁剪图,看用户框选了哪块区域、写了什么意见。 - 修改 UI 后,
POST /api/projects/{id}/screenshots以同一screen_key+ 同一组 platform/locale/theme 上传新截图(同变体即覆盖更新,文件与宽高/上传时间被替换;该截图上全部 open 标注置outdated=true,等待人工「确认保留」或你确认修完后置 resolved)。 - 逐条
PUT {"status":"resolved"}标已解决(JWT 批量场景可用POST /api/projects/{id}/screenshot-annotations/batch,API Key 无此能力)。
删 Issue 只清空标注的 issue_id(标注保留);删截图会级联删标注。界面随版本增删时,用 DELETE /api/screenshot-screens/{sid} 清理过时截图(JWT / API Key 均可)。
Issue 关联 PR
一个 Issue 可挂多个 PR(跨仓库也可以)。时机:建完 PR 立刻 attach,让 Issue 页能看到实现进度;PR 合并后调一次 sync 刷新状态。
- attach:body 只传
{"url":"https://github.com/<owner>/<repo>/pull/<n>"},支持/files、query 等后缀。服务端自行去 GitHub 拉标题/状态/作者,拉取失败不落记录(502)。重复 attach 幂等,不产生第二行。attach 必须读回确认:加--verify /api/issues/{iid}或紧接一次 GET,确认pull_requests[]里出现该 PR 才算挂上——502/超时会留下「以为挂上了、实际没落记录」的窟窿,只看退出码不够。 - 读:详情
GET /api/issues/:iid的pull_requests[]是全量列表;列表项带pull_request_summary {total, open, merged}(closed = total - open - merged)。 - sync:返回
{items, failures},每条 PR 是独立失败域——某条拉不到(404/限流)只进failures[],其余照常刷新;failures[].id是关联行 id。 - detach:
DELETE /api/issues/:iid/pull-requests/:lid;不存在的关联返回 40412(非幂等,重复调用会报错)。 - PR 状态与
workflow_status无耦合:PR 全合并不等于需求完成,internal-meta仍要自己推。 link_origin=manual的关联永不被 GitHub 同步投影的清理逻辑误删。
语义陷阱与权限分工
multipart
这些端点是 curl -F file=@路径,不是 JSON。Issue 图片的响应里有 markdown,把这段贴进正文才算挂上附件。
POST /api/auth/avatarPOST /api/projects/{id}/issues/assets(草稿,仅 JWT)POST /api/issues/{iid}/assetsPOST /api/versions/{vid}/artifacts(可选表单字段platform)
字段级权限
spec 的 security 经常同时写 JWT 和 API Key,真正的拒绝在 handler 里。
- API Key 不能传
state/state_reason,不能POST /api/issues/{iid}/comments,不能PUT或DELETE /api/issues/{iid}/ship-hook。做了就是 403(40301)。ship_hook只出现在 Issue 的 GET 和列表里,只读。 PUT /api/issues/{iid}/collab/consensus、PUT /api/issues/{iid}/collab/summary、PUT /api/issues/{iid}/recommendation只接受 API Key。JWT 调用返回 403(40303)。- 推荐被用户延后后,
PUT recommendation返回 409(40911)——不要重试再推荐,也不要试图 DELETE(同样 40911)。PUT/DELETE /api/issues/{iid}/recommendation/defer是延后/恢复,仅 JWT(API Key 40301)。彻底移除延后项只能由 JWT 用户做。 POST /api/projects/{id}/logs只接受 API Key。JWT 调用返回 403(40303)。
自身日志不是项目日志
GET /api/self-logs、/aggregate、/trace 查的是 Fast Ship 服务端自己的 slog(INT-94)。项目运行日志仍走 /api/projects/{id}/logs。fsr_ 令牌查自身日志返回 40301。失败请求用响应头 X-Request-Id 调 /trace?request_id=;审查运行链路用 run_id。
checklist 是整组替换
PUT /api/issues/{iid}/checklist 提交的 items 就是最终清单。没带上的旧条目会被删掉。items=[] 会清空清单。
q 是内存全量过滤
GET /api/projects/{id}/issues 的 q 不是索引查询。它扫全量,匹配标题、正文、作者 login、INT-xxx / GH-xxx。纯数字还会匹配 sequence_number 或 GitHub number。
详情自带 collab
GET /api/issues/{iid} 的 data 里有 collab(consensus 和 summary)。列表项没有。要看协作区,读详情即可,不必再打一次 GET /collab。
批量改工作流
PUT /api/issues/internal-meta 的请求体是 {items:[{issue_id, workflow_status}]},最多 200 条。某一条失败不会让整批变成 4xx,HTTP 仍是 200,看 failures[]。
collab 先读后写
PUT consensus 或 summary 之前先 GET。用户已经清空的块,不要写回去。DELETE 幂等,目标本来就没有也返回 200。
追问还没结束时不要写共识。决策问完、用户确认可以开工之后,再 PUT 已经拍板的内容。用户说别问了直接做,共识留空,不要编「按 Issue 原文实施」。未经许可不要关单,不要提交或推送代码。
完成总结写给普通人看,两段就够:之前怎样,现在怎样。不列文件,不贴 commit SHA,不写测试清单。改动还没落到能感知的结果上,就先别写「现在」。
请求编码
请求体写成 UTF-8 JSON 文件,用脚本的 body.json 传入。不要在 shell 里拼接中文。
Breaking Changes
- API Key 不可通过
PUT /api/issues/:issue_id修改state/state_reason(open/close);Agent 应改用PUT /api/issues/:issue_id/internal-meta的workflow_status标记完成,open/close 由 JWT 用户在 Web 端操作。 - API Key 不可发表评论(
POST /api/issues/:issue_id/comments)。 - API Key 不可
PUT/DELETE /api/issues/:issue_id/ship-hook。ship_hook仅出现在 Issue GET/列表中供只读。发货后关单/留言由 JWT 用户在 Web 配置,发货成功后由服务器执行。 - 协作区旧端点
POST/PUT/DELETE /collab/notes、/collab/questions已移除;suggestions、plan、review与commit_ids一并废弃。当前GET /collab只返回consensus与summary。