关于 dev
dev 是面向 Claude Code 开发流程的技能,用一条命令启动并管理本地开发服务器、可选模拟器和 agent-browser 会话。它按 Git worktree 隔离子域名与状态,并提供状态查看、停止及预览共享模式。
主要功能
- 01一键启动开发循环组件
- 02按分支创建 HTTPS 子域名
- 03预热并注册 agent-browser 会话
- 04支持幂等启动、状态查看和停止
- 05提供 tailnet 与公开预览模式
适用场景
- 01开始新分支时启动开发环境
- 02中断后恢复正在运行的开发会话
- 03与团队成员或相关方共享预览
- 04演示时限时公开本地预览
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yonatangross/ orchestkit --skill dev安装后在 Claude Code 中输入/dev确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
test-cases.jsonreferences/state-schema.mdboot-sequence.mdrules/_template.mdlab-stack-prerequisites.mdteardown-order.mdidempotent-boot.md_sections.mdbranch-named-subdomain.mdscripts/status.shboot.shstop.sh详细介绍
dev — Lab-Stack 启动
一条命令即可启动 Vercel-Labs 风格开发循环中的四个组成部分:
- portless → 命名 HTTPS 地址
https://<branch>.localhost(不同工作树之间不会发生端口冲突) - emulate → 通过
@emulators/adapter-next在同一源上运行有状态 API 模拟器 - 开发服务器 →
pnpm dev/npm run dev/yarn dev(自动检测) - agent-browser → 预热一个以分支命名的会话
状态保存在 .claude/state/dev-stack.json 中。dev stop 会读取 PID,并按启动顺序的逆序发送 SIGTERM 信号来停止进程。
与
expect配套使用:dev预热的 agent-browser 会话,也是expect(以及 M125 #2 自动触发功能)所连接的会话——首次 UI 测试无需再承受第二次启动延迟。
何时调用
| 情况 | 命令 |
|---|---|
| 在新分支上开始工作 | dev |
| 会话中断后恢复 | dev(幂等——跳过已运行的进程) |
| 删除分支前停止服务 | dev stop |
| 检查状态 | dev status |
| 与利益相关者共享预览 | dev --share(tailnet)或 dev --funnel(公开) |
| 限时现场演示 | dev --live 4(公开 funnel,有效期为 4 小时) |
恢复转入后台的开发会话(CC 2.1.144+): 通过
claude --bg启动的会话现在会与交互式会话一同显示在/resume中,并标记为bg——崩溃或会话结束后,请使用/resume直接恢复,而无需浏览 Agent 视图。后台 Shell 会话(CC 2.1.154+): 在
claude agents中,输入! <command>即可将 Shell 命令作为后台会话运行,你可以连接或断开该会话——也可通过claude --bg --exec '<command>'运行。适用于需要监控但不想一直占用终端的长时间开发循环进程(监视器、构建任务、服务器)。
模式(M127)
| 标志 | 包装的命令 | 可访问范围 | 是否需要 Tailscale CLI |
|---|---|---|---|
| (无) | portless <slug> <pkg-mgr> run dev | 仅限 https://<branch>.localhost | 不需要 |
--share | portless --tailscale ... | tailnet 成员可通过 https://*.ts.net 访问 | 需要 |
--funnel | portless --funnel ... | 可在互联网公开访问 | 需要 |
--live N | portless --funnel ... + N 小时有效期 | 公开可访问,记录在 live-demos.jsonl 中 | 需要 |
Tailscale 是可选的——仅在使用 --share/--funnel/--live 时需要。对于不共享预览的用户,默认的 dev 行为保持不变。
检测到 turbo.json 或 package.json 工作区时(#1562),启动过程会使用裸 portless(零配置),自动发现每个工作区的开发脚本,并通过任务图分配子域名。状态文件会显示 mode: "monorepo";可通过 portless list 或 dev status 列出子域名。
启动顺序
portless 是一个包装器,而非伴随进程——portless <slug> <pkg-mgr> run dev 是一个融合命令,负责管理开发服务器的生命周期。boot.sh 会跟踪包装器的 PID;stop.sh 会遍历其进程树以清理子进程。
0. Detect package manager pnpm > yarn > bun > npm (lockfile-based)
1. Resolve subdomain slug <branch> → lower → / to - → DNS-safe → ≤63 chars
2. portless proxy start (idempotent — skipped if `portless list` already responds)
3. emulate --seed <yaml> (sidecar, optional — only if emulate.config.yaml exists)
4. portless <slug> <pkg-mgr> run dev (FUSED — wrapper owns dev server's lifecycle)
5. portless get <slug> (poll up to 30s for the route to register)
6. wait-on <baseUrl> (poll up to 30s for the dev server through the proxy)
7. AGENT_BROWSER_SESSION=<slug> agent-browser open <baseUrl> (warm + register session)
8. atomic state write (.claude/state/dev-stack.json via jq + temp + mv)
9. print summary
完整的注释版说明:references/boot-sequence.md。
状态文件结构
{
"bootedAt": "2026-04-27T12:34:56Z",
"branch": "feat/m125-lane-b",
"subdomain": "feat-m125-lane-b.localhost",
"baseUrl": "https://feat-m125-lane-b.localhost",
"mode": "single",
"processes": {
"portlessWrapper": {
"pid": 86104,
"command": "portless feat-m125-lane-b pnpm run dev"
},
"agentBrowser": { "sessionName": "feat-m125-lane-b" },
"emulate": { "pid": 86200, "command": "emulate --seed emulate.config.yaml" }
},
"emulators": ["github", "stripe"],
"share": null,
"notes": "portless proxy daemon is shared and not tracked here — stop.sh leaves it running."
}
使用 --share / --funnel / --live 时(M127 #1561 / #1565),share 会变为:
"share": {
"mode": "tailscale",
"tailscaleUrl": "https://app.your-tailnet.ts.net",
"expiresAt": "2026-05-03T20:00:00Z"
}
mode 为 "single"(默认)或 "monorepo"(检测到 turbo.json/工作区时)。请注意,使用的是 portlessWrapper(而不是 portless + devServer)——portless 负责管理开发服务器。完整架构:references/state-schema.md。
自动显示的提示(M127)
启动 dev 时,它会检查 package.json 并显示提示:
- 检测到
@json-render/*(#1560)→ 输出 devtools 适配器导入行,以便在开发环境中启用检查器面板(Spec / State / Actions / Stream / Catalog / Pick)。生产构建会通过摇树优化移除相关代码。 - 检测到
@clerk/*(#1563)→ 如果emulate.config.yaml中有clerk,则输出模拟登录 URL(http://localhost:4012);否则提示运行emulate-seed --auto。
前置条件 + 平稳无操作
$ dev
✓ portless found
✓ agent-browser found
✓ jq found
[1] slug feat-m125-lane-b
# OR with a missing prereq:
✗ portless not found. Install: npm i -g portless
Skipping boot — install missing tools and re-run.
需要 portless、agent-browser 和 jq。emulate 是可选项——仅当 emulate.config.yaml 存在时才需要。启动时必须满足所有必需条件;如果没有 emulate 配置,启动会在不启用模拟器的情况下继续。
CI=1 会让启动流程提前结束(立即以 0 退出)。
状态 + 拆除
$ dev status
ork:dev — feat/m125-lane-b
✓ portlessWrapper portless feat-m125-lane-b pnpm run dev
✓ agentBrowser feat-m125-lane-b
base url: https://feat-m125-lane-b.localhost
booted: 2026-04-27T19:36:54Z
portless: route registered ✓
$ dev stop
ork:dev — sending SIGTERM in reverse boot order…
✓ agent-browser session "feat-m125-lane-b" closed
✓ portless wrapper (pid 86104) + 21 descendant(s) stopped
Cleared .claude/state/dev-stack.json
Note: portless proxy daemon left running (shared). Run `portless proxy stop` if you really mean to stop the daemon.
停止时会遍历包装器的进程树(递归调用 pgrep -P),并从叶节点开始向上向后代进程发送 SIGTERM,因为 portless 并不总能正确传递信号。portless 代理守护进程本身是共享基础设施,dev stop 绝不会将其杀掉。
工作树行为
每个 git 工作树都有自己的子域名——feat-foo.localhost 和 feat-bar.localhost 可以在同一台机器上共存。状态文件位于各自工作树的 .claude/state/ 下,因此从一个工作树运行 dev 时看不到另一个工作树的进程。
幂等性
如果服务栈已在运行,再次运行 dev 不会执行任何操作:
$ dev
ork:dev — feat/m125-lane-b already running.
https://feat-m125-lane-b.localhost (uptime 2h 14m)
Run dev stop to tear down, or dev status for detail.
存活探测:针对每个已跟踪的 PID 调用 process.kill(pid, 0)。如果有进程已停止运行,该技能会显示具体进程,并提供清理状态并重新启动的选项。
agent-browser 如何协同工作
会话名称等于子域名——如果只连接了一个会话,针对该会话的 agent-browser 命令无需添加 --session 标志:
agent-browser open "https://feat-m125-lane-b.localhost/dashboard"
# implicit session = "feat-m125-lane-b" because it's the only one
expect(M125 #2)会读取开发栈状态文件并复用同一个会话,无需再次握手。
与 expect(M125 #2)集成
在编辑 .tsx 文件后触发 auto-expect 时,它会:
- 读取
.claude/state/dev-stack.json,查找 agent-browser 会话和基础 URL。 - 根据文件路径计算受影响的路由(
app/dashboard/page.tsx→/dashboard)。 - 使用实时会话,通过
<baseUrl><route>操作 agent-browser。 - 将 ARIA 快照记录到以
(route, parentCommit)为键的记忆中(M125 #6)。
如果开发栈未在运行,auto-expect 会静默跳过——dev 是前置条件,而非硬依赖。
不适用的情况
- CI — 设置
CI=1;该技能会以 0 退出,不会启动服务。 - 生产部署 — 绝不适用;这仅用于开发循环。
- 非 Vercel-Labs 服务栈 — 会回退到安装提示;你仍可手动运行底层工具。
- 处于
tmux -CC会话中 — agent-browser 仪表板与 iTerm2 tmux 集成不兼容。
脚本
| 脚本 | 功能 |
|---|---|
scripts/boot.sh | 检查所有前置条件,全部满足后按 9 个步骤启动。具备幂等性(如果已在运行则不执行任何操作)。在 CI 中遵循 CI=1 跳过启动。 |
scripts/stop.sh | 按启动顺序的逆序发送 SIGTERM,5 秒后回退为 SIGKILL。最后移除状态文件。 |
scripts/status.sh | 显示格式化状态。使用 --quiet 仅检查存活状态(运行时退出 0,已停止时退出 1)。供 boot 检查幂等性时使用。 |
dev 会调用 scripts/boot.sh;stop → stop.sh;status → status.sh。Shell 脚本是唯一可信来源。
参考资料
| 文件 | 用途 |
|---|---|
references/boot-sequence.md | 按步骤说明启动流程并附带命令 |
references/state-schema.md | 完整的 JSON 结构及字段语义 |
规则
| 规则 | 影响 | 适用场景 |
|---|---|---|
rules/lab-stack-prerequisites.md | CRITICAL | 每次启动 |
rules/branch-named-subdomain.md | HIGH | 子域名解析 |
rules/idempotent-boot.md | HIGH | 服务栈运行时再次启动 |
rules/teardown-order.md | MEDIUM | 调用 stop 时 |
使用 /goal 无人值守运行
使用 /goal(CC 2.1.139+)设置完成条件后,该技能会在多轮对话中持续工作,直至满足条件。适用于交互模式、-p 和 Remote Control。覆盖面板会实时显示已用时间、轮数和令牌数。
此技能的完成条件示例:
/goal until services.running == 4, or stop after 5 turns
满足以下条件时停止:全部 4 个开发循环服务(portless + emulate + dev-server + agent-browser)都在各自端口/套接字上报告健康状态。兼容 claude.ai Remote Control 运行。
相关技能
expect— 感知差异的浏览器测试;复用此技能预热的 agent-browser 会话emulate-seed— 生成步骤 3 使用的模拟器配置portless(技能)— 底层工具文档browser-tools(技能)— agent-browser 命令参考