← 提示词库 Anthropic/claude-code/skills/run-skill-generator/SKILL.md 原文 md
🌐 中英双语对照

name: run-skill-generator
description: Author or improve the run- skill - a per-project skill that tells agents how to build, launch, and drive this project's app. Use when the user asks to set up the project, get it running, write run instructions, or verify build/run steps work from a clean environment.
disable-model-invocation: true

Your job is to produce a skill at <unit>/.claude/skills/run-<unit-name>/
that lets a future agent build, launch, and drive this project from
a clean machine.

你的任务是在 <unit>/.claude/skills/run-<unit-name>/ 下产出一个 skill,让未来的代理能够在干净的机器上构建、启动并**操控(drive)**这个项目。

The skill has two parts that live together:

这个 skill 包含共处一处的两个部分:

<unit>/.claude/skills/run-<unit-name>/
  SKILL.md      <- agent-facing instructions - SHORT. Points at the driver.
  driver.mjs    <- (or driver.py, smoke.sh, ... - or none: web apps use
                   chromium-cli off-the-shelf, and the heredoc in
                   SKILL.md is the script)

That almost always means writing code, not just prose. If the app
has any interactive surface (GUI, TUI, long-running server, REPL), the
future agent needs a programmatic way to poke it. A markdown file by
itself cannot click a button - but sometimes the button-clicker
already exists: for web apps it's chromium-cli, for servers it's
curl. You build (or script) that harness now, commit it alongside
the skill, and the SKILL.md documents how to use it.

这几乎总是意味着要编写代码,而不只是写文字。如果应用有任何可交互的界面(GUI、TUI、长期运行的服务器、REPL),未来的代理就需要一种以编程方式与之交互的手段。光靠一个 markdown 文件点不了按钮——但有时候"点按钮的人"已经存在:对 Web 应用来说是 chromium-cli,对服务器来说是 curl。你现在就要构建(或编写脚本)这个驱动工具(harness),把它与 skill 一起提交,并在 SKILL.md 中写明如何使用它。

Definition of done / 完成标准

You are done when all of these are true:

当以下条件全部满足时,你才算完成:

  1. You launched the app in this container and interacted with it -
    not its test suite, the actual running app. For anything with a GUI,
    that means you have a screenshot file on disk that you took.
    你在本容器中启动了这个应用并与之交互——不是它的测试套件,而是实际运行中的应用。对任何带 GUI 的东西来说,这意味着磁盘上存有一张你亲手截取的屏幕截图文件。
  2. The interaction harness is committed next to the skill. A driver
    script, a REPL wrapper, a smoke test, or the chromium-cli heredoc
    inline in SKILL.md - whatever you used to drive the app in step 1.
    (Graduated into scripts//e2e/? - fine, point at it. Web app with
    chromium-cli off-the-shelf? - the inline script is the harness; no
    separate file.)
    交互驱动工具(harness)已提交在 skill 旁边。驱动脚本、REPL 包装器、冒烟测试,或内联在 SKILL.md 中的 chromium-cli heredoc——即你在第 1 步中用来驱动应用的任何东西。(已经"毕业"进 scripts//e2e/?——可以,指向它即可。Web 应用直接用现成的 chromium-cli?——内联脚本就是 harness,无需单独的文件。)
  3. The SKILL.md documents the harness as the primary agent path -
    the section a future agent reads first is "run this driver / pipe
    these commands to chromium-cli," not "run npm start and a window
    opens."
    SKILL.md 把该 harness 记录为主代理路径——未来代理最先读到的章节应是"运行这个驱动程序 / 把这些命令喂给 chromium-cli",而不是"运行 npm start 然后窗口打开"。
  4. Every code block in SKILL.md is a command you ran that worked.
    This session. This container. Not from the README, not inferred.
    **SKILL.md 中的每个代码块都是你实际运行成功过的命令。**就在本次会话、本容器中。不是抄自 README,也不是推断出来的。

If you're about to write the skill and you don't have (1), stop. You
are about to paraphrase existing docs. That document already exists -
it's called the README, and the whole reason you're here is that it
wasn't enough.

如果你正准备写这个 skill 却还不满足条件 (1),**停下来。**你正要做的只是改写现有文档。那份文档早就存在——它叫 README,而你之所以会接到这个任务,正是因为它不够用。

【评论】本 skill 的核心设计是反"照抄文档":要求一切结论来自本容器内的真实执行(截图、驱动脚本、可复现命令),用以防止代理生成看似完备实则未经验证的说明。

The deliverables are code AND docs / 交付物是代码加文档

Typical output is a skill directory containing both:

典型的产出是一个同时包含两者的 skill 目录:

<unit>/.claude/skills/run-<unit>/
  SKILL.md         <- SHORT. Points at the driver. Has the frontmatter
                     that lets Claude auto-load it when someone asks
                     to "run <unit>" or "screenshot <unit>".
  driver.mjs       <- (or driver.py, smoke.sh, ... - or none: web apps
                     use chromium-cli off-the-shelf, and the heredoc
                     in SKILL.md is the script)

The driver lives inside the skill directory by default. They are a
pair - the skill's instructions and the code that implements them. A
driver that lives here is allowed to be a bit messier than production
code; it's agent tooling, not product surface.

驱动程序默认放在 skill 目录内部。两者是一对——skill 的说明文字,以及实现这些说明的代码。住在这里的驱动程序允许比生产代码略显杂乱;它是代理的工具,不是产品表面。

Graduation: if the driver grows into something the project's own
test suite wants to reuse - shared launch helpers, a real e2e harness -
move it to scripts/ or e2e/ and update SKILL.md to reference the
new path. The skill stays; the driver finds a better home.

**毕业(Graduation):**如果驱动程序成长到项目自己的测试套件也想复用它——共享的启动辅助函数、真正的 e2e harness——就把它移到 scripts/ 或 e2e/,并更新 SKILL.md 指向新路径。skill 留在原地;驱动程序搬去更合适的家。

The exact shape depends on the project, but the principle is constant:
the driver is the deliverable. The SKILL.md is its man page. For
a web app, the driver already exists - chromium-cli
(examples/playwright.md) - and the skill is
the script that runs it. For a desktop app
(examples/electron.md), the driver is a custom
REPL under tmux that exposes launch/ss/click/eval. For a server,
the driver is curl. Whatever shape it takes, without something that
reaches into the running app, the skill is a description of a window
nobody can touch.

具体形态取决于项目,但原则恒定不变:驱动程序才是交付物。SKILL.md 只是它的 man 手册页。对 Web 应用来说,驱动程序已经现成——chromium-cli(examples/playwright.md)——skill 就是运行它的脚本。对桌面应用(examples/electron.md)来说,驱动程序是 tmux 下暴露 launch/ss/click/eval 命令的自定义 REPL。对服务器来说,驱动程序就是 curl。无论何种形态,如果没有任何东西能伸进正在运行的应用里,这个 skill 就只是对一个谁也碰不到的窗口的描述。

Where the skill goes / skill 放在哪里

The skill lives at <unit>/.claude/skills/run-<unit-name>/, where
<unit> is the directory for one deployable thing - an app, a
service, a library.

skill 位于 <unit>/.claude/skills/run-<unit-name>/,其中 <unit> 是一个可部署物——一个应用、一个服务或一个库——所在的目录。

Claude Code natively discovers skills from nested .claude/skills/
directories: an agent working anywhere inside <unit> will see
/run-<unit-name> as an available skill, and it auto-loads when the
request matches its description (e.g. "run the desktop app," "take a
screenshot of billing").

Claude Code 会原生发现嵌套 .claude/skills/ 目录中的 skill:任何在 <unit> 内工作的代理都会看到 /run-<unit-name> 是一个可用的 skill,当请求匹配其描述时它会自动加载(例如"运行桌面应用""给 billing 截图")。

If you're not sure where the unit boundary is, ask the user.

如果你不确定 unit 边界在哪里,问用户。

Slugify the directory name: lowercase, dashes for spaces, no slashes
(run-billing-api, not run-billing/api). The directory name and
the frontmatter name: should match - that's the slash command.

目录名做 slug 化处理:小写、空格换成连字符、不含斜杠(run-billing-api,而不是 run-billing/api)。目录名应与 frontmatter 中的 name: 一致——那就是斜杠命令名。

Process / 流程

0. Find any existing skill about running this app / 0. 寻找已有的关于运行本应用的 skill

List the project's skills with their descriptions (same probe /run
uses - users name these variously, so match on description, not name):

列出项目的各个 skill 及其描述(与 /run 使用的探查方式相同——用户对它们的命名五花八门,所以按描述匹配,而不是按名字):

d=$PWD; while :; do
  grep -Hm1 '^description:' "$d"/.claude/skills/*/SKILL.md 2>/dev/null
  [ -e "$d/.git" ] || [ "$d" = / ] && break
  d=$(dirname "$d")
done

If one is about launching/driving this app - whatever it's named -
refine, don't rewrite: verify its claims, fix what's wrong, add
what's missing, preserve what works. Re-run the driver if there is
one. Keep its existing name.

如果其中某个 skill 与启动/驱动本应用有关——无论它叫什么名字——改进它,不要重写:验证它的说法、修正错误、补上缺失、保留有效的部分。如果有驱动程序就重新运行一遍。保留它现有的名字。

(Also check for a legacy .claude/run.md - earlier versions of this
tool produced those. If you find one, migrate it: the body becomes
the skill's SKILL.md content, any referenced scripts move into the
skill dir, and delete the old file.)

(另外检查是否有旧式的 .claude/run.md——本工具的早期版本生成的是这种文件。如果找到,就迁移它:正文变成 skill 的 SKILL.md 内容,被引用的脚本移入 skill 目录,然后删除旧文件。)

If none exists, decide where to create it (see above) and continue.

如果一个都没有,就决定在哪里创建(见上文)并继续。

1. Discover - and treat every claim as disprovable / 1. 探索——把每个论断都当作可证伪的

Figure out what you're authoring for:

弄清楚你是在为哪种情况编写:

Survey the usual places: README.md, package.json scripts,
Dockerfile, Makefile, .github/workflows/, CONTRIBUTING.md. CI
configs are often more accurate than READMEs.

调查那些常见位置:README.md、package.json 脚本、Dockerfile、Makefile、.github/workflows/、CONTRIBUTING.md。CI 配置往往比 README 更准确。

Every claim in existing docs is a hypothesis. Especially the
negative ones:

**现有文档中的每个论断都是一个假设。**尤其是那些否定性的论断:

When docs say... What you do
"Requires macOS/Windows" Launch it on Linux anyway. Apps rarely refuse to start - they crash on a missing .so, which apt-get fixes. Native modules for your host's keychain/notifications may no-op; the core usually runs.
"Requires a GPU" Try software rendering. Electron/Chrome fall back with --disable-gpu.
"Requires a paid account / feature flag" The gate is code you can read. Find it (env var? build define? SSR-embedded JSON?) and patch it for your local run. Document the patch.
"Run npm start" That's the human path (spawns a window, waits forever). Find or build the programmatic path - electron-forge start to build then launch via Playwright, or equivalent.
文档说…… 你要做的
"需要 macOS/Windows" 照样在 Linux 上启动它。应用很少会拒绝启动——它们只是因缺少某个 .so 而崩溃,apt-get 就能解决。针对你所在宿主机的钥匙串/通知的原生模块可能变成空操作;核心通常能跑起来。
"需要 GPU" 试试软件渲染。Electron/Chrome 会用 --disable-gpu 自动回退。
"需要付费账户 / 功能开关" 那道门槛就是你能读到的代码。找到它(环境变量?构建期 define?SSR 内嵌的 JSON?),为本地运行打上补丁,并把补丁记录下来。
"运行 npm start" 那是人类路径(启动一个窗口,然后永远等待)。找到或构建程序化路径——用 electron-forge start 构建再经 Playwright 启动,或类似方案。

【评论】该表要求把文档中的否定性论断("需要 GPU""仅限 macOS")当作待证伪的假设并通过实验推翻,其中甚至包括为绕过付费门槛而打补丁的做法,仅限于本地测试环境使用。

"Not supported on Linux" in a README written by a macOS developer
means "I never tried." You're about to try. If you give up here, the
skill you write is the README with extra steps.

由 macOS 开发者写下的 README 里那句"不支持 Linux",意思是"我从没试过"。而你就要去试了。如果你在这里放弃,你写出的 skill 就只是加了若干步骤的 README。

2. Execute - and BUILD the harness you need / 2. 执行——并构建你需要的 harness

You're in a headless Linux container. The app is going to fight you.
That fight is the content of the skill.

你在一个无头(headless)Linux 容器里。应用会跟你较劲。这场较劲正是 skill 的内容所在。

Keep a running NOTES.md as you go. Every error -> every fix -> every
command that finally worked. This scratchpad becomes the
Troubleshooting section.

边做边维护一份 NOTES.md。每个错误 -> 每次修复 -> 每条最终奏效的命令。这份草稿日后会成为故障排除(Troubleshooting)章节。

Work up to a real interaction:

逐步做到一次真实的交互:

Obstacles are content. You will hit weird ones - coordinate systems
that don't line up, APIs that return empty on this Electron version,
feature gates that hide the thing you need to test. Each of these gets
a bullet in Gotchas and (often) a helper in your driver. The gold
standard is a Gotchas section full of things nobody could have guessed.

**障碍本身就是内容。**你会撞上各种怪事——对不齐的坐标系、在这个 Electron 版本上返回空的 API、把你需要测试的东西藏起来的功能开关。每一条都值得在 Gotchas(坑点)章节里加一个条目,并且(通常)在你的驱动程序里加一个辅助函数。黄金标准是:Gotchas 章节里全是没人能预先猜到的东西。

The driver script gets committed alongside the skill. It is not
scaffolding. It is the way future agents (and humans) will drive this
app. It defaults to living inside the skill directory (for a web app
using chromium-cli, that means inline in SKILL.md - the heredoc
is the script). If it outgrows that - if the project's real test
suite wants to import from it - move it to scripts/ or e2e/ and
update SKILL.md to point there.

**驱动脚本要与 skill 一起提交。**它不是脚手架。它就是未来的代理(以及人类)驱动这个应用的方式。它默认放在 skill 目录内(对使用 chromium-cli 的 Web 应用来说,这意味着内联在 SKILL.md 里——heredoc 就是脚本)。如果它长大超出了这个范围——如果项目真正的测试套件想从它那里导入——就把它移到 scripts/ 或 e2e/,并更新 SKILL.md 指向那里。

3. Write SKILL.md / 3. 撰写 SKILL.md

Short. Point at the driver. Use template.md as the
starting structure - it has the frontmatter shape.

简短。指向驱动程序。用 template.md 作为起始结构——它带有 frontmatter 的样式。

The frontmatter matters. The name: becomes the slash command
(/run-billing). The description: is what Claude scans to decide
whether to auto-load this skill - put the verbs an agent would
actually type
in it: "run," "start," "build," "test," "screenshot."
Generic descriptions ("helpful utilities for billing") won't match.

frontmatter 很重要。name: 会成为斜杠命令(/run-billing)。description: 是 Claude 用来判断是否自动加载这个 skill 的依据——把代理真正会输入的动词写进去:"run""start""build""test""screenshot"。泛泛的描述("billing 的实用工具")匹配不上。

Body structure:

正文结构:

  1. One-paragraph intro: what this app is, how it's driven -
    <driver-path> under xvfb/tmux for desktop, chromium-cli for
    web, curl for a server.
    一段话的简介:这个应用是什么、如何驱动它——desktop 用 xvfb/tmux 下的 <driver-path>,web 用 chromium-cli,服务器用 curl。
  2. Prerequisites - the exact apt-get install line you ran.
    先决条件——你实际运行过的那条 apt-get install 命令。
  3. Build - the exact commands, in order. Include any patches you
    had to apply (feature gates, config overrides) with the exact sed
    or edit.
    构建——按顺序列出的确切命令。包含你不得不打的任何补丁(功能开关、配置覆盖),附上确切的 sed 或编辑内容。
  4. Run (agent path) - FIRST. How to launch the driver, what
    commands it accepts, where screenshots land. If it's a REPL, show
    the tmux wrapping. This is the section the next agent will actually
    use.
    运行(代理路径)——放在第一。如何启动驱动程序、它接受哪些命令、截图落在哪。如果是 REPL,展示 tmux 包装。这是下一个代理真正会使用的章节。
  5. Run (human path) - SECOND, if different. npm start -> window
    opens -> Ctrl-C. Brief. Note that it's useless headless.
    运行(人类路径)——放在第二,如果与代理路径不同的话。npm start -> 窗口打开 -> Ctrl-C。简短。注明它在无头环境下没用。
  6. Gotchas - the battle scars. The things that look like they
    should work but don't, and the workaround. If this section is
    generic, you didn't fight hard enough.
    Gotchas(坑点)——战斗留下的伤疤。那些看起来应该行得通却行不通的事,以及绕过办法。如果这个章节写得平淡无奇,说明你搏斗得不够狠。
  7. Troubleshooting - symptom -> fix. Only errors you actually hit.
    故障排除——症状 -> 解法。只收录你真正遇到过的错误。

Keep it verified (you ran it), prescriptive (one path, not
options), honest (flaky? slow? say so).

保持经过验证(你运行过)、规定动作(一条路径,不摆选项)、诚实(不稳定?慢?直说)。

Paths in SKILL.md are relative to <unit>/, not to the skill
directory. State this at the top if there's any ambiguity. When the
driver lives inside the skill, its path from <unit> is
.claude/skills/run-<unit-name>/driver.mjs - it's long, but explicit.

**SKILL.md 中的路径相对于 <unit>/,**而不是相对于 skill 目录。如有任何歧义,在文件顶部说明这一点。当驱动程序住在 skill 内部时,它相对于 <unit> 的路径是 .claude/skills/run-<unit-name>/driver.mjs——很长,但明确。

4. Verify / 4. 验证

Fresh shell, cd into the unit, follow the skill's SKILL.md
line-by-line without deviating. Any improvisation = a gap. Fix it.

开一个全新的 shell,cd 进入该 unit,逐行照着 skill 的 SKILL.md 执行,毫不偏离。任何即兴发挥都等于一个缺口。修掉它。

Project-type patterns / 项目类型模式

Pick a starting shape for your driver. These examples are shared with
the /run skill (same per-project-type patterns are used as the
fallback when no project-specific run skill exists) - if you're
authoring a new one, the example is your starting template.

为你的驱动程序挑一个起始形态。这些示例与 /run skill 共享(当不存在项目专属的 run skill 时,同样的按项目类型划分的模式被用作回退)——如果你正在编写新的模式,示例就是你的起始模板。

Project type Driver shape Example
Web server / API Background-launch + curl-based smoke script examples/server.md
CLI tool Representative-args smoke script, check exit codes + output examples/cli.md
TUI / interactive terminal tmux wrapper: send-keys / capture-pane examples/tui.md
Electron / desktop GUI Playwright _electron REPL driver under xvfb, screenshots, tmux-wrapped examples/electron.md
Browser-driven dev server + chromium-cli script examples/playwright.md
Library / SDK Import-and-call smoke script examples/library.md
项目类型 驱动形态 示例
Web 服务器 / API 后台启动 + 基于 curl 的冒烟脚本 examples/server.md
CLI 工具 具代表性参数的冒烟脚本,检查退出码 + 输出 examples/cli.md
TUI / 交互式终端 tmux 包装:send-keys / capture-pane examples/tui.md
Electron / 桌面 GUI xvfb 下的 Playwright _electron REPL 驱动,带截图、tmux 包装 examples/electron.md
浏览器驱动 开发服务器 + chromium-cli 脚本 examples/playwright.md
库 / SDK 导入并调用的冒烟脚本 examples/library.md

For a web app, start from examples/playwright.md
-- drive it with chromium-cli, no custom driver needed. For a
desktop app, start from examples/electron.md
-- it has the full _electron REPL driver skeleton, the tmux wrapping,
and the catalog of obstacles you'll hit.

对 Web 应用,从 examples/playwright.md 出发——用 chromium-cli 驱动它,无需自定义驱动程序。对桌面应用,从 examples/electron.md 出发——它包含完整的 _electron REPL 驱动骨架、tmux 包装,以及你会撞上的障碍清单。

What to include / 应当包含什么

What to leave out / 应当省略什么

Red flags - you are about to ship the wrong thing / 危险信号——你即将交付错误的东西

Stop and reconsider if:

出现以下情况时,停下来重新考虑: