单人项目 CI/CD:让 @claude 自己跑流水线
一天 14 个 PR、零命令行 —— 从「写代码 8 小时」到「提 issue + Ctrl+F5 = 30 分钟」的质变
过去给自己的项目加一个小功能,从 grep 找文件、读上下文、改、跑测试、commit、push、SSH 部署、刷新验证,一套下来半小时就没了。现在我在 GitHub 上写一句 @claude,五分钟后改好的代码已经在我浏览器里待我 Ctrl+F5 验收。我点头说"上线",又十几秒就在 prod 跑了 —— 除了写 issue 和按 F5,全程 0 命令行。这篇博客记录这套面向单人开发者的全自动 CI/CD 流水线,以及它带来的生产力质变。Case study 是 claude-ai-harness —— 我自己写的 Claude.ai 风格 AI Agent 文档前端 —— 第一天接通这套流水线后,agent 替我跑出了 14 个 PR、关掉了 9 个 issue。
生产力的质变:从「写代码 = 主要工作时间」到「写 issue + Ctrl+F5 = 主要工作时间」
单人项目最大的瓶颈一直不是会不会写代码,而是上下文切换的累积成本。一个想法到上线要切换 8 次状态:编辑器 → 终端 → 服务器 → 浏览器 → GitHub → 终端 → 部署日志 → 浏览器验证。每次切换几分钟,加起来一个『加个按钮』的小改动半小时就没了。
真正昂贵的不是写代码本身,而是「让大脑进入写代码状态」的这部分时间。一旦把写代码这一步交给 agent,需要人做的就只剩 无法被替代的两个动作:
- 提出需求:开一个 issue 描述要什么、为什么要、怎么验证
- 业务验收:在本地预览里实操,判断是否符合预期
这两件事 AI 永远做不好 —— 它没你的产品直觉,不知道你心里那个『差一点的感觉』。剩下的步骤(grep、读、改、测、commit、push、部署、重启、验证 HTTP 200),全都自动化。
三种迭代模式对比:纯手动 vs 纯 AI vs AI + CI/CD
讨论"用 AI 加速开发"通常停在一层:让 AI 替你写代码。但写代码本身只占整个迭代周期的 30%,剩下 70% 是 grep 找上下文 / commit / push / SSH 部署 / 重启服务 / 浏览器验证 / 各种状态切换。只优化前 30% 远远不够。
同一个 UX 改动(比如『给点赞按钮加颜色』),在三种迭代模式下时间分布大致是这样:
| 阶段 | 纯手动 | 纯 AI(Claude Code / Codex / Cursor 在 IDE 内) | AI + CI/CD(本文) |
|---|---|---|---|
| grep + 读 + 改代码 | 15 min | 3 min(提示 AI) | 0(agent 自己干) |
| commit / push | 1 min | 1 min | 0(agent push) |
| 开 PR | 1 min | 1 min | 0(auto-pr.yml) |
| 等 CI | — | 1–2 min(守屏幕) | 1–2 min(后台跑,可离开) |
| 本地预览 / 验收 | 5 min | 3 min | 30 s(Ctrl+F5) |
| merge | 1 min | 1 min | 0(auto-merge) |
| SSH 部署 | 5 min | 5 min | 0(deploy.yml) |
| 验证 prod | 3 min | 3 min | 0(deploy.yml 内含 200 探测) |
| 键盘时间 | ~30 min | ~15 min | ~3 min(issue + F5) |
| 能离开椅子? | 不能 | 不能 | 能 |
纯手动 → 纯 AI(Claude Code、Cursor、Aider、OpenAI Codex CLI、GitHub Copilot 这些 IDE 内的 AI 编程工具):砍掉一半时间,但没改变工作的形态 —— 你还是坐在 IDE 前面手动 commit / push / SSH。这些工具优化的都是同一段:写代码这 30%。对人不可替代的状态切换没影响。
纯 AI → AI + CI/CD:再砍掉一半,但更重要的是改变了工作形态。一旦"写代码"交给 agent、commit / push / merge / 部署 / 验证全交给 GitHub Actions,你的 4-5 分钟变成真实的离开时间。地铁上、洗衣机前、做饭的间歇都能切回来 F5 一下。生产力提升不是线性叠加,是注意力解放的质变。
AI 写代码是必要但不充分。只优化『写』这一步,你仍然被钉在键盘前;把『AI 边界外』的所有状态切换也自动化,注意力才能真正离开 IDE。Claude Code 是这条流水线里的一个组件,不是全部。
第一天的实战业绩
这两张截图是流水线接通后第一天结尾的状态。
这些条目背后是同一条流水线。我先让 agent 做了一次 UX gap audit(对比 claude.ai 列出 14 个差距),然后把 top 6 拆成单独 issue 串行 @claude,每个 agent 平均 4-5 分钟写完推到 feature 分支,auto-PR 工作流接力开 PR + 启用 auto-merge,CI smoke 跑过自动合进 dev,本地 watcher 拉到 :3141 预览,我浏览器验收,最后 git merge --ff-only dev 把 dev 推到 main,deploy.yml 把代码 SSH 到 DigitalOcean VPS 重启服务。
具体改了什么 —— claude-ai-harness 第一天的迭代清单
把 issue 编号 + 类型 + 一句话描述列出来给读者一个具体印象。粗体的几条特别值得说一下:
| # | 类型 | 内容 | 谁写的 |
|---|---|---|---|
| #3 | feat | 新增 /healthz 端点供 CI smoke + 监控 | agent |
| #5 | fix | 回复点赞按钮点击零反馈 —— 根因是彩色 emoji 不响应 CSS color | agent + 人工补一刀 |
| #8 | chore | UX gap audit:对比 claude.ai 找出 14 个体验差距 | agent |
| #9 | feat | 用主题化内联弹层替换浏览器原生 prompt() / confirm() —— 顺手修了 deleteThread 在确认前就发 DELETE 请求的 bug | agent |
| #10 | feat | 滚动历史 >200px 时浮现『跳到底部』按钮 + 空输入框禁用发送按钮 | agent |
| #11 | feat | 拖拽文件上传 + 键盘快捷键(Cmd+N 新对话 / Esc 关面板 / Cmd+K 聚焦输入) | agent |
| #12 | feat | 代码块语法高亮:自研轻量 tokenizer,覆盖 12 种语言,零外部依赖 | agent |
| #13 | feat | 侧边栏对话搜索(按 title + 消息内容 substring 实时过滤) | agent |
| #14 | feat | Markdown 渲染补全:链接 / 有序列表 / 斜体 / 代码块 copy+lang 工具栏 | agent |
| #21 | fix | 代码块路由 bug:Python/JS/CSS 代码块不再错误推送到右侧文档面板,回归到聊天中渲染 | agent |
| #23 | feat | KaTeX LaTeX 数学公式渲染(反向传播 case 写起来终于不丑了) | agent |
| #24 | feat | 对话置顶(star)功能 + starred 列表前置 | agent |
| #27 | chore | End-to-end 自动化链路验证(footer 加一行标记) | agent |
这里面让我印象最深的不是数量,是质量。比如 #9 主题化弹层那次,agent 没只做我让它做的事 —— 顺手发现并修了 deleteThread 在弹 confirm 之前就发 DELETE 请求的 bug(旧版逻辑:用户点取消、对话还是被删了)。这种「主动发现并修复正交 bug」的能力,靠的不是 LLM 智能,是它在改完代码后会自己复读一遍上下文找异常 —— 一种它擅长但人懒得做的工作。
同样,#5 点赞按钮那次 CI 一切绿但浏览器毫无反馈 —— agent 的 CSS 语法对,但彩色 emoji 不响应 color 属性是一个视觉层面的事实,CI 抓不到,人也只有点了才知道。这是「人不可替代」的最好示例:不是 AI 不会写 CSS,是 AI 看不到屏幕。
Case study:claude-ai-harness 是什么
这套流水线之所以能在一天内迭代出这么多功能,部分原因是被迭代的项目本身足够轻 —— 几个文件、零外部服务依赖、纯前端无构建步骤。所以借这个机会简短介绍一下 case study 对象:
正因为它够轻,agent 改它的反馈环路才能短到 5 分钟一次。重型项目(带数据库迁移 / 复杂构建 / Docker 编排)暂时撑不起这种节奏 —— 不是流水线的问题,是项目本身没准备好。
整套链路:10 步里 7 步自动
10 步里 7 步全自动。手工部分剩三个:开 issue、F5 验收、说一句上线。其余全部机器代劳。
实践经验:标『你做』的步骤里,又有两步能委托给本地 AI
实操久了发现,上面图里那三个『你做』不全是不可替代的人类动作。其中两步又能再外包一层 —— 给本地 Claude Code(或任意能跑命令的 AI)当 orchestrator:
- 开 issue:我用嘴/打字跟本地 Claude Code 说『点赞按钮点了没反应、Chrome 148、控制台没报错』,它替我写一份格式完整的 GitHub issue(含复现步骤、期望行为、@claude 触发),
gh issue create直接提交。我连 GitHub 页面都不用打开。 - 说上线:我跟本地 AI 说『上吧』,它替我跑
git checkout main && git merge --ff-only dev && git push。一条命令的事,连终端也省得我开。 - F5 验收:这一步目前还是人 —— 浏览器看一眼对不对,是 product sense 不可替代的部分。如果挂了 MCP 浏览器工具,本地 AI 可以帮你截屏 + 描述视觉,但最终拍板的判断还是人。
真正无法委托的只剩"我看一眼然后说行不行"。从『8 小时坐在 IDE 前面』到『地铁上跟手机说三句话、到家 F5 一下』—— 这是两层抽象的叠加:第一层 GitHub Actions 把工程动作自动化,第二层本地 AI 把人机界面动作(措辞、敲命令)也接管,人最后只贡献产品判断。
分支模型:main = prod 真相
核心约束一句话:main 永远等于线上跑的代码,只通过 ff-merge 从 dev 前进。
- main —— prod 真相分支。任意时刻 main HEAD = VPS 上跑的代码。
- dev —— 集成 / staging 分支。agent 的所有 feature 分支 PR 都进这里。本地 :3141 预览跟踪它。
- claude/issue-N-时间戳 —— agent 一次任务的 feature 分支。合进 dev 后等 promote 上线,上线后由 deploy.yml 自动删除,避免分支墓地堆积。
Promote 操作是一行 git merge --ff-only dev,ff 性质保证不可能产生 merge commit、不可能有冲突 —— 因为 dev 永远是 main 的严格后代。
Agent 实际在干什么
下面是 agent 完成一个 issue 之后留在 GitHub 上的工作记录样本。
--append-system-prompt 注入的约束生成。三件事使审 PR 变快:
- 第一句 ack:『收到 — 正在排查/实现:<title>』。让人确认 agent 已经看到 issue 而不是石沉大海。
- 任务清单:agent 自己列 todo + 同步打勾。审 PR 时能快速判断它有没有跳过步骤。
- 按文件分组的改动摘要:审 PR 不用 git diff 逐行看,先扫这段就能判断 80% 方向对不对。
五个工作流文件
claude.yml —— @claude 触发器
监听 @claude 出现在 issue 或 PR 评论里。用 anthropics/claude-code-action@v1 + Claude Pro OAuth token(不烧 API 钱)启动 agent。关键设置:ref: dev 让 agent checkout 集成分支,看到的是『下一个待发布版本』状态。
auto-pr.yml —— 自动开 PR + auto-merge
监听 claude/issue-** 分支的 push。agent 推完,立刻:从分支名提 issue 号,读 issue 标题做 PR 标题,gh pr create --base dev,gh pr merge --auto --merge 启用 auto-merge。幂等:同分支已有 PR 时不重开。
ci.yml —— 极简 smoke
三步:npm ci → npm run check(语法验证)→ 启 server 30 秒 curl /healthz。不做语义级测试,业务正确性靠人工 QA 比靠测试套件 ROI 高得多。
deploy.yml —— main 推 prod + 清理墓地
监听 push 到 main。SSH 到 VPS、git pull、必要时 npm ci --omit=dev、systemctl restart、探公网 URL 200。末尾自动删已合进 main 的 claude/issue-* 分支(compare API status=identical|behind 即删)。
dev-watcher.sh —— 本地预览同步(唯一本机组件)
30 行 bash 循环:每 15 秒 git fetch origin dev,发现 dev 前进就 ff-pull。如果后端文件(server.mjs / db.mjs / package*.json)变了 → pkill + 重启 node;否则纯静态变更,浏览器 Ctrl+F5 即可。
一天踩进的几个坑
1. CSS 给彩色 emoji 加 color 不生效
Agent 给点赞按钮 .feedback-btn.active 加了 color: var(--accent),CI 全绿。浏览器测时点击毫无视觉反馈。原因:按钮里的 👍 👎 是彩色 emoji,Chrome/Edge 把它当多色 glyph 渲染,不响应 CSS color。改成 background: var(--accent-glow) 立刻可见。教训:CI 验证不了『看起来对不对』,UI 改动必须人眼过一遍。
2. VPS 上 8 天前的野生 node 进程
systemctl restart claude-lite 报 active,/healthz 还返回老代码。原来 8 天前某次手动调试 nohup node server.mjs & 留了一个进程一直占着 3040 端口,systemd 重启的新进程 EADDRINUSE 静默失败。教训:能走 systemd 就走 systemd,nohup 一时爽,半个月后撞鬼。
3. YAML 块标量被多行 bash 字符串撑爆
auto-pr.yml 第一版用 body="line1\n\nline2" 写多行 PR body。YAML | 块根据首行非空内容缩进定 base,顶格的 line2 被当成块结束符。GitHub Actions 报 『workflow file issue』0 秒失败。改用 body=$(printf '%s\n\n%s' "$a" "$b") 单行 printf 解决。
4. GitHub Actions 默认不能创建 PR
auto-pr.yml YAML 修对之后还是失败:『GitHub Actions is not permitted to create or approve pull requests』。一行命令打开:
gh api -X PUT repos/$OWNER/$REPO/actions/permissions/workflow \
-f default_workflow_permissions=write \
-F can_approve_pull_request_reviews=true 5. Strict status check 卡住 auto-merge
main 分支保护开了 required_status_checks.strict=true(PR 必须 up-to-date 才能合)。默认 allow_update_branch=false,GitHub 不会自动 rebase 落后的 PR。结果 PR 永远 BLOCKED。修复 gh api -X PATCH repos/... -f allow_update_branch=true。
成本核算
| 组件 | 成本 |
|---|---|
| GitHub Actions | 公开仓库 免费无限分钟数。一个 issue 全链路 ≈ 3 分钟 |
| Claude Code OAuth token | Claude Pro 订阅配额,不烧 API 钱。一天 10-20 个 issue 是舒适区 |
| VPS | 2 vCPU / 2GB DigitalOcean,已有的,没新增成本 |
| 本地 watcher | 15 秒轮询一次 git fetch,CPU 占用看不见 |
边际成本接近 0。Claude Pro 已经订阅了用作日常开发,VPS 已经在跑别的项目。整套流水线的"基础设施成本"等于已有支出之和,额外只多了一次决心去搭它。
常见疑问
claude/issue-N 分支,各自 PR 进 dev。第一个合完 dev 前进,第二个 PR 自动 rebase 到新 dev + 重跑 CI(需要 allow_update_branch=true)。同文件同区块修改会产生 git 冲突,agent 不会自己解,需人工 rebase。降低冲突的方案:claude.yml 加 concurrency group 把 agent run 串行化,或按 issue label 分组并行。color: var(--accent),CI 全绿,但浏览器测时发现彩色 emoji 不响应 CSS color,改动视觉零影响。CI 抓不到这种『语法对但视觉无效』的问题,人眼必须过一遍。写在结尾
这套流水线跑下来最大的解放感不是写代码变快,而是注意力可以离开 IDE。我可以在地铁上用手机提个 issue,到家开电脑 F5 一下就完了。生产力的瓶颈从"我能写多快"变成了"我能想多清楚"。这种切换对我个人来说是质变 —— 同样八小时,过去能干一两个小改动,现在能 ship 十几个。
下一步在考虑给 alpha 测试用户开放 issue 提交 —— 他们提 bug 写复现步骤,我看一眼觉得合理就在评论 @claude 触发自动修。生产部署门还是我把,issue 收集层完全开放。如果你想试 claude-ai-harness 当 alpha 用户,在 GitHub 上提 issue 即可。
怎么复现 —— 直接拿走整套 skill
我把这套流水线打包成了一个可复用的 Claude Code skill,扔到自己的 skills 仓库里。你可以照搬,或者把它喂给你自己的 Claude Code,让它替你在你的项目上跑一遍 bootstrap:
如果你不用 Claude Code,那只看 claude-ai-harness/.github/workflows 目录里的 4 个 yml + scripts/dev-watcher.sh 也能完整复刻 —— 文中所有的坑都已经填好。
https://sg.yaoyuheng2001.me/posts/solo-cicd-claude-agent/。
商业用途请通过博客联系作者授权。