bunshin
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBunshin - The Shadow Clones
Bunshin - 影分身
One art director, many clones. You keep the vision; the clones carry the width. This is genjutsu's heaviest pipeline. It exists for one job: a whole site, first version, from the client's real material.
You direct. You write the direction contract, build the foundation and the signature surface
yourself, and decide what the reviews mean. Clones (subagents) research, build pages in
parallel on files that never overlap, review through independent lenses, and apply the plan.
Impeccable, when installed, leads the product interview and draws the visual direction;
genjutsu's modules govern the motion, the platform principles, the tells and the audit. The
human is asked twice: once to summon, once to choose the direction, and again only to pass the
tier's round cap.
一位艺术指导,许多分身。你掌控愿景;分身承担广度。 这是 genjutsu 最重型的流水线。它只为一个任务而存在:基于客户的真实素材,交付完整网站的首版。
你负责指挥。你亲自撰写方向契约、搭建基础层和标志性界面,并决定评审意见的含义。分身(subagent)负责调研、在互不重叠的文件中并行构建页面、从不同视角进行审查,并执行方案。安装 Impeccable 后,由它主导产品访谈并绘制视觉方向;genjutsu 的模块则管理动效、平台原则、tells 和审查。人类只需被询问两次:一次用于召唤,一次用于选择方向;只有在需要超过层级的轮次上限时,才会再次询问。
Voice
语气
This skill speaks in two registers:
During execution - light ninja flair, short.
- "Summoning four clones for the research."
- "The clones return: six pages, five builds green."
- "Sealing round two."
In reports, summaries and gate messages - plain, factual, dev-readable. What was built, what
was verified and how, what was not, what it cost, what the client still has to supply. No mystic
prose. The gate messages are plain too: someone is deciding to spend money on them.
此 skill 采用两种表达方式:
执行期间——轻松的忍者风格,简短明了。
- “正在召唤四个分身进行调研。”
- “分身归来:六个页面,五个构建通过。”
- “封印第二轮。”
在报告、摘要和门控消息中——平实、客观且便于开发者阅读。说明构建了什么、如何验证、哪些内容未验证、花费了多少,以及客户还需要提供什么。不使用神秘化措辞。门控消息同样平实:毕竟有人需要根据这些消息决定是否投入资金。
bunshin, paint, cast
bunshin、paint、cast
| | | |
|---|---|---|---|
| For | One effect, component or section | One visual identity, one page or product | A whole site or web app, first version |
| Who works | You | You | You and a team of clones |
| Direction | An interaction thesis | Visual and interaction theses, MASTER.md | Impeccable's drawn direction (when installed) plus genjutsu's interaction thesis, as one contract |
| Proof | Quick audit | Full audit | Captures of every page, scripted tests, independent review lenses, verdicts, a cold-eyes pass |
| Human gates | Thesis, variants | Brainstorm, theses, design system, pages | Two: summon, direction |
| Cost | A session | A long session | Millions of tokens, hours (see "The summoning") |
| | | |
|---|---|---|---|
| 适用场景 | 单个效果、组件或区块 | 一套视觉识别、单个页面或产品 | 完整网站或 Web 应用的首版 |
| 执行者 | 你 | 你 | 你和一支分身团队 |
| 方向 | 一项交互命题 | 视觉与交互命题、MASTER.md | Impeccable 绘制的方向(已安装时)加上 genjutsu 的交互命题,合并为一份契约 |
| 证明 | 快速审查 | 完整审查 | 每个页面的截图、脚本测试、独立审查视角、裁决和冷眼审查 |
| 人工门控 | 命题、变体 | 头脑风暴、命题、设计系统、页面 | 两道:召唤、方向选择 |
| 成本 | 一次会话 | 一次长时间会话 | 数百万 token、数小时(见“召唤仪式”) |
Iron Rules
铁律
- The summoning comes first. No clone runs, and nothing heavier than reading happens, before the tier is answered. With nobody answering, see "When nobody is answering".
- Ask twice, then decide from evidence. The summoning and the direction are the user's. Every other decision is yours, made from the material, the research and the reviews, and written in the report.
- One art director. You write the direction contract, the foundation and the signature surface. Clones build inside the contract and never redefine it.
- Never code without a validated thesis. The direction gate validates the visual and the
interaction thesis together, with the line.
Allowed patterns: - Disjoint ownership. Every clone owns a declared list of files, and everything else is read-only to it. A shared need is a request, never an edit.
- No dev server, no shared browser. Clones capture with their own headless browser and build in copies, with the framework's binary.
- Evidence or it did not happen. Every finding cites a capture region or a , every "done" has a build that printed exit code 0, every behaviour a measured value.
file:line - Nothing invented. Facts come from the material and the answers. What is missing stays generic on the page, is marked in the content file, and is listed in the report.
- The loop ends on a rule. Minor-only from the finish reviewer, the tier's round cap, or a round that fixed nothing. Never open-ended, never past the cap without asking.
- Never install a dependency without asking. Impeccable and browser tooling included. The one install the summoning covers is the scaffold it names (see SUMMON). With nobody answering, nothing beyond it.
- Nothing leaves the machine unasked. No commit, no push, no deploy, no publish.
- Web only, for now. On Compose or SwiftUI, say that bunshin does not cover native stacks
yet and step down to .
paint
- 召唤必须最先进行。 在层级得到答复前,不运行任何分身,也不执行比阅读更重的操作。若无人答复,请参阅“无人答复时”。
- 询问两次,然后依据证据决策。 召唤和方向选择由用户决定。其他所有决定均由你根据素材、研究和评审作出,并写入报告。
- 只有一位艺术指导。 由你撰写方向契约、基础层和标志性界面。分身在契约内构建,绝不重新定义契约。
- 没有经过验证的命题,绝不编写代码。 方向门控会同时验证视觉命题和交互命题,并包含 行。
Allowed patterns: - 所有权互不重叠。 每个分身拥有明确列出的文件,其余文件对它只读。共享需求应提出请求,绝不能直接修改。
- 不使用开发服务器,也不共享浏览器。 分身使用自己的无头浏览器进行截图,并在副本中使用框架的二进制文件构建。
- 没有证据,就等于没有发生。 每项发现都要引用截图区域或 ;每项“完成”都必须对应一个打印退出码 0 的构建;每项行为都必须有可测量的数值。
file:line - 绝不虚构。 事实只能来自素材和答复。缺失内容在页面上保持通用表述,在内容文件中进行标记,并列入报告。
- 循环必须依据规则终止。 终止条件包括:完成审查者仅剩轻微问题、达到层级轮次上限,或某轮没有修复任何内容。绝不无限循环;未经询问也绝不超过上限。
- 未经询问,绝不安装依赖。 Impeccable 和浏览器工具也包括在内。召唤所涵盖的唯一一次安装,是 SUMMON 中指定的脚手架(见 SUMMON)。若无人答复,除该脚手架外不得执行任何安装。
- 未经允许,任何内容都不得离开本机。 不 commit、不 push、不 deploy、不 publish。
- 目前仅支持 Web。 遇到 Compose 或 SwiftUI 时,说明 bunshin 尚不覆盖原生技术栈,并降级使用 。
paint
Step down, when this is not the job
不适用时如何降级
bunshin is the wrong tool for anything smaller than a whole site. Recognise it at READ and say so
in one line before anything is spent:
| The request is | Go to |
|---|---|
| One component, one effect, one section | |
| One page, one landing, or a visual identity without a site behind it | |
| A whole site, but the host can spawn no subagent | |
| A native Compose or SwiftUI app | |
"This is one landing page, so paint is the right pipeline, not bunshin. Running paint."
To go there: invoke it as a skill when the host lists or ;
otherwise read its entry file next to this one, the one Markdown file at the top of
(or ), and follow it from its first step. The user can
overrule the step down; bunshin then runs, and says what it expects to be oversized.
genjutsu:paintgenjutsu:cast$GENJUTSU_SKILL_DIR/../paint/../cast/对于任何小于完整网站的任务,bunshin 都是错误的工具。应在 READ 阶段识别出来,并在产生任何成本前用一行说明:
| 请求类型 | 应改用 |
|---|---|
| 单个组件、效果或区块 | |
| 单个页面、单个落地页,或没有网站作为载体的视觉识别 | |
| 完整网站,但宿主无法生成 subagent | |
| 原生 Compose 或 SwiftUI 应用 | |
“这是一个落地页,因此应使用 paint 流水线,而不是 bunshin。现在运行 paint。”
要降级时:如果宿主列出了 或 ,则以 skill 方式调用;否则读取与本文件相邻的入口文件,即 (或 )顶部唯一的 Markdown 文件,并从第一步开始执行。用户可以否决降级;此时 bunshin 仍会运行,但必须说明该任务预计会超出其适用范围。
genjutsu:paintgenjutsu:cast$GENJUTSU_SKILL_DIR/../paint/../cast/What this host can summon
此宿主可以召唤什么
Check once, at READ. Capabilities, never product names: the tools this session actually exposes
decide, and the names in brackets are only what Claude Code calls them.
- A tool that spawns subagents, directly (Agent) or through a workflow script (Workflow). Without either there are no clones: step down. With the workflow tool, the templates run as written; with the subagent tool alone, the templates are the plan and you spawn the same clones by hand.
- A structured question tool (AskUserQuestion), for the two gates. Without one, one message per gate.
- A browser the session can drive, for the harvest of a social profile and your own look at pages. Clones never use it.
- Permissions. Clones run ,
rsync,ln,find, the framework's binary and a headless Chrome, in parallel, with new paths every time. When this session asks before each command, say so at the summoning and list the allow rules the run needs (for examplenode,Bash(rsync:*),Bash(find:*),Bash(node:*)); never write them into a settings file yourself.Bash(./node_modules/.bin/astro:*)
Then, in one shell call:
bash
for d in .claude/skills/impeccable .agents/skills/impeccable "$HOME/.claude/skills/impeccable" "$HOME/.agents/skills/impeccable"; do
# The entry file's name is assembled from parts: the bundle rewrites it when spelled out.
e="$d/SKILL"
if [ -f "$e.md" ]; then echo "impeccable: $d ($(sed -n 's/^version: //p' "$e.md" | head -1))"; break; fi
done
node -e 'process.exit(typeof WebSocket === "function" ? 0 : 1)' 2>/dev/null && echo "node: 22+ (shoot.mjs runs)" || echo "node: missing or older than 22 (shoot.mjs cannot run)"
for c in "${CHROME_PATH:-}" "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" "/Applications/Chromium.app/Contents/MacOS/Chromium" \
"$(command -v google-chrome google-chrome-stable chromium chromium-browser chrome 2>/dev/null | head -1)"; do
[ -n "$c" ] && [ -x "$c" ] && { echo "chrome: $c"; break; }
done
command -v magick >/dev/null 2>&1 && echo "imagemagick: yes" || echo "imagemagick: no"
python3 -c 'import PIL, numpy' 2>/dev/null && echo "python PIL + numpy: yes" || echo "python PIL + numpy: no"What each missing piece costs, said at the summoning, never discovered at phase 8:
| Missing | Consequence |
|---|---|
| Both the subagent and the workflow tool | bunshin does not run. Step down to paint. |
| The workflow tool (the subagent tool is there) | Same phases, clones spawned by hand with the prompts |
| Impeccable | The direction is drawn by bunshin's own round ( |
| A browser the session can drive | No harvest of a social profile, whose posts are listed by script: ask for the images and texts as files, or for the current site's address. |
| Node 22 or Chrome | No captures: reviewers read code only, and the review loop loses most of its value. Say so; install nothing. |
| ImageMagick, Pillow and numpy | No contact sheets, no cutouts: the material step shrinks to cropping by hand. |
在 READ 阶段只检查一次。依据实际能力,而不是产品名称:当前会话真正暴露的工具决定结果,方括号中的名称仅代表 Claude Code 对它们的称呼。
- 能够生成 subagent 的工具,可以直接使用(Agent),也可以通过 workflow 脚本完成(Workflow)。两者都没有时就不存在分身,必须降级。使用 workflow 工具时,模板会按原样运行;只有 subagent 工具时,模板作为计划使用,由你手动生成相同的分身。
- 结构化提问工具(AskUserQuestion),用于两道门控。若没有该工具,每道门控改用一条消息。
- 当前会话能够驱动的浏览器,用于采集社交资料,以及你亲自查看页面。分身绝不使用它。
- 权限。 分身会并行运行 、
rsync、ln、find、框架的二进制文件和无头 Chrome,每次都使用新路径。如果当前会话会在每条命令前询问,应在召唤时说明,并列出运行所需的允许规则,例如node、Bash(rsync:*)、Bash(find:*)、Bash(node:*);绝不自行将它们写入设置文件。Bash(./node_modules/.bin/astro:*)
然后在一次 shell 调用中执行:
bash
for d in .claude/skills/impeccable .agents/skills/impeccable "$HOME/.claude/skills/impeccable" "$HOME/.agents/skills/impeccable"; do
# The entry file's name is assembled from parts: the bundle rewrites it when spelled out.
e="$d/SKILL"
if [ -f "$e.md" ]; then echo "impeccable: $d ($(sed -n 's/^version: //p' "$e.md" | head -1))"; break; fi
done
node -e 'process.exit(typeof WebSocket === "function" ? 0 : 1)' 2>/dev/null && echo "node: 22+ (shoot.mjs runs)" || echo "node: missing or older than 22 (shoot.mjs cannot run)"
for c in "${CHROME_PATH:-}" "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" "/Applications/Chromium.app/Contents/MacOS/Chromium" \
"$(command -v google-chrome google-chrome-stable chromium chromium-browser chrome 2>/dev/null | head -1)"; do
[ -n "$c" ] && [ -x "$c" ] && { echo "chrome: $c"; break; }
done
command -v magick >/dev/null 2>&1 && echo "imagemagick: yes" || echo "imagemagick: no"
python3 -c 'import PIL, numpy' 2>/dev/null && echo "python PIL + numpy: yes" || echo "python PIL + numpy: no"每项缺失能力造成的代价,都必须在召唤时说明,绝不能拖到第 8 阶段才发现:
| 缺失项 | 后果 |
|---|---|
| subagent 工具和 workflow 工具均缺失 | bunshin 无法运行,降级使用 paint。 |
| 缺少 workflow 工具,但有 subagent 工具 | 阶段保持不变,使用 |
| 缺少 Impeccable | 方向由 bunshin 自己的轮次绘制( |
| 缺少当前会话能够驱动的浏览器 | 无法采集社交资料,也无法自动列出其中的帖子;应要求客户提供图片和文本文件,或当前网站的地址。 |
| 缺少 Node 22 或 Chrome | 无法生成截图;审查者只能阅读代码,审查循环的大部分价值都会丧失。必须如实说明,并且不安装任何内容。 |
| 缺少 ImageMagick、Pillow 和 numpy | 无法生成联系表和抠图;素材阶段会缩减为手动裁剪。 |
The summoning - tiers and cost
召唤仪式——层级与成本
One run has been measured: a seven-page site in two languages, built from a professional's social
profile, with two human touches. It spent about 10.5M subagent tokens over six to eight hours,
with one review, three refine rounds (one from the review, two from decisions files) and two
verdicts. The main session's own tokens were not measured. The tiers below are estimates scaled
from that run, and they scale with the page count. Say so every time you quote them.
| Tier | Refine rounds | Lenses | Cold eyes | Estimate, subagent tokens |
|---|---|---|---|---|
| lean | 1 | 3: finish, mobile, truth-tech | no | about 6M, 3 to 4 hours |
| standard (recommended) | up to 2 | 5 | in round 1's verdict, so round 2 applies its decisions | about 8 to 9M, 4 to 6 hours |
| full | up to 4 | 5 | every verdict | about 12 to 13M, 6 to 10 hours |
What the measured run spent, per unit, to scale an estimate: research about 0.6M; about 0.4M per
page clone (2.3M for six); a five-lens review with its plan about 1.6M; a refine round from a plan
about 1.6M with eight owners; a refine round that applies a decisions file about 1.75M; a verdict
with cold eyes about 0.35M; the documenter about 0.2M. Two units were not measured and are
estimated from these: a three-lens review with its plan, about 1.1M, and a verdict without cold
eyes, about half of one with them.
<!-- genjutsu:shared:preview:start -->目前有一次经过测量的运行:一个双语七页网站,基于某位专业人士的社交资料构建,并包含两处人工处理。它在六到八小时内消耗了约 10.5M subagent token,完成一次审查、三轮细化(其中一轮来自审查,另外两轮来自决策文件)和两次裁决。主会话自身的 token 数量未计入测量。下面的层级是根据该次运行缩放得到的估算值,并会随页面数量变化。每次引用这些数字时都必须说明这一点。
| 层级 | 细化轮次 | 审查视角 | 冷眼审查 | 估算 subagent token |
|---|---|---|---|---|
| lean | 1 | 3 个:结束、移动端、真实性与技术 | 无 | 约 6M,3 至 4 小时 |
| standard(推荐) | 最多 2 | 5 个 | 包含在第 1 轮裁决中,因此第 2 轮会应用其决策 | 约 8 至 9M,4 至 6 小时 |
| full | 最多 4 | 5 个 | 每次裁决均包含 | 约 12 至 13M,6 至 10 小时 |
用于缩放估算的实测单位成本:调研约 0.6M;每个页面分身约 0.4M(6 个页面共 2.3M);包含计划在内的五视角审查约 1.6M;根据计划执行一轮细化、涉及八个所有者时约 1.6M;应用决策文件的一轮细化约 1.75M;包含冷眼审查的裁决约 0.35M;文档整理者约 0.2M。另有两个单位未经测量,因此根据上述数据估算:包含计划的三个视角审查约 1.1M;不包含冷眼审查的裁决约为包含冷眼审查时的一半。
<!-- genjutsu:shared:preview:start -->Showing Your Work - The Preview Gate
展示成果——预览门控
Some gates in this pipeline exist so the user can look at something before approving it: an interaction thesis, a set of variants, a visual identity, a design system. Motion and color do not survive being described in a sentence - approving an easing curve you cannot see is not approval, it's a guess.
So before the first gate of that kind, ask how they want to see it. Then never ask again.
The menu - present it once, at the first visual gate, with the recommended default marked:
Before I show you this - how do you want to see it?A. Rendered page - a live HTML page: the real easing curve, the real durations, an element actually doing the motion. B. Live preview - a throwaway route in your project, real stack, real tokens. Native: a/@Previewscratch file. C. Inline - written out here in the conversation.#Preview
Recommended default - state it in the menu, never apply it silently:
| Situation | Default |
|---|---|
| Scope is light (a hover, one transition) | C - inline |
| Scope is medium or full, web stack | A - rendered page |
| Scope is medium or full, Compose / SwiftUI | B - live preview, A as second choice |
| A full visual identity or design system is on the table | A - rendered page |
| No dev server, or the repo must not be written to | A - rendered page |
| Host is Cowork and there is no project checkout to write into | A - rendered page, B is unavailable |
The choice sticks for the whole session. At every later gate, announce the mode in one line ("Variants on a rendered page.") and go. Do not reopen the menu. The user switches by saying so - "show me that as text", "put it on a page", "just tell me" - respect it immediately, and the new mode becomes the session default from then on.
Which host is this? The gate fires before LOAD, so does not exist yet and this stands on its own. Detect once, cheaply, then map:
$SKILL_BASEbash
if [ -d /mnt/skills/plugins ] || [ -d /mnt/skills/user ]; then
GENJUTSU_HOST=claude-ai
elif [ -d /mnt/.claude/skills ] \
|| [ -n "$(find /sessions -maxdepth 6 -type d -path '*/.claude/skills' 2>/dev/null | head -1)" ]; then
GENJUTSU_HOST=cowork
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] || [ -d "$HOME/.claude/plugins" ]; then
GENJUTSU_HOST=claude-code
else
GENJUTSU_HOST=unknown
fi
echo "genjutsu host: $GENJUTSU_HOST"Cowork is tested before Claude Code on purpose: both can have a tree, and only Cowork has the session-rooted skills mount, so the specific signal has to win.
~/.claudeProducing the preview - resolve the host, degrade, never fail:
| Host | A - rendered page | C - inline |
|---|---|---|
| claude.ai | Rendered natively as an artifact. Just produce one. | Written out in the conversation. |
| Cowork | The host's persistent artifact. It outlives the turn, which is what a design system needs: the user comes back to it. | The host's inline widget, rendered in place. Right default for a short task. |
| Claude Code | The | Written out in the conversation. |
| unknown (any other host) | The capability rule below. | Written out in the conversation. |
A, by capability. Mode A needs one of three things, tried in this order: a tool in this session that renders HTML for the user (on Claude hosts, the artifact); else a self-contained, throwaway HTML file written to a temporary path and opened in a browser the session can drive, if it has one; else that same file, its path handed to the user with one line on how to open it. Check the tools the session actually exposes rather than assuming any by name. If nothing works, fall back to C rather than failing the gate: an inline preview always beats an aborted one.
B - live preview needs a project to write into. On Cowork there often is not one, so offer A and C, and say in one line why B is missing instead of listing an option that cannot work.
What goes in it. A preview that restates the sentence in a nicer font is worthless. Carry what a sentence cannot:
| Gate | The preview shows |
|---|---|
| An interaction thesis | The easing curve plotted in SVG with its exact value printed, an element that actually performs the interaction with a replay button, the bare numbers (duration, delay, stagger, spring parameters), and a reduced-motion toggle showing the degraded version. |
| A set of variants | That same card per variant, side by side, with one global trigger firing them simultaneously so they are comparable, plus a per-variant replay. |
| A visual identity | Swatches with hex and contrast ratio against their background, a type specimen at the real scale steps, spacing bars, radii and shadow samples, one real button and one real card. |
| A design system | Every token category rendered, the five states of each base component (default, hover, focus, active, disabled), light and dark side by side when both exist. |
Rules the preview obeys:
- The message that carries it names the thesis in plain text. Whatever the mode, it opens
with the thesis in one sentence, labelled (or
Interaction thesis:), then itsVisual thesis:line, says in one line that the page is the proposal and not the build, and ends with the validation question. It holds no implementation: code starts in a later turn, after a yes. Someone who picked A or B must never have to look for where the thesis went.Allowed patterns: - It is throwaway. It never becomes the implementation. Build the real thing from the validated thesis and the loaded sub-skills, never by porting preview markup. This matters most on Compose / SwiftUI, where the HTML approximates timing and curve only, not rendering - say so on the page.
- Delete the live-preview route after validation, unless the user asks to keep it.
- Never install a dependency to build a preview.
- Never start a dev server without asking.
- Only show values that are in the thesis. A number that is not in the thesis has no business in the preview - otherwise the preview becomes a second thesis, and nobody validated that one.
How bunshin uses the preview gate. Its only visual gate is the direction, and its only
questions are the two gates, so it never opens the menu. With Impeccable, the decision page is
the preview. Without it, the direction cards are shown as a rendered page (mode A), announced in
one line. The user can still switch mode by saying so.
<!-- genjutsu:shared:headless:start -->此流水线中的某些门控是为了让用户在批准前亲眼查看成果:交互命题、一组变体、视觉识别或设计系统。动效和颜色无法通过一句文字完整传达——批准一条看不见的缓动曲线并不叫批准,而只是猜测。
因此,在遇到第一个此类门控前,先询问用户希望以何种方式查看。此后绝不再询问。
菜单——在第一个视觉门控处展示一次,并标记推荐默认项:
在我展示之前——您希望以什么方式查看?A. 渲染页面——一个实时 HTML 页面:真实的缓动曲线、真实的持续时间,以及实际执行动效的元素。 B. 实时预览——项目中的临时路由,使用真实技术栈和真实 token。原生项目使用/@Preview临时文件。 C. 内联展示——直接写在当前对话中。#Preview
推荐默认项——必须在菜单中说明,绝不能静默应用:
| 情况 | 默认项 |
|---|---|
| 范围较轻(悬停、单个过渡) | C——内联展示 |
| 范围为中等或完整,且使用 Web 技术栈 | A——渲染页面 |
| 范围为中等或完整,且使用 Compose / SwiftUI | B——实时预览,A 作为次选 |
| 涉及完整视觉识别或设计系统 | A——渲染页面 |
| 没有开发服务器,或不得写入代码仓库 | A——渲染页面 |
| 宿主为 Cowork,且没有可供写入的项目检出目录 | A——渲染页面,B 不可用 |
所选方式在整个会话中保持不变。 后续每次门控只需用一行说明当前方式(“变体将以渲染页面展示。”),然后继续。不得重新打开菜单。用户可以主动切换,例如“把它显示为文本”“把它放在页面上”“直接告诉我”;应立即尊重该要求,并从此时起将新方式作为会话默认项。
这是哪种宿主? 门控会在 LOAD 之前触发,因此 尚不存在,以下判断可独立执行。只进行一次低成本检测,然后进行映射:
$SKILL_BASEbash
if [ -d /mnt/skills/plugins ] || [ -d /mnt/skills/user ]; then
GENJUTSU_HOST=claude-ai
elif [ -d /mnt/.claude/skills ] \
|| [ -n "$(find /sessions -maxdepth 6 -type d -path '*/.claude/skills' 2>/dev/null | head -1)" ]; then
GENJUTSU_HOST=cowork
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] || [ -d "$HOME/.claude/plugins" ]; then
GENJUTSU_HOST=claude-code
else
GENJUTSU_HOST=unknown
fi
echo "genjutsu host: $GENJUTSU_HOST"先检测 Cowork 而不是 Claude Code 是有意为之:两者都可能存在 目录树,但只有 Cowork 拥有以会话为根目录的 skills 挂载点,因此必须优先识别这一特定信号。
~/.claude生成预览——识别宿主,按能力降级,绝不失败:
| 宿主 | A——渲染页面 | C——内联展示 |
|---|---|---|
| claude.ai | 原生渲染为 artifact,直接生成即可。 | 写在对话中。 |
| Cowork | 使用宿主的持久化 artifact。它会保留至后续轮次,设计系统正需要这种能力,用户可以稍后返回查看。 | 使用宿主的内联组件直接呈现。短任务的推荐默认项。 |
| Claude Code | 会话提供 | 写在对话中。 |
| unknown(其他任何宿主) | 遵循下面的能力规则。 | 写在对话中。 |
A——按能力判断。 模式 A 需要以下三项能力之一,并按顺序尝试:当前会话中有能为用户渲染 HTML 的工具(Claude 宿主上为 artifact);否则,如果会话有可驱动浏览器,则生成一个自包含的临时 HTML 文件并写入临时路径,然后在浏览器中打开;否则,将同一文件路径交给用户,并用一行说明如何打开。应检查当前会话实际暴露的工具,不要仅凭名称做出假设。如果全都不可用,则降级为 C,而不是让门控失败:内联预览永远优于中止门控。
B——实时预览需要可写入的项目。 Cowork 通常没有项目,因此应提供 A 和 C,并用一行说明 B 缺失的原因,而不是列出无法执行的选项。
预览中应包含什么。 只是把一句话换一种漂亮字体展示毫无价值。预览必须承载文字无法表达的内容:
| 门控 | 预览展示内容 |
|---|---|
| 交互命题 | 在 SVG 中绘制缓动曲线并标出精确数值;提供一个实际执行交互并带重播按钮的元素;列出基础数字(持续时间、延迟、错峰、spring 参数);以及一个展示降级版本的 reduced-motion 开关。 |
| 一组变体 | 每个变体各展示一张相同卡片,并排比较;使用一个全局触发器同时启动所有变体;每个变体还提供独立重播。 |
| 视觉识别 | 展示带十六进制值和相对背景对比度的色板;按真实字号阶梯展示字体样张;展示间距条、圆角和阴影样例;以及一个真实按钮和一张真实卡片。 |
| 设计系统 | 渲染每一类 token,并展示每个基础组件的五种状态(默认、悬停、焦点、激活、禁用);若浅色和深色模式同时存在,则并排展示。 |
预览遵守的规则:
- 承载预览的消息必须用平实文字点明命题。 无论采用哪种模式,开头都用一句话说明命题,并加上标签(或
Interaction thesis:),然后给出Visual thesis:行;用一行说明该页面是提案而非最终构建,最后提出验证问题。Allowed patterns: - 它不包含任何实现内容:代码只能在用户确认后的后续轮次中开始。选择了 A 或 B 的用户绝不应该还需要寻找命题被放在哪里。
- 它是临时内容,绝不会成为最终实现。 真正产品应根据经过验证的命题和已加载的子 skill 构建,绝不能移植预览标记。这一点对 Compose / SwiftUI 尤其重要,因为 HTML 只近似表现时序和曲线,并不代表实际渲染;必须在页面上说明。
- 除非用户要求保留,否则验证后删除实时预览路由。
- 绝不为了构建预览而安装依赖。
- 未经询问,绝不启动开发服务器。
- 只展示命题中已有的数值。命题之外的数字不应出现在预览中,否则预览就会成为第二份未经验证的命题。
bunshin 如何使用预览门控。 它唯一的视觉门控是方向选择,唯一的提问也只有这两道门控,因此不会打开菜单。安装 Impeccable 时,决策页面本身就是预览;未安装时,方向卡片以渲染页面展示(模式 A),并用一行说明。用户仍可通过语言切换模式。
<!-- genjutsu:shared:headless:start -->When nobody is answering
无人答复时
Some sessions have no human on the other end: an eval harness, a CI job, another agent driving
this skill. You know it because the request or the host says so (a non-interactive run, "do not
ask questions", a prompt that pre-answers the gates), never because one question went unanswered
for a while. When the request pre-answers a gate, that answer stands: the gate is answered, not
skipped.
In such a session every gate still produces its output. What changes is that nobody validates it:
- Discovery and brainstorm questions: do not ask them. Answer each from the brief and the scan, and name every answer as an assumption in the thesis.
- Preview gate: take the default the menu recommends for this scope and stack, announce it in one line, and go on.
- Thesis gate: take the thesis you would have proposed, say in one line that it is not validated, and go on. The final report prints it, marked UNVALIDATED.
- Dependencies: never install one. Where the thesis wants a library the project does not have, use the stack's native APIs and name the missing dependency in the final report.
Everything else holds: the thesis is written before any code, the modules are loaded, and the
audit reports evidence. A headless run skips the waiting, never the work.
<!-- genjutsu:shared:headless:end -->
What nobody answering means for bunshin. The tier is a budget, and nobody agreed to one.
A headless run goes past READ only when the request names the tier, and that answer stands.
Without one, stop after READ, print the summoning message as the final report, and spawn
nothing. When it runs: the scaffold is the stack the scan finds, or the one the request names
when it also says installs are allowed (the shared rule above forbids any other install);
otherwise plain static HTML and CSS, with no install (FOUNDATION, "On plain HTML and CSS"); the
direction is the card the draw assigned,
taken without serving the decision page, or without Impeccable the first of the three worlds
carried forward; an Impeccable that is not installed stays not installed; every gate answer is
marked UNVALIDATED in the report.
有些会话没有真人参与,例如评测框架、CI 作业,或由另一个 Agent 驱动此 skill。只有当请求或宿主明确说明非交互运行、“不要提问”或提示已预先回答门控时,才能判断属于这种情况,不能因为某个问题暂时无人回答就作出判断。当请求预先回答门控时,该答案立即生效:门控视为已回答,而不是被跳过。
在此类会话中,每道门控仍要产生输出。变化仅在于无人验证这些输出:
- 发现和头脑风暴问题: 不提问。根据简报和扫描结果逐一回答,并在命题中将每项答案标记为假设。
- 预览门控: 采用菜单针对当前范围和技术栈推荐的默认项,用一行说明后继续。
- 命题门控: 采用原本准备提出的命题,用一行说明其未经验证,然后继续。最终报告中将其标为 UNVALIDATED。
- 依赖: 绝不安装任何依赖。如果命题需要项目中不存在的库,应使用技术栈原生 API,并在最终报告中注明缺失的依赖。
其他所有规则仍然有效:先写命题再编写代码,加载各模块,审查报告提供证据。无头运行只是跳过等待,绝不跳过工作。
<!-- genjutsu:shared:headless:end -->
无人答复对 bunshin 的含义。 层级代表预算,而没有人同意该预算。只有当请求明确指定层级时,无头运行才能越过 READ 阶段,该指定立即生效。如果没有指定,则在 READ 后停止,将召唤消息作为最终报告输出,并且不生成任何分身。
实际运行时:若请求同时说明允许安装依赖,脚手架应使用扫描发现的技术栈,或请求指定的技术栈;共享规则仍禁止执行其他任何安装。否则使用纯静态 HTML 和 CSS,不进行安装(见 FOUNDATION 中的“On plain HTML and CSS”)。方向采用抽取环节分配的卡片,不提供决策页面;未安装 Impeccable 时,则采用三个世界中第一个被保留的世界。未安装的 Impeccable 仍保持未安装状态。报告中的每项门控答案均标为 UNVALIDATED。
Sub-skills Path Detection
子 skill 路径检测
Tell the block where this skill lives. The block's first line reads .
Claude Code fills it in by itself. On any other host, put one line in front of the block, in the
same shell call, naming the directory you read this file from:
. When the genjutsu router printed a
line, use that value as it is.
<!-- genjutsu:shared:skill-base:start -->
GENJUTSU_SKILL_DIRGENJUTSU_SKILL_DIR='/absolute/path/to/bunshin'GENJUTSU_SKILL_DIR=This block defines shell state, and shell state does not survive between shell calls.
, and exist only inside the single shell call that ran
this block. Any later phase - and every phase after a user-validation gate is a later phase -
starts from nothing. So: re-emit this whole block in the same shell call as the
lines you are about to run. Never in a call that did
not define it: the path resolves to , the fails, and the module is lost.
$SKILL_BASEload_skillload_refload_skillcat "$SKILL_BASE/..."/<name>/...catIf the block prints , stop the pipeline. Show the
user the message, install command included, and do nothing else: every later step depends
on the modules, and running without them produces exactly the generic output this skill
exists to prevent.
could not find the genjutsu modulesbash
GENJUTSU_SKILL_DIR="${GENJUTSU_SKILL_DIR:-${CLAUDE_SKILL_DIR}}"告诉代码块此 skill 所在的位置。 代码块第一行读取 。Claude Code 会自动填充。在其他宿主上,应在同一次 shell 调用中,将读取此文件的目录放在代码块之前:
。如果 genjutsu 路由器已经打印了 行,直接使用该值。
<!-- genjutsu:shared:skill-base:start -->
GENJUTSU_SKILL_DIRGENJUTSU_SKILL_DIR='/absolute/path/to/bunshin'GENJUTSU_SKILL_DIR=此代码块定义 shell 状态,而 shell 状态不会在多次调用之间保留。
、 和 仅存在于运行此代码块的那一次 shell 调用中。之后的每个阶段——用户验证门控之后的每个阶段都是后续阶段——都从空白状态开始。因此:必须在与即将运行的 命令相同的 shell 调用中,重新输出整个代码块。 绝不要在未定义该路径的调用中执行 :路径会解析为 , 将失败,模块也会丢失。
$SKILL_BASEload_skillload_refload_skillcat "$SKILL_BASE/..."/<name>/...cat如果代码块输出 ,立即停止流水线。 向用户显示该消息和安装命令,不执行任何其他操作:后续每个步骤都依赖这些模块,缺少模块时运行只会产生此 skill 原本要防止的通用输出。
could not find the genjutsu modulesbash
GENJUTSU_SKILL_DIR="${GENJUTSU_SKILL_DIR:-${CLAUDE_SKILL_DIR}}"Resolution order, first hit wins:
Resolution order, first hit wins:
0. claude.ai, /mnt/skills/plugins (or the older /mnt/skills/user): the
0. claude.ai, /mnt/skills/plugins (or the older /mnt/skills/user): the
genjutsu bundle.
genjutsu bundle.
1. This skill's own directory: its _jutsu, or the _jutsu next to it.
1. This skill's own directory: its _jutsu, or the _jutsu next to it.
2. ${CLAUDE_PLUGIN_ROOT}/skills/_jutsu, when Claude Code substituted it.
2. ${CLAUDE_PLUGIN_ROOT}/skills/_jutsu, when Claude Code substituted it.
3. Bounded probes: .claude/skills and .agents/skills from $PWD upward, then
3. Bounded probes: .claude/skills and .agents/skills from $PWD upward, then
the skills directories installers write to, then /sessions (Cowork).
the skills directories installers write to, then /sessions (Cowork).
4. The Claude Code plugin cache, newest version. Last on purpose: an old
4. The Claude Code plugin cache, newest version. Last on purpose: an old
plugin install must never win over a newer bundle.
plugin install must never win over a newer bundle.
Resolved from scratch every time. A cache was tried here and removed: after a
Resolved from scratch every time. A cache was tried here and removed: after a
plugin update the old version directory is still on disk, so a cached path
plugin update the old version directory is still on disk, so a cached path
passes an "is it a directory" check and serves the previous release.
passes an "is it a directory" check and serves the previous release.
A _jutsu directory counts only if it holds motion-principles. The shared
A _jutsu directory counts only if it holds motion-principles. The shared
skills directory of npx serves about 80 agents, so a directory name proves
skills directory of npx serves about 80 agents, so a directory name proves
nothing. The entry file is named SKILL or GUIDE depending on the artifact
nothing. The entry file is named SKILL or GUIDE depending on the artifact
(the bundle renames it at packaging time), so the name is assembled from
(the bundle renames it at packaging time), so the name is assembled from
parts: spelled out in full, the packaging step would rewrite it too.
parts: spelled out in full, the packaging step would rewrite it too.
genjutsu_is_jutsu() {
for d in SKILL GUIDE; do
[ -f "$1/motion-principles/$d.md" ] && return 0
done
return 1
}
genjutsu_is_jutsu() {
for d in SKILL GUIDE; do
[ -f "$1/motion-principles/$d.md" ] && return 0
done
return 1
}
Print the first genjutsu _jutsu among the candidate paths read on stdin.
Print the first genjutsu _jutsu among the candidate paths read on stdin.
genjutsu_first_jutsu() {
while read -r jutsu_c; do
genjutsu_is_jutsu "$jutsu_c" && { printf '%s\n' "$jutsu_c"; return 0; }
done
return 1
}
SKILL_BASE=""
genjutsu_first_jutsu() {
while read -r jutsu_c; do
genjutsu_is_jutsu "$jutsu_c" && { printf '%s\n' "$jutsu_c"; return 0; }
done
return 1
}
SKILL_BASE=""
0. claude.ai mounts uploaded skills under /mnt/skills/plugins/<name>/ (seen on
0. claude.ai mounts uploaded skills under /mnt/skills/plugins/<name>/ (seen on
2026-09-28), next to the user's other skills; /mnt/skills/user before that.
2026-09-28), next to the user's other skills; /mnt/skills/user before that.
GENJUTSU_CLAUDE_AI_ROOT stands in for /mnt/skills in the test suite only.
GENJUTSU_CLAUDE_AI_ROOT stands in for /mnt/skills in the test suite only.
Only a _jutsu holding motion-principles counts: a mount without genjutsu in it
Only a _jutsu holding motion-principles counts: a mount without genjutsu in it
must never pass for a resolved base.
must never pass for a resolved base.
genjutsu_claude_ai="${GENJUTSU_CLAUDE_AI_ROOT:-/mnt/skills}"
for claude_root in "$genjutsu_claude_ai/plugins" "$genjutsu_claude_ai/user"; do
[ -z "$SKILL_BASE" ] && [ -d "$claude_root" ] || continue
SKILL_BASE="$(find -L "$claude_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)"
done
genjutsu_claude_ai="${GENJUTSU_CLAUDE_AI_ROOT:-/mnt/skills}"
for claude_root in "$genjutsu_claude_ai/plugins" "$genjutsu_claude_ai/user"; do
[ -z "$SKILL_BASE" ] && [ -d "$claude_root" ] || continue
SKILL_BASE="$(find -L "$claude_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)"
done
1. This skill's own directory. Empty means unknown: never probe "/_jutsu".
1. This skill's own directory. Empty means unknown: never probe "/_jutsu".
if [ -z "$SKILL_BASE" ] && [ -n "$GENJUTSU_SKILL_DIR" ]; then
SKILL_BASE="$(printf '%s\n' "$GENJUTSU_SKILL_DIR/_jutsu" "$GENJUTSU_SKILL_DIR/../_jutsu" | genjutsu_first_jutsu)"
fi
if [ -z "$SKILL_BASE" ] && [ -n "$GENJUTSU_SKILL_DIR" ]; then
SKILL_BASE="$(printf '%s\n' "$GENJUTSU_SKILL_DIR/_jutsu" "$GENJUTSU_SKILL_DIR/../_jutsu" | genjutsu_first_jutsu)"
fi
2. Claude Code plugin root.
2. Claude Code plugin root.
if [ -z "$SKILL_BASE" ] && [ -n "${CLAUDE_PLUGIN_ROOT}" ]; then
SKILL_BASE="$(printf '%s\n' "${CLAUDE_PLUGIN_ROOT}/skills/_jutsu" | genjutsu_first_jutsu)"
fi
if [ -z "$SKILL_BASE" ] && [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then
SKILL_BASE="$(printf '%s\n' "${CLAUDE_PLUGIN_ROOT}/skills/_jutsu" | genjutsu_first_jutsu)"
fi
3. Bounded probes, following symlinks (npx links .claude/skills/<name> to
3. Bounded probes, following symlinks (npx links .claude/skills/<name> to
.agents/skills/<name>). The case guard stops the walk at "/", "." or "".
.agents/skills/<name>). The case guard stops the walk at "/", "." or "".
probe_dir="${PWD:-$(pwd)}"
probe_n=0
while [ -z "$SKILL_BASE" ] && [ "$probe_n" -lt 24 ]; do
probe_n=$((probe_n + 1))
SKILL_BASE="$(find -L "$probe_dir/.claude/skills" "$probe_dir/.agents/skills" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)"
case "$probe_dir" in /|.|"") break ;; esac
probe_dir="$(dirname "$probe_dir")"
done
for probe_root in "$HOME/.agents/skills" "$HOME/.claude/skills" "$HOME/.codex/skills"
"$HOME/.cursor/skills" /mnt/.claude/skills; do [ -z "$SKILL_BASE" ] && [ -d "$probe_root" ] || continue SKILL_BASE="$(find -L "$probe_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)" done if [ -z "$SKILL_BASE" ] && [ -d /sessions ]; then SKILL_BASE="$(find -L /sessions -maxdepth 8 -type d -path '/.claude/skills//_jutsu' 2>/dev/null | genjutsu_first_jutsu)" fi
"$HOME/.cursor/skills" /mnt/.claude/skills; do [ -z "$SKILL_BASE" ] && [ -d "$probe_root" ] || continue SKILL_BASE="$(find -L "$probe_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)" done if [ -z "$SKILL_BASE" ] && [ -d /sessions ]; then SKILL_BASE="$(find -L /sessions -maxdepth 8 -type d -path '/.claude/skills//_jutsu' 2>/dev/null | genjutsu_first_jutsu)" fi
probe_dir="${PWD:-$(pwd)}"
probe_n=0
while [ -z "$SKILL_BASE" ] && [ "$probe_n" -lt 24 ]; do
probe_n=$((probe_n + 1))
SKILL_BASE="$(find -L "$probe_dir/.claude/skills" "$probe_dir/.agents/skills" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)"
case "$probe_dir" in /|.|"") break ;; esac
probe_dir="$(dirname "$probe_dir")"
done
for probe_root in "$HOME/.agents/skills" "$HOME/.claude/skills" "$HOME/.codex/skills"
"$HOME/.cursor/skills" /mnt/.claude/skills; do [ -z "$SKILL_BASE" ] && [ -d "$probe_root" ] || continue SKILL_BASE="$(find -L "$probe_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)" done if [ -z "$SKILL_BASE" ] && [ -d /sessions ]; then SKILL_BASE="$(find -L /sessions -maxdepth 8 -type d -path '/.claude/skills//_jutsu' 2>/dev/null | genjutsu_first_jutsu)" fi
"$HOME/.cursor/skills" /mnt/.claude/skills; do [ -z "$SKILL_BASE" ] && [ -d "$probe_root" ] || continue SKILL_BASE="$(find -L "$probe_root" -maxdepth 2 -type d -name _jutsu 2>/dev/null | genjutsu_first_jutsu)" done if [ -z "$SKILL_BASE" ] && [ -d /sessions ]; then SKILL_BASE="$(find -L /sessions -maxdepth 8 -type d -path '/.claude/skills//_jutsu' 2>/dev/null | genjutsu_first_jutsu)" fi
4. Claude Code plugin cache, newest version first. Numeric version
4. Claude Code plugin cache, newest version first. Numeric version
directories only, so a bare marketplace clone never wins.
directories only, so a bare marketplace clone never wins.
if [ -z "$SKILL_BASE" ] && [ -d "$HOME/.claude/plugins/cache" ]; then
SKILL_BASE="$(find "$HOME/.claude/plugins/cache" -maxdepth 6 -type d -path '/genjutsu/[0-9]/skills/_jutsu' 2>/dev/null | sort -V -r | genjutsu_first_jutsu)"
fi
[ -n "$SKILL_BASE" ] && SKILL_BASE="$(cd "$SKILL_BASE" 2>/dev/null && pwd -P)"
if [ -z "$SKILL_BASE" ] && [ -d "$HOME/.claude/plugins/cache" ]; then
SKILL_BASE="$(find -L "$HOME/.claude/plugins/cache" -maxdepth 6 -type d -path '/genjutsu/[0-9]/skills/_jutsu' 2>/dev/null | sort -V -r | genjutsu_first_jutsu)"
fi
[ -n "$SKILL_BASE" ] && SKILL_BASE="$(cd "$SKILL_BASE" 2>/dev/null && pwd -P)"
Stop instead of running the pipeline without its modules. Name every root that
Stop instead of running the pipeline without its modules. Name every root that
was tried, so a new layout can be reported instead of guessed.
was tried, so a new layout can be reported instead of guessed.
if [ -z "$SKILL_BASE" ]; then
echo "genjutsu: could not find the genjutsu modules (a _jutsu directory holding motion-principles)." >&2
echo " genjutsu's pipelines do not work without them. Install the full bundle:" >&2
echo " any agent npx skills add https://genjutsu.athevon.dev -g" >&2
echo " Claude Code /plugin marketplace add AThevon/genjutsu, then /plugin install genjutsu" >&2
echo " claude.ai upload genjutsu.zip in Customize > Skills" >&2
echo " npx skills add AThevon/genjutsu installs the pipelines without their modules." >&2
echo " Tried: /mnt/skills/plugins, /mnt/skills/user, GENJUTSU_SKILL_DIR (${GENJUTSU_SKILL_DIR:-empty}) and its parent," >&2
echo " $CLAUDE_PLUGIN_ROOT, .claude/skills and .agents/skills from $PWD upward," >&2
echo " ~/.agents/skills, ~/.claude/skills, ~/.codex/skills, ~/.cursor/skills," >&2
echo " /mnt/.claude/skills, /sessions, ~/.claude/plugins/cache." >&2
echo "genjutsu: stop the pipeline here and show this message to the user." >&2
return 1 2>/dev/null || exit 1
fi
echo "genjutsu: modules from $SKILL_BASE" >&2
if [ -z "$SKILL_BASE" ]; then
echo "genjutsu: could not find the genjutsu modules (a _jutsu directory holding motion-principles)." >&2
echo " genjutsu's pipelines do not work without them. Install the full bundle:" >&2
echo " any agent npx skills add https://genjutsu.athevon.dev -g" >&2
echo " Claude Code /plugin marketplace add AThevon/genjutsu, then /plugin install genjutsu" >&2
echo " claude.ai upload genjutsu.zip in Customize > Skills" >&2
echo " npx skills add AThevon/genjutsu installs the pipelines without their modules." >&2
echo " Tried: /mnt/skills/plugins, /mnt/skills/user, GENJUTSU_SKILL_DIR (${GENJUTSU_SKILL_DIR:-empty}) and its parent," >&2
echo " $CLAUDE_PLUGIN_ROOT, .claude/skills and .agents/skills from $PWD upward," >&2
echo " ~/.agents/skills, ~/.claude/skills, ~/.codex/skills, ~/.cursor/skills," >&2
echo " /mnt/.claude/skills, /sessions, ~/.claude/plugins/cache." >&2
echo "genjutsu: stop the pipeline here and show this message to the user." >&2
return 1 2>/dev/null || exit 1
fi
echo "genjutsu: modules from $SKILL_BASE" >&2
Print a module's entry file. A missing module does not stop the pipeline (a
Print a module's entry file. A missing module does not stop the pipeline (a
partial claude.ai upload is legitimate), but it is announced, and the final
partial claude.ai upload is legitimate), but it is announced, and the final
report lists it: shell state does not survive, so the model keeps the list.
report lists it: shell state does not survive, so the model keeps the list.
load_skill() {
for d in SKILL GUIDE; do
if [ -f "$SKILL_BASE/$1/$d.md" ]; then
cat "$SKILL_BASE/$1/$d.md"
return 0
fi
done
echo "genjutsu: sub-skill '$1' NOT LOADED - not found under $SKILL_BASE. Carry on, and list it under 'Modules not loaded' in the final report." >&2
return 1
}
load_skill() {
for d in SKILL GUIDE; do
if [ -f "$SKILL_BASE/$1/$d.md" ]; then
cat "$SKILL_BASE/$1/$d.md"
return 0
fi
done
echo "genjutsu: sub-skill '$1' NOT LOADED - not found under $SKILL_BASE. Carry on, and list it under 'Modules not loaded' in the final report." >&2
return 1
}
Print one reference file of a module: load_ref <module> <path inside it>.
Print one reference file of a module: load_ref <module> <path inside it>.
load_ref() {
if [ -f "$SKILL_BASE/$1/$2" ]; then
cat "$SKILL_BASE/$1/$2"
return 0
fi
echo "genjutsu: reference '$1/$2' NOT LOADED - not found under $SKILL_BASE. Carry on, and say so in the final report." >&2
return 1
}
<!-- genjutsu:shared:skill-base:end -->
bunshin needs the absolute `$SKILL_BASE` beyond the shell: the workflow templates are passed by
path, and every clone brief names the modules a clone must read. Note the path the block prints
(`genjutsu: modules from ...`) the first time, and write it in `.bunshin/run.json` with the tier,
the capabilities and the Impeccable directory; the owner map goes in `.bunshin/owners.json` at
FOUNDATION. Shell state still does not survive: re-emit the block in every call that loads
something or runs one of its scripts.
The orchestration module is loaded at SUMMON, before the first clone:
```bashload_ref() {
if [ -f "$SKILL_BASE/$1/$2" ]; then
cat "$SKILL_BASE/$1/$2"
return 0
fi
echo "genjutsu: reference '$1/$2' NOT LOADED - not found under $SKILL_BASE. Carry on, and say so in the final report." >&2
return 1
}
<!-- genjutsu:shared:skill-base:end -->
bunshin 在 shell 之外也需要 `$SKILL_BASE` 的绝对路径:workflow 模板会按路径传入,每个分身简报也必须指明该分身需要读取的模块。记录代码块第一次打印的路径(`genjutsu: modules from ...`),并在 `.bunshin/run.json` 中写入层级、能力和 Impeccable 目录;FOUNDATION 阶段将所有者映射写入 `.bunshin/owners.json`。Shell 状态仍不会保留:从第一次加载到最后一次加载,都必须由你自行维护这份列表。
编排模块在 SUMMON 阶段、生成第一个分身之前加载:
```bash(skill-base block re-emitted above this line)
(skill-base block re-emitted above this line)
load_skill orchestration
Its references load when their phase comes, one per shell call:
`load_ref orchestration references/material.md` (HARVEST, MATERIAL),
`references/impeccable.md` (READ when Impeccable is there, DIRECTION, SEAL),
`references/evidence.md` (FOUNDATION, PROVE).
Every path you hand a template is absolute: `<root>` below is the project's absolute path, and
the scratch directory is resolved before the call (the session's scratch directory when the host
gives one, else the value of `printf '%s\n' "${TMPDIR:-/tmp}/bunshin-<project>"`). The templates
quote what they receive, so a shell expression passed as a path is never expanded.
---load_skill orchestration
其参考文件会在对应阶段加载,每次 shell 调用只加载一个:
`load_ref orchestration references/material.md`(HARVEST、MATERIAL),
`references/impeccable.md`(检测到 Impeccable 时的 READ、DIRECTION、SEAL),
`references/evidence.md`(FOUNDATION、PROVE)。
交给模板的每个路径都必须是绝对路径:下文中的 `<root>` 表示项目的绝对路径,临时目录在调用前解析(宿主提供会话临时目录时使用该目录,否则使用 `printf '%s\n' "${TMPDIR:-/tmp}/bunshin-<project>"` 的值)。模板会引用收到的内容,因此作为路径传入的 shell 表达式不会被展开。
---Pipeline
流水线
Twelve phases. Everything a run writes that is not the site goes into , which
you add to at SUMMON: , , , ,
(the chosen card's board and hero, and without Impeccable),
(round 1: the evidence of the review; round N+1: the evidence after refine
round N), and the lens files beside it, ,
, , . Nothing under
is ever imported by the site: the isolated copies exclude it.
<root>/.bunshin/.gitignorerun.jsonowners.jsonharvest/research/direction/direction.mdcaptures/round-N/reviews/round-N.jsonreviews/round-N-refine.jsonreviews/round-N-verdict.jsondecisions/round-N.mdreport.md.bunshin/共十二个阶段。运行过程中生成但不属于网站本身的所有内容都写入 ,并在 SUMMON 阶段将其加入 :、、、、(所选卡片的展板和主视觉,以及未安装 Impeccable 时的 )、(第 1 轮为审查证据;第 N+1 轮为完成第 N 轮细化后的证据)、 及其旁边的视角文件、、、、。网站绝不会导入 下的任何内容:隔离副本会排除该目录。
<root>/.bunshin/.gitignorerun.jsonowners.jsonharvest/research/direction/direction.mdcaptures/round-N/reviews/round-N.jsonreviews/round-N-refine.jsonreviews/round-N-verdict.jsondecisions/round-N.mdreport.md.bunshin/0. READ - the project, the brief, the host
0. READ——读取项目、简报与宿主
<!-- genjutsu:shared:scan:start -->
bash
undefined<!-- genjutsu:shared:scan:start -->
bash
undefined1. Web (existing)
1. Web (existing)
cat package.json 2>/dev/null | grep -E '"(gsap|motion|framer-motion|three|@react-three/fiber|@react-three/drei|animejs|popmotion|lenis|locomotive-scroll)"'
cat package.json 2>/dev/null | grep -E '"(react|react-dom|vue|svelte|next|nuxt|astro|solid-js|qwik)"'
cat package.json 2>/dev/null | grep -E '"(tailwindcss|styled-components|@emotion|sass|less|vanilla-extract|panda)"'
cat package.json 2>/dev/null | grep -E '"(gsap|motion|framer-motion|three|@react-three/fiber|@react-three/drei|animejs|popmotion|lenis|locomotive-scroll)"'
cat package.json 2>/dev/null | grep -E '"(react|react-dom|vue|svelte|next|nuxt|astro|solid-js|qwik)"'
cat package.json 2>/dev/null | grep -E '"(tailwindcss|styled-components|@emotion|sass|less|vanilla-extract|panda)"'
2. Android / Compose
2. Android / Compose
ls build.gradle.kts build.gradle settings.gradle.kts settings.gradle 2>/dev/null
grep -rE 'androidx.compose|implementation("androidx.compose' build.gradle* settings.gradle* 2>/dev/null
ls build.gradle.kts build.gradle settings.gradle.kts settings.gradle 2>/dev/null
grep -rE 'androidx.compose|implementation("androidx.compose' build.gradle* settings.gradle* 2>/dev/null
3. Compose Multiplatform / KMP
3. Compose Multiplatform / KMP
grep -rE 'org.jetbrains.compose|kotlin("multiplatform")|id("org.jetbrains.kotlin.multiplatform")' build.gradle* settings.gradle* 2>/dev/null
grep -rE 'org.jetbrains.compose|kotlin("multiplatform")|id("org.jetbrains.kotlin.multiplatform")' build.gradle* settings.gradle* 2>/dev/null
4. Apple / SwiftUI
4. Apple / SwiftUI
ls *.xcodeproj *.xcworkspace Package.swift 2>/dev/null
grep -lE 'import SwiftUI|@main.App' --include=".swift" -r . 2>/dev/null | head -1
ls *.xcodeproj *.xcworkspace Package.swift 2>/dev/null
grep -lE 'import SwiftUI|@main.App' --include=".swift" -r . 2>/dev/null | head -1
5. Apple platform sub-detection (iOS vs macOS)
5. Apple platform sub-detection (iOS vs macOS)
grep -E '.iOS(|.macOS(' Package.swift 2>/dev/null
grep -E 'SDKROOT = (iphoneos|macosx)' *.xcodeproj/project.pbxproj 2>/dev/null
grep -E '.iOS(|.macOS(' Package.swift 2>/dev/null
grep -E 'SDKROOT = (iphoneos|macosx)' *.xcodeproj/project.pbxproj 2>/dev/null
6. Mobile web indicators
6. Mobile web indicators
grep -rE 'viewport.width=device-width|@media.pointer:\scoarse|@media.max-width' --include='.html' --include='.css' --include='*.scss' . 2>/dev/null | head -3
ls public/manifest.json public/sw.js 2>/dev/null
grep -rE 'viewport.width=device-width|@media.pointer:\scoarse|@media.max-width' --include='.html' --include='.css' --include='*.scss' . 2>/dev/null | head -3
ls public/manifest.json public/sw.js 2>/dev/null
7. Legacy bridge indicators (mention in DISCOVER, do not auto-load)
7. Legacy bridge indicators (mention in DISCOVER, do not auto-load)
ls -- .xib .storyboard 2>/dev/null
find . -path '/res/layout/.xml' 2>/dev/null | head -1
grep -rE 'setContentView(R.layout' --include='.kt' --include='.java' . 2>/dev/null | head -1
Map the results:
- **Animation lib**: gsap, `motion`, `framer-motion`, three/@react-three, anime.js, or none.
**`motion` and `framer-motion` are the same library at two names.** Framer Motion was renamed
to Motion; `motion` is the current package and `framer-motion` is the legacy one, still widely
installed and still published. Note which of the two is in `package.json` - the import path
differs and the sub-skill needs to know. If both are present, the project is mid-migration:
say so and follow whichever one the file you are editing already imports.
- **Framework**: React, Vue, Svelte, Next.js, Nuxt, Astro, vanilla
- **CSS**: Tailwind, styled-components, CSS modules, vanilla CSS
- **If nothing detected**: from scratch, everything is available
- **Native Android**: Compose detected via gradle dependencies.
- **Native Apple**: SwiftUI detected via Package.swift / xcodeproj + swift files. Distinguish iOS vs macOS via Package.swift platforms or pbxproj SDKROOT.
- **Compose Multiplatform**: kotlin-multiplatform plugin + jetbrains.compose plugin.
- **Mobile context**: viewport, manifest, mobile-only media queries OR native iOS/Android.
- **Desktop context**: macOS target OR no mobile indicators on web.
- **Legacy mixed**: presence of `.xib`, `.storyboard`, layout XML, `setContentView(R.layout.*)`. Mention only, no auto-load.
<!-- genjutsu:shared:scan:end -->
Then read the brief and skim every source it names (the profile, the current site, the
documents), without harvesting yet. Run the capability check above. Size the job: pages or
screens, languages, audiences, the main channel. Decide whether bunshin is the right pipeline
(see "Step down"). With Impeccable, `load_ref orchestration references/impeccable.md` now and
read Impeccable's own `reference/init.md` (its Step 3 holds the interview questions, its Step 4
the PRODUCT.md format) and section 2 of its `reference/new-work.md` (the questions asked before
the draw), so the summoning can carry them.
**Declare your read** in one line before the summoning, the way cast and paint do: "My read so
far: <what> for <whom>, heading toward <direction>, on <stack>." A slot you cannot fill is said as
unknown and becomes a question at the gate.ls -- .xib .storyboard 2>/dev/null
find . -path '/res/layout/.xml' 2>/dev/null | head -1
grep -rE 'setContentView(R.layout' --include=".kt" --include=".java" . 2>/dev/null | head -1
<!-- genjutsu:shared:scan:end -->
映射扫描结果:
- **动画库**:gsap、`motion`、framer-motion、three/@react-three、anime.js,或没有动画库。
**`motion` 和 `framer-motion` 是同一个库的两个名称。** Framer Motion 已更名为 Motion;`motion` 是当前包名,`framer-motion` 是旧名称,目前仍被广泛安装和使用。必须记录 `package.json` 中使用的是哪一个,因为导入路径不同,子 skill 需要知道这一信息。如果两者同时存在,说明项目正处于迁移期:如实说明,并遵循当前正在编辑的文件所采用的导入方式。
- **框架**:React、Vue、Svelte、Next.js、Nuxt、Astro 或原生技术栈
- **CSS**:Tailwind、styled-components、CSS modules 或原生 CSS
- **未检测到任何内容**:项目从零开始,所有技术栈选项均可用
- **原生 Android**:通过 Gradle 依赖检测 Compose。
- **原生 Apple**:通过 Package.swift、xcodeproj 和 Swift 文件检测 SwiftUI。通过 Package.swift 平台或 pbxproj 中的 SDKROOT 区分 iOS 与 macOS。
- **Compose Multiplatform**:检测到 kotlin-multiplatform 插件和 jetbrains.compose 插件。
- **移动端上下文**:存在 viewport、manifest、仅限移动端的媒体查询,或原生 iOS/Android。
- **桌面端上下文**:目标为 macOS,或 Web 项目没有任何移动端标识。
- **遗留混合项目**:存在 `.xib`、`.storyboard`、layout XML 或 `setContentView(R.layout.*)`。仅进行说明,不自动加载。
然后阅读简报,并快速查看其中提到的每个来源(个人资料、当前网站、文档),但暂不采集素材。执行上述能力检查。评估任务规模:页面或屏幕数量、语言、受众、主要渠道。决定 bunshin 是否为正确流水线(见“降级”)。如果安装了 Impeccable,此时执行 `load_ref orchestration references/impeccable.md`,并阅读 Impeccable 自己的 `reference/init.md`(其步骤 3 包含访谈问题,步骤 4 包含 PRODUCT.md 格式)以及 `reference/new-work.md` 的第 2 节(抽取前提出的问题),以便召唤仪式能够携带这些内容。
**在召唤前用一行声明你的理解:**“我目前的理解:这是为 <受众> 打造的 <内容>,计划采用 <方向>,技术栈为 <技术栈>。”无法确定的项应标为 unknown,并在门控时转化为问题。1. SUMMON - the first gate
1. SUMMON——第一道门控
One message, then one structured question call when the host has the tool:
bunshin for <what>: <N> pages in <languages>, from <sources>. The plan: harvest the material, research with four clones and a synthesis, you choose a direction, I build the foundation and the signature surface, <N> page clones build the rest, then refine rounds and verdicts until only minor issues remain or the tier's cap is reached. This host: <clones in parallel through workflows | clones one by one | cannot summon>. Impeccable: <version, it leads the direction | not installed: the direction round is weaker;fixes that>. Captures: <yes | no, and what that costs>. Stack: <framework and adapter, already in place | no project yet: each option of the stack question below names its exact scaffold command and packages, the type-check ones included>. Your answers to the tier and the stack cover that one install and nothing else. Cost: one run has been measured, a seven-page bilingual site, about 10.5M subagent tokens over six to eight hours. Estimated from it: lean ~6M, standard ~8-9M, full ~12-13M, plus this session's own tokens; yours scales with the page count. <Permissions: the allow rules the run needs, when this session asks before each command.>npx impeccable install --project -y
In the same call, up to four questions: the tier first (standard marked recommended), then the
product questions that change the work the most, recommended option first. With Impeccable,
those are the questions its Step 3 asks and the ones its asks before the draw,
at most three, the stack question first when there is no scaffold; its interview is then done,
and neither is asked again. Without it, paint's brainstorm domains. Anything the four questions
do not settle becomes an assumption, written in PRODUCT.md and in the report.
initnew-workWait for the answers. Then: add to , write , and load
the orchestration module. With Impeccable, run once from the
project root ( as the capability check printed it; a project install puts nothing on the
).
.bunshin/.gitignore.bunshin/run.json<dir>/scripts/impeccable context<dir>PATH先发送一条消息;若宿主提供相应工具,则在同一次调用中发起一次结构化提问:
bunshin 用于 <内容>:<N> 个页面,<语言>,基于 <来源>。 计划如下:采集素材,由四个分身进行调研并生成综合结果;你选择方向;我构建基础层和标志性界面;<N> 个页面分身构建其余页面;随后执行细化轮次和裁决,直到只剩轻微问题或达到层级的轮次上限。 当前宿主:<通过 workflow 并行生成分身 | 逐个生成分身 | 无法召唤>。 Impeccable:<版本,由它主导方向 | 未安装:方向轮次效果较弱;可通过修复>。截图:<支持 | 不支持,以及这会造成的损失>。 技术栈:<框架和适配器已经就位 | 尚无项目:技术栈问题中的每个选项都列出了准确的脚手架命令和软件包,包括类型检查选项>。 你对层级和技术栈的回答仅涵盖这一次安装,不涵盖其他任何安装。 成本:目前有一次经过测量的运行,即一个双语七页网站,在六到八小时内消耗约 10.5M subagent token。根据该次运行估算:lean 约 6M,standard 约 8 至 9M,full 约 12 至 13M,此外还应计入当前会话自身的 token;你的实际成本会随页面数量变化。 <权限:如果当前会话会在每条命令前询问,请列出运行所需的允许规则。>npx impeccable install --project -y
在同一次调用中最多提出四个问题:首先询问层级,standard 标记为推荐选项;随后提出最能影响工作内容的产品问题,同样将推荐选项放在首位。安装 Impeccable 时,使用其 步骤 3 中的问题以及 在抽取前提出的问题,最多三个;如果尚无脚手架,先问技术栈问题。其访谈至此完成,这些问题不再重复询问。未安装时,使用 paint 的头脑风暴领域。四个问题未能确定的所有内容都将成为假设,并写入 PRODUCT.md 和报告。
initnew-work等待答复。然后将 加入 ,写入 ,并加载编排模块。安装 Impeccable 时,从项目根目录运行一次 ( 为能力检查打印的路径;项目级安装不会向 添加任何内容)。
.bunshin/.gitignore.bunshin/run.json<dir>/scripts/impeccable context<dir>PATH2. HARVEST - the real material
2. HARVEST——采集真实素材
load_ref orchestration references/material.md.bunshin/harvest/执行 ,然后遵循其中说明:获取客户拥有且处于完整分辨率的图片、文本、真正阅读过的联系表、从关键图片中采样的色板、附带来源的事实,以及缺失内容列表。只采集客户拥有的素材。所有内容都放入 。
load_ref orchestration references/material.md.bunshin/harvest/3. RESEARCH - four clones, then a synthesis
3. RESEARCH——四个分身,然后综合
Run with the brief (facts and gate answers only) and set to
. Read the synthesis. Then write PRODUCT.md: with
Impeccable, in its Step 4 format; without it, the same headings. Confirmed facts only, a
section of what must never be invented (prices, reviews, clients, figures), the evidence on hand,
the principles.
research.jsout<root>/.bunshin/research/synthesis.mdinit使用简报(仅包含事实和门控答案)运行 ,并将 设置为 。阅读综合结果。然后编写 PRODUCT.md:安装 Impeccable 时使用其 步骤 4 的格式;未安装时使用相同标题。只写已确认的事实,设置“绝不可虚构”的章节,列出已有证据和设计原则。
research.jsout<root>/.bunshin/research/synthesis.mdinit4. DIRECTION - the second gate
4. DIRECTION——第二道门控
Run the direction round of : seven worlds ordered before the draw, the
draw, the challengers and their raises, the decision page, and the structured-question fallback
only when the page cannot run or was closed unanswered. Every card carries the interaction
thesis (timing range, hover, scroll, forbidden patterns) and its line,
inside a field the page actually shows, so one choice validates both theses. bunshin builds
code-led, always. Without Impeccable, run the round that reference describes, on a rendered page.
references/impeccable.mdAllowed patterns:The guessability test holds for every card: a direction that could be written from the product
category alone is the category's default, not a direction.
Once the user has chosen, write the contract (, or ):
THESIS, OWN-WORLD, STORY, FIRST VIEWPORT, FORM, FINISH, the interaction thesis, the allowed
patterns. This file is what every clone and every reviewer holds the work against. With
Impeccable, save the chosen card's board and hero images into (the finish
reviewer reads them as the QUALITY BAR card). Then, in a shell call of its own, re-emit the
skill-base block and load with its web reference ( then
): MATERIAL fixes the type next, and names the reflexes
it has to rule out. Read the chosen card's line against the catalogue, and
name the catalogued reflexes it allows in one line of your next message (not a question) and in
the report's assumptions.
surface-brief write.bunshin/direction.md.bunshin/direction/tellsload_skill tellsload_ref tells references/web.mdtellsAllowed patterns:运行 中的方向轮次:先排列七个世界,再进行抽取、挑战者质疑与加码、决策页面展示;仅当页面无法运行或已关闭但未得到答复时,才使用结构化提问作为后备方案。每张卡片都必须包含交互命题(时间范围、悬停、滚动、禁用模式)及其 行,并放在页面实际展示的字段中,使一次选择能够同时验证两份命题。bunshin 始终采用代码主导的方式。未安装 Impeccable 时,在渲染页面上运行该参考文件描述的轮次。
references/impeccable.mdAllowed patterns:每张卡片都必须通过可猜测性测试:如果一个方向仅根据产品类别就能写出来,那么它就是该类别的默认方向,而不是真正的方向。
用户选择后,编写契约(,或 ):THESIS、OWN-WORLD、STORY、FIRST VIEWPORT、FORM、FINISH、交互命题和允许的模式。该文件是所有分身和所有审查者据以工作的依据。安装 Impeccable 时,将所选卡片的展板图和主视觉图保存到 (结束审查者将其作为 QUALITY BAR 卡片读取)。然后在独立的 shell 调用中重新输出 skill-base 代码块,并加载 及其 Web 参考(,然后 ):MATERIAL 决定下一步的字体选择,而 列出必须排除的条件反射。将所选卡片的 行与目录进行比对,并在下一条消息中用一行列出允许的目录化条件反射(不是问题),同时将其写入报告的假设部分。
surface-brief write.bunshin/direction.md.bunshin/direction/tellsload_skill tellsload_ref tells references/web.mdtellsAllowed patterns:5. MATERIAL - by evidence, not by reflex
5. MATERIAL——以证据而非直觉为依据
From : type specimens rendered in a real miniature of the layout and
compared as captures; photographs trimmed and cropped; cutouts fitted to the object's own edge
and checked on a light and a dark ground; grain as a tile; provenance on every raster. Record the
type choice with its reason in the contract. Every raster the site ships is written into the
project's own asset folder (for example ), owned by , with an index (file,
subject, which page may use it) that the build packet names.
references/material.mdsrc/assets/shared遵循 :在真实布局缩略模型中渲染字体样张,并将截图进行对比;裁剪照片;沿物体自身边缘制作抠图,并分别在浅色和深色背景上检查;将颗粒效果平铺为纹理;为每张位图记录来源。将字体选择及其原因记录在契约中。网站发布的每张位图都应写入项目自己的资源目录(例如 ),归 所有,并附带索引(文件、主题、允许使用的页面);构建资料包会引用该索引。
references/material.mdsrc/assets/shared6. FOUNDATION - yours, not a clone's
6. FOUNDATION——由你亲自构建,而非分身
Always load (via , defined above: a missing module prints and the pipeline carries on, so keep the list for the final report):
load_skill <name>NOT LOADED- - the foundation
load_skill motion-principles
One module per shell call. The output of a shell call over about 30,000 characters does not
arrive inline: you get a 2,000-character preview and a file path, and a module you could not
read is a module you did not load. So each loading call re-emits the skill-base block and loads
one module, which keeps its output under 25,000 characters: no module entry file is over that
cap, and keeps it that way. Keep the tally as you go: prints
for a missing module and carries on, and the final report lists both. Load each
module whole: never pipe or into , , , or , since
the batching rule above already keeps each call under the limit, and a truncated module is a
module not loaded.
validate-skills.pyload_skillNOT LOADEDload_skillload_refheadtailsedgrepContext layers (load when applicable):
| Detected | Load |
|---|---|
| Web stack and scope is medium or full | |
| Mobile context (web mobile OR native iOS / Android) | |
| Desktop context (macOS OR web desktop with no mobile indicators) | |
| Audit explicitly requested OR scope=full | |
| Advanced UI/UX questions | |
tellsbash
undefined始终加载(通过上述 :模块缺失时会打印 ,流水线仍会继续,因此必须保留列表供最终报告使用):
load_skill <name>NOT LOADED- ——基础层
load_skill motion-principles
每次 shell 调用只加载一个模块。 单次 shell 调用的输出超过约 30,000 个字符时,不会完整内联返回:只会得到 2,000 字符的预览和一个文件路径;无法读取的模块就等同于没有加载。因此,每次加载调用都重新输出 skill-base 代码块,并且只加载一个模块,使输出保持在 25,000 个字符以内:没有任何模块入口文件超过该上限, 也会维持这一限制。请在过程中持续维护加载清单: 会为缺失模块打印 并继续执行,最终报告会同时列出已加载和未加载的模块。必须完整加载每个模块:绝不能将 或 的输出传入 、、 或 ,因为上述批量加载规则已经将每次调用控制在限制以内,而被截断的模块就等同于没有加载。
validate-skills.pyload_skillNOT LOADEDload_skillload_refheadtailsedgrep上下文层(按需加载):
| 检测结果 | 加载内容 |
|---|---|
| Web 技术栈,范围为中等或完整 | |
| 移动端上下文(Web 移动端或原生 iOS / Android) | |
| 桌面端上下文(macOS,或没有移动端标识的 Web 桌面端) | |
| 明确要求审查或 scope=full | |
| 高级 UI/UX 问题 | |
tellsbash
undefined(skill-base block re-emitted above this line)
(skill-base block re-emitted above this line)
load_skill tells
load_ref tells references/web.md
It loads after the thesis gate and before any visual choice is frozen: the validated thesis says
which patterns are wanted, and `tells` names the reflexes nobody asked for. Never on a Compose or
SwiftUI stack, never on light scope. In paint this row is already met: Phase 3 loads `tells`
before the design-system query.
**Stack-specific** (load by SCAN):
| Detected stack | Sub-skill to load |
|---|---|
| gsap | `load_skill gsap` |
| `motion` or `framer-motion` (same library, two package names) | `load_skill framer-motion` |
| Pure CSS / Tailwind / no lib | `load_skill css-native` |
| three / @react-three | `load_skill threejs-r3f` |
| Canvas / generative | `load_skill canvas-generative` |
| Android Compose | `load_skill compose-motion` (always) + `load_skill compose-graphics` (if scope=full or thesis is advanced - see below) |
| Compose Multiplatform | `load_skill compose-motion` + `load_skill compose-multiplatform` (always); `load_skill swiftui-motion` if iOS target detected and SwiftUI interop demanded; `load_skill compose-graphics` if advanced |
| SwiftUI iOS or macOS | `load_skill swiftui-motion` (always) + `load_skill swiftui-graphics` (if scope=full or thesis is advanced) |
**"Advanced thesis" trigger** for `compose-graphics` / `swiftui-graphics`:
The thesis is "advanced" (and triggers loading the graphics sub-skill) if it contains any of these terms:
- `shader`, `Metal`, `AGSL`, `RuntimeShader`, `MSL`
- `liquid-glass`, `glassEffect`, `morphing transition`
- `M3 Expressive`, `MotionScheme`, `expressive motion`
- `colorEffect`, `distortionEffect`, `layerEffect`
- `Canvas` (with generative / particle / flow field context)
- `holographic`, `CRT`, `displacement`, `ripple`
Otherwise stick to the base motion sub-skill.
<!-- genjutsu:shared:load:end -->
bunshin builds a whole site, so its scope is always full: `tells` (already loaded after the
direction), `mobile-principles`, `desktop-principles` and `design-audit` all apply, each in a call
of its own, before the first line of the foundation. With Impeccable, read its
`reference/craft-floor.md` right before the first UI edit.
Then build, yourself:
- **The scaffold**, when there is no project. The root already holds `.claude/`, `.bunshin/`,
PRODUCT.md and `.gitignore`, and scaffolders refuse, redirect or offer to empty a folder that is
not empty: run the command the summoning named, without its install step, in
`<scratch>/scaffold`, then `rsync -a --ignore-existing '<scratch>/scaffold/' '<root>/'`, append
the scaffold's `.gitignore` lines to the root's, install the named packages in the root with the
package manager (the only place it ever runs), and run one build that prints exit code 0
before anything else.
- **Tokens**: the inks, tone roles (a class that sets background, text, button and focus for a
whole field), a fluid type scale, spacing, four or five durations and named easings.
- **The content model**: every visible text, in every language, in typed content files, with one
source for the practical facts (contacts, legal, areas). No copy in the views: that is what
lets the client edit the site with an AI later.
- **The shared components**: layout (metadata, alternates, structured data, fonts), header,
footer, the mobile call-to-action bar, the responsive image with its reveal, the page header
every inner page reuses.
- **Every route, before the fan-out**: the route file of every page in every language, each
rendering its page's view with an empty content file, and every page linked from the header,
so each clone's routes build and capture from its first run.
- **The signature surface**: the home page and the one signature interaction, the surface that
decides everything. Capture it (`references/evidence.md`), fix what the capture shows, capture
again. Two passes, then move on.
**On plain HTML and CSS** (no build step): pass `build.cmd: 'true'`, `build.static: '.'` and
`build.link: []`. Each page's HTML file is its view and holds its copy, so the content-model rule
cannot apply, and the report says so. Write the header and footer once in the home page and copy
them verbatim into every route file before the fan-out; a change to them is a shared change
request that you apply to every page.
Write `.bunshin/owners.json`, every owner included: one owner per page (its view, its content
file, its components folder), `shared` for everything used by more than one page, the route files
included, and the home page's owner, which is you until the fan-out is over. Pass all of it to
`review.js` and `verdict.js`; pass `build.js` only the page owners you did not build yourself,
each with its mission; pass `refine.js` only the owners that have fixes, or rules of the
decisions file that touch their files.load_skill tells
load_ref tells references/web.md
它会在命题门控之后、冻结任何视觉选择之前加载:经过验证的命题说明需要哪些模式,而 `tells` 则列出没有人主动要求、但必须排除的条件反射。绝不在 Compose 或 SwiftUI 技术栈上加载,也绝不在轻量范围中加载。paint 已满足这一要求:步骤 3 会在设计系统查询前加载 `tells`。
**技术栈专属模块**(根据 SCAN 加载):
| 检测到的技术栈 | 要加载的子 skill |
|---|---|
| gsap | `load_skill gsap` |
| `motion` 或 `framer-motion`(同一个库,两个软件包名称) | `load_skill framer-motion` |
| 纯 CSS / Tailwind / 无动画库 | `load_skill css-native` |
| three / @react-three | `load_skill threejs-r3f` |
| Canvas / 生成式效果 | `load_skill canvas-generative` |
| Android Compose | `load_skill compose-motion`(始终加载);scope=full 或命题高级时还需 `load_skill compose-graphics`(见下文) |
| Compose Multiplatform | `load_skill compose-motion` + `load_skill compose-multiplatform`(始终加载);检测到 iOS 目标且要求 SwiftUI 互操作时加载 `load_skill swiftui-motion`;命题高级时加载 `load_skill compose-graphics` |
| SwiftUI iOS 或 macOS | `load_skill swiftui-motion`(始终加载);scope=full 或命题高级时还需 `load_skill swiftui-graphics` |
**触发 `compose-graphics` / `swiftui-graphics` 的“高级命题”条件:**
命题包含以下任一术语时,即属于“高级”命题,并触发加载图形子 skill:
- `shader`、`Metal`、`AGSL`、`RuntimeShader`、`MSL`
- `liquid-glass`、`glassEffect`、`morphing transition`
- `M3 Expressive`、`MotionScheme`、`expressive motion`
- `colorEffect`、`distortionEffect`、`layerEffect`
- `Canvas`(且涉及生成式效果、粒子或流场)
- `holographic`、`CRT`、`displacement`、`ripple`
否则只使用基础动效子 skill。
<!-- genjutsu:shared:load:end -->
bunshin 构建的是完整网站,因此范围始终为 full:`tells`(方向选择后已加载)、`mobile-principles`、`desktop-principles` 和 `design-audit` 均适用,并且必须在编写基础层第一行代码前分别通过独立调用加载。安装 Impeccable 时,在第一次编辑 UI 前阅读其 `reference/craft-floor.md`。
然后由你亲自构建:
- **脚手架**(项目中尚不存在脚手架时)。根目录已经包含 `.claude/`、`.bunshin/`、PRODUCT.md 和 `.gitignore`,而脚手架工具会拒绝、重定向或提示清空非空目录:在 `<scratch>/scaffold` 中运行召唤时指定的命令,但跳过其安装步骤;然后执行 `rsync -a --ignore-existing '<scratch>/scaffold/' '<root>/'`;将脚手架的 `.gitignore` 内容追加到根目录的 `.gitignore`;在根目录中使用包管理器安装指定软件包(这是全流程唯一一次执行安装的位置);并在其他操作前完成一次打印退出码 0 的构建。
- **Token**:墨色、语气角色(用于为整个字段设置背景、文本、按钮和焦点的 class)、流体字体比例、间距、四或五种持续时间,以及命名缓动。
- **内容模型**:每种语言中的所有可见文本都放在有类型约束的内容文件中,实际事实(联系方式、法律信息、业务范围)只有一个来源。视图中不得包含文案:这样客户以后才能借助 AI 编辑网站。
- **共享组件**:布局(元数据、替代文本、结构化数据、字体)、页眉、页脚、移动端 CTA 栏、带揭示效果的响应式图片,以及每个内页复用的页面标题组件。
- **分发前的每个路由**:为每种语言下的每个页面创建路由文件,每个路由都使用空内容文件渲染对应页面视图;页眉中的所有链接目标都必须存在,以保证每个分身的路由从首次运行起就可以构建和截图。
- **标志性界面**:主页以及一个标志性交互,也就是决定整体效果的界面。使用 `references/evidence.md` 对其截图,根据截图修复,再次截图。执行两轮后继续。
**关于纯 HTML 和 CSS**(没有构建步骤):传入 `build.cmd: 'true'`、`build.static: '.'` 和 `build.link: []`。每个页面的 HTML 文件就是其视图并保存文案,因此内容模型规则不适用,报告中必须说明这一点。在分发前,将页眉和页脚写在主页中,并逐字复制到每个路由文件;之后若要修改它们,应作为共享变更请求应用到所有页面。
编写 `.bunshin/owners.json`,其中必须包含每位所有者:每个页面各一位所有者(负责其视图、内容文件和组件目录),被多个页面使用的所有内容归 `shared`,其中也包括路由文件;主页的所有者是你本人,直到分发结束。将完整信息传给 `review.js` 和 `verdict.js`;只将你没有亲自构建的页面所有者及其任务说明传给 `build.js`;只将存在待修复项的所有者,或需要执行决策文件规则的所有者传给 `refine.js`。7. CLONES - the pages, in parallel
7. CLONES——并行构建页面
Run with , the packet (what to read first by absolute path: PRODUCT.md, the
contract, the quality floor, the design system, the home page you built; the conventions; the
rules of the theses; the voice; the asset folder and its index), the page owners with their
missions, and : the
framework's binary as (and when it has a type check), the resolved absolute
, the static output folder as , the absolute path of as ,
and each owner's routes, so every clone captures its own page from its own copy and looks at it
before it returns. The anatomy of a good brief is in the orchestration module; a clone knows only
what its brief says.
build.jsrootbuildcmdcheckscratchstaticshoot.mjsshootWhen the clones return: read every entry, apply the ones that hold (you
own the shared files at this point), and note the open questions for the client.
shared_change_requests运行 ,传入 、资料包(按绝对路径说明首先应读取的内容:PRODUCT.md、契约、质量底线、设计系统、你构建的主页;约定;命题规则;语气;资源目录及其索引)、带有任务说明的页面所有者,以及 :框架二进制文件作为 (存在类型检查时还要传入 )、解析后的绝对路径 、静态输出目录作为 、 的绝对路径作为 ,以及每位所有者的路由。这样每个分身都会从自己的副本中截取自己的页面,并在返回前亲自查看。优秀简报的结构见编排模块;分身只知道自己简报中包含的内容。
build.jsrootbuildcmdcheckscratchstaticshoot.mjsshoot分身返回后:阅读每一条 ,应用其中成立的内容(此时共享文件归你所有),并记录需要客户解答的开放问题。
shared_change_requests8. PROVE - before anyone reviews
8. PROVE——在任何人审查之前
load_ref orchestration references/evidence.md- The build and the type check, each printing exit code 0; when Impeccable is installed; the tells audit (in one shell call, re-emit the skill-base block, then
<dir>/scripts/impeccable detect --json <source folders>); and a grep for U+2014 unless the thesis allows it.python3 "$SKILL_BASE/design-audit/scripts/audit.py" . --group tells - Captures of every page and language with : the standard shot list, one shots file and one call per page and language, into
shoot.mjs. With Impeccable, add the two shots its finish reviewer requires, unsegmented, straight to their files:.bunshin/captures/round-1/and the same at 390x664 to{ "path": "/", "w": 1440, "h": 900, "full": true, "out": "<root>/.impeccable/review/desktop.png" }, with the samemobile.png, at every PROVE: its verdict pass reads those exact paths again. Read the first screens yourself.reveal - The functional tests of the paths that sell (menu, sticky bar, selection into the form, form steps, endpoint failure and success), each reported with its measured value.
Fix what is broken before the review: five lenses spent on a broken build are five lenses wasted.
What passed goes into the packet as already verified.
执行 。然后依次完成:
load_ref orchestration references/evidence.md- 构建和类型检查,二者都必须打印退出码 0;安装 Impeccable 时,执行 ;执行 tells 审查(在一次 shell 调用中重新输出 skill-base 代码块,然后运行
<dir>/scripts/impeccable detect --json <source folders>);并在命题允许的情况下,对 U+2014 执行 grep。python3 "$SKILL_BASE/design-audit/scripts/audit.py" . --group tells - 使用 截取每个页面和每种语言:采用标准截图列表,每个页面和语言分别使用一个 shots 文件和一次调用,输出到
shoot.mjs。安装 Impeccable 时,额外添加其结束审查器要求的两张截图,保持未分段并直接写入指定文件:.bunshin/captures/round-1/,以及在 390x664 下使用相同{ "path": "/", "w": 1440, "h": 900, "full": true, "out": "<root>/.impeccable/review/desktop.png" }生成reveal;每次 PROVE 都要重新拍摄这两张图,因为裁决流程会再次读取这些准确路径。亲自阅读每个页面的首屏。mobile.png - 对影响转化的路径执行功能测试,包括菜单、吸底栏、选择项进入表单、表单步骤、接口失败和成功;每项都报告测得的数值。
审查前先修复损坏内容:把五个审查视角浪费在损坏的构建上毫无意义。已经通过的内容应作为已验证项写入资料包。
9. REVIEW - independent lenses
9. REVIEW——独立审查视角
Run with the evidence packet, the round, the tier's lenses, the module directories
(, , , as absolute paths),
every owner from , and set to , N
the round this review opens (1 the first time; after a rebuild, the next round). With Impeccable,
and when the host lists its agent type, pass set to the name the host gives
Impeccable's finish reviewer (Claude Code: ), so it is spawned fresh,
the way Impeccable asks; never paste its definition into a prompt. When Impeccable is installed
but the host does not list that agent type, pass set to the absolute path of its
instead, and say so in the report.
review.js$SKILL_BASE/mobile-principlesdesktop-principlesmotion-principlesowners.jsonplanOut<root>/.bunshin/reviews/round-<N>.jsonfinishAgentimpeccable-finish-reviewerfinishRolereference/degraded/finish-reviewer.mdRead the finish disposition first. : the evidence failed, not the build; recapture what
the list names, then run the review again, and the round does not count. No
disposition (the finish reviewer returned nothing twice) is treated the same way. :
rebuild the named regions yourself, then run the review again, a full one; the round counts, as
one of the tier's refine rounds. or : read the
plan and its rejected list (a rejection that contradicts the validated direction is the plan's
call to make; a rejection of a real defect is yours to overturn), and apply the
fixes yourself, before refine.
recapturerecapturerebuildfixshiporchestrator运行 ,传入证据资料包、轮次、层级对应的审查视角、模块目录(、、 的绝对路径)、 中的所有所有者,并将 设置为 ;N 为本次审查开启的轮次(首次为 1;重新构建后进入下一轮)。安装 Impeccable 且宿主列出其 Agent 类型时,将 设置为宿主提供的 Impeccable 结束审查器名称(Claude Code:),以全新方式生成该审查器,正如 Impeccable 所要求;绝不能将其定义粘贴到提示中。已安装 Impeccable 但宿主未列出该 Agent 类型时,将 设置为 的绝对路径,并在报告中说明。
review.js$SKILL_BASE/mobile-principlesdesktop-principlesmotion-principlesowners.jsonplanOut<root>/.bunshin/reviews/round-<N>.jsonfinishAgentimpeccable-finish-reviewerfinishRolereference/degraded/finish-reviewer.md首先阅读结束处置结论。:失败的是证据,而不是构建;重新截取 列表指定的区域,然后再次运行审查,本轮不计入。结束审查器连续两次没有返回任何内容,也按同样方式处理。:由你亲自重建指定区域,然后再次运行一次完整审查;本轮计入层级的细化轮次。 或 :阅读审查计划及其拒绝列表(若拒绝项与已验证方向冲突,则由计划决定;若拒绝的是实际缺陷,则由你推翻),并在细化前由你亲自执行 修复项。
recapturerecapturerebuildfixshiporchestrator10. REFINE - the loop
10. REFINE——循环
Each round, from round 1:
- Run with
refine.js, the packet (PRODUCT.md, the contract, the quality floor, by absolute path),root(round 1: the review's plan file; later rounds: the plan the last verdict wrote),planPath(from round 2: the last decisions file), the owners that have fixes or decisions to apply,decisionswhen it has some (it runs first and alone), and the samesharedas phase 7. Write its result tobuild..bunshin/reviews/round-N-refine.json - PROVE again: the checks, then new captures into , and the two
.bunshin/captures/round-<N+1>/captures shot again over the same files..impeccable/review/ - Run with the new packet,
verdict.js(the round's plan file, its refine results, its decisions file),history, every owner,roundset toplanOut, the same<root>/.bunshin/reviews/round-<N+1>.jsonas the review, andfinishAgentwhen the tier says so, with the one-sentence scenario of how the audience meets the site. It writes the next round's plan from the finish reviewer's remaining points, with an empty fixes list when nothing is left. Write its result tofreshEyes: true..bunshin/reviews/round-N-verdict.json - When the verdict ran cold eyes and the loop goes on, turn their notes into decisions,
yourself (when the stop rule ends the loop, the notes go into the report): , rules the next round applies everywhere (the one role of each hero image, where saturated colour is allowed, the type roles, the shape of controls, the shared contracts that change). Never hand the notes to clones as a task list. Apply the plan's
.bunshin/decisions/round-N.mdfixes yourself.orchestrator - Apply the stop rule (orchestration module), the disposition first: means recapture and run the verdict again;
recapturesends you back to the review. Then: ship when nothing above minor is left, stop at the tier's round cap, stop when a round fixed nothing. Otherwise the next round starts at step 1.rebuild
Passing the tier's cap needs the user's yes, with the table of what is left in front of them.
从第 1 轮开始,每轮执行:
- 运行 ,传入
refine.js、资料包(PRODUCT.md、契约和质量底线的绝对路径)、root(第 1 轮为审查计划文件;后续轮次为上一次裁决写出的计划)、planPath(从第 2 轮开始为上一次决策文件)、存在待修复项或待应用决策的所有者、存在待修复项时的decisions(它最先且独自运行),以及与阶段 7 相同的shared。将结果写入build。.bunshin/reviews/round-N-refine.json - 再次执行 PROVE:先运行各项检查,再将新截图写入 ,并重新将两张
.bunshin/captures/round-<N+1>/截图覆盖到相同文件。.impeccable/review/ - 运行 ,传入新资料包、
verdict.js(本轮计划文件、细化结果和决策文件)、history、所有所有者、将round设置为planOut、与审查阶段相同的<root>/.bunshin/reviews/round-<N+1>.json,并在层级要求时传入finishAgent,同时提供一句说明受众如何接触该网站的场景描述。它会根据结束审查器剩余的问题写出下一轮计划;如果没有剩余问题,修复列表为空。将结果写入freshEyes: true。.bunshin/reviews/round-N-verdict.json - 当裁决包含冷眼审查且循环仍需继续时,由你亲自将其意见转化为决策:写入 ,这些规则将在下一轮全局应用,包括每张主视觉图的唯一角色、高饱和色彩允许出现的位置、字体角色、控件形态,以及需要变更的共享契约。绝不能把冷眼意见作为任务列表交给分身。亲自执行计划中的
.bunshin/decisions/round-N.md修复项。orchestrator - 应用停止规则(编排模块),并首先考虑处置结论:表示重新截图并再次运行裁决;
recapture表示返回审查阶段。然后:当不存在高于轻微级别的问题时交付;达到层级轮次上限时停止;当某轮没有修复任何内容时停止。否则开始下一轮。rebuild
超过层级上限需要用户明确同意,并同时向用户展示尚未解决的问题表。
11. SEAL - document, audit, report
11. SEAL——文档、审查与报告
- DESIGN.md: spawn Impeccable's documenter by the agent type the host lists (Claude Code:
) with the project root, the artifact paths (the source folders and the built output), the direction contract, PRODUCT.md, the absolute path of Impeccable's
impeccable-documenter, and the write boundary (the project root); it writes DESIGN.md andreference/document.mdfrom the shipped code. Without Impeccable, write DESIGN.md yourself from the shipped code, never from intentions..impeccable/design.json - AGENTS.md (with a pointing to it): for the AI that will maintain the site, in the client's language. Where each kind of change is made, the design rules, the writing rules, the commands, what to check before pushing.
CLAUDE.md - A launch guard: a build-time warning listing every fact still missing (contacts, legal details, the domain), with a strict mode that fails the production build.
- The audit, below, run over the whole project.
- The report, below, also written to .
.bunshin/report.md
The closing step of this pipeline used to be twenty-five checkboxes, several of which name a
tool the agent cannot run. Ticking "60fps verified via Chrome DevTools" without opening Chrome
turns "I did not look" into "I looked and it is fine", which is worse than saying nothing.
So the checks are split. Report the first group with the evidence you used. Never tick the
second group at all - hand it over.
- DESIGN.md:按照宿主列出的 Agent 类型生成 Impeccable 的文档整理者(Claude Code:),传入项目根目录、artifact 路径(源文件夹和构建输出)、方向契约、PRODUCT.md、Impeccable 的
impeccable-documenter绝对路径,以及写入边界(项目根目录);由它根据已交付代码编写 DESIGN.md 和reference/document.md。未安装 Impeccable 时,根据已交付代码亲自编写 DESIGN.md,绝不能依据最初的设想编写。.impeccable/design.json - AGENTS.md(并让 指向它):面向以后维护该网站的 AI,使用客户的语言编写。说明各类更改在哪里进行、设计规则、写作规则、命令,以及 push 前需要检查的内容。
CLAUDE.md - 发布防护:构建时发出警告,列出仍然缺失的所有事实(联系方式、法律信息、域名),并提供严格模式,在生产构建时使构建失败。
- 审查,见下文,对整个项目执行。
- 报告,见下文,同时写入 。
.bunshin/report.md
此流水线的收尾步骤过去包含二十五个复选框,其中几项还指定了 Agent 无法运行的工具。在没有打开 Chrome 的情况下勾选“已通过 Chrome DevTools 验证 60fps”,会把我没有查看变成我查看过且没有问题,这比什么都不说更糟糕。
因此,这些检查被分成两组。第一组必须附带所使用的证据进行报告。第二组绝不能勾选——应移交给用户。
Checked here, with evidence
此处已检查,并附有证据
Each line is reported as . The evidence is the grep you ran, the
value you computed, or the you read. A verdict with no evidence beside it is not a
finding, and an item you could not check is reported as not checked rather than passed.
check - verdict - the evidencefile:line- Thesis against code. First, because every check below assumes the code is the thesis
that was validated. For each promise the validated thesis actually makes (durations,
easing, springs, palette, type, layout family) give the that holds it, or "not found". A thesis that makes no palette or type promise, an interaction thesis alone, gets no palette or type line. A promise with no
file:lineis a problem found, not a pass. Honest downgrade: when promised motion cannot be shipped working, ship the static version, say so here, and name the promise that was dropped; it counts as a problem found. Never ship motion that is half broken to keep a promise on paper. Evidence: one line per promise, e.g.file:line.hover 180ms ease-out - src/Card.tsx:42 - Reduced motion honoured. Web: a block that actually degrades the animation, not an empty one. SwiftUI:
prefers-reduced-motion. Compose: a helper onaccessibilityReduceMotion/ValueAnimator.areAnimatorsEnabled(). Evidence: the file and line of the guard, and what it degrades to.Settings.Global.ANIMATOR_DURATION_SCALE - Exit animations present wherever something unmounts. Evidence: the conditional render and its exit path, or the list of unmounts that have none.
- No layout-property animation. Nothing animating ,
width,height,top,leftormargin; use transform, opacity orpadding. Evidence: the grep and its hits, or that it returned nothing.graphicsLayer - Focus visible on every interactive element, and no without a replacement. Evidence: the grep.
outline: none - All five states on interactive elements: default, hover or press, focus, active, disabled. Evidence: the states you found per component, and the ones missing.
- Tokens, not magic numbers. Colours and spacing come from the project's design tokens
(MASTER.md when one exists). Evidence: the rogue values, with .
file:line - Contrast at least 4.5:1 for body text, 3:1 for large text and UI boundaries.
Compute it from the token values you emitted; do not eyeball a swatch. Evidence: the
pair and the computed ratio, e.g. .
#831843 on #FDF2F8 = 9.4:1 - Semantics. Web: no clickable without a role,
divon decorative motion. Compose:aria-hiddenon custom interactive components. SwiftUI:Modifier.semanticson controls that have no text. Evidence: the grep..accessibilityLabel - Web only. Conditional renders wrapped in or the framework's equivalent;
AnimatePresenceused sparingly and removed after the animation. Evidence: the grep.will-change - Tells confronted with the thesis. Only when was loaded. In one shell call, re-emit the skill-base block and run
tells, whether or notpython3 "$SKILL_BASE/design-audit/scripts/audit.py" . --group tellswas loaded. Evidence, for each finding: either the problem you kept, with itsdesign-audit, or the entry of the thesis'sfile:lineline that names it. A kept tell counts among the problems found. An allowed one is listed as "allowed by the thesis", with that entry quoted, and is not a problem. The manual readsAllowed patterns:lists (fake product in divs, repeated layout family, floating corner paragraph, copy register, copy held in JavaScript data) are reported the same way. Each finding has one of three outcomes, never a fourth: allowed by the thesis, itstellsentry quoted; not this tell, only when the detection contradicts the entry's own marker (the loop reports a real loading state, the blur is a modal backdrop, the matched line is not displayed text), with theAllowed patterns:that proves it and never on a matter of taste; or a problem. Fix before you report, and only what this run introduced: a problem on a line this run wrote (readfile:linewhen the project has one) is removed or rewritten, then this check runs again, two passes at most, and what still fails is reported with itsgit diff. A tell that was already in the project, on a line this run did not write, is never changed here: it is listed for the user. Nothing on the protected list of an existing project (public token names, URLs, navigation labels, form field names, logo, legal mentions) is changed by this step.file:line
每行都按 报告。证据应是执行过的 grep、计算得到的数值,或阅读过的 。没有证据的结论不是发现;无法检查的项目应报告为未检查,而不是通过。
检查项 - 结论 - 证据file:line- 命题与代码一致。 首先检查这一点,因为后续每项检查都假设代码实现了已验证的命题。对于已验证命题实际作出的每一项承诺(持续时间、缓动、spring、色板、字体、布局家族),给出对应的 ,或注明“未找到”。如果命题没有作出色板或字体承诺,仅包含交互命题,则不设置色板或字体项。找不到
file:line的承诺属于发现的问题,而不是通过。如实降级:承诺的动效无法正常交付时,交付静态版本,在此如实说明,并指出被放弃的承诺;这同样计为发现的问题。绝不能为了维持纸面承诺而交付半损坏的动效。 证据:每项承诺一行,例如file:line。悬停 180ms ease-out - src/Card.tsx:42 - 遵守 reduced motion。 Web:存在真正降级动画的 代码块,而不是空代码块。SwiftUI:
prefers-reduced-motion。Compose:基于accessibilityReduceMotion/ValueAnimator.areAnimatorsEnabled()的辅助方法。 证据:防护代码所在的文件和行号,以及降级后的行为。Settings.Global.ANIMATOR_DURATION_SCALE - 所有卸载位置都存在退出动画。 证据:条件渲染和退出路径,或列出没有退出动画的卸载位置。
- 不对布局属性执行动画。 不对 、
width、height、top、left或margin执行动画;应使用 transform、opacity 或padding。证据:grep 命令及其命中项,或说明没有返回结果。graphicsLayer - 每个交互元素都有可见焦点。 不存在没有替代方案的 。证据:grep 结果。
outline: none - 交互元素具备全部五种状态。 默认、悬停或按下、焦点、激活、禁用。证据:每个组件发现的状态,以及缺失的状态。
- 使用 token,而非魔法数字。 颜色和间距来自项目设计 token(存在 MASTER.md 时使用其中定义)。证据:异常值及其 。
file:line - 对比度。 正文至少 4.5:1,大号文本和 UI 边界至少 3:1。
必须计算已输出 token 的对比度,不能靠肉眼判断色板。证据:颜色组合和计算出的比例,例如 。
#831843 on #FDF2F8 = 9.4:1 - 语义。 Web:可点击的 必须具有 role,装饰性动效必须标记
div。Compose:自定义交互组件使用aria-hidden。SwiftUI:没有文本的控件使用Modifier.semantics。证据:grep 结果。.accessibilityLabel - 仅限 Web。 条件渲染应包裹在 或框架的等价机制中;
AnimatePresence应谨慎使用,并在动画结束后移除。证据:grep 结果。will-change - 以命题审视 tells。 仅在已加载 时执行。在一次 shell 调用中重新输出 skill-base 代码块,并运行
tells,无论是否加载了python3 "$SKILL_BASE/design-audit/scripts/audit.py" . --group tells。每项发现的证据只能是以下三种结果之一:命题允许该问题,并引用对应的design-audit条目;该检测与条目自身的标记相矛盾,因此判定为“不是这种 tell”,并给出证明它的Allowed patterns:,且不能仅凭主观喜好判断;或者判定为“问题”。报告前先修复问题,并且只修复本次运行引入的问题:本次运行编写的代码行所存在的问题(项目有 Git 时阅读file:line)应删除或重写,然后再次运行此检查,最多执行两轮,仍未通过的项必须附带git diff报告。原本就存在于项目、且不是本次运行编写的代码行中的 tell 绝不能在此修改,而应列给用户。此步骤不会更改现有项目保护列表中的任何内容,包括公共 token 名称、URL、导航标签、表单字段名称、logo 和法律声明。file:line
You must run these - not verified here
必须由你执行——此处未验证
The agent cannot open a profiler, attach to a device, or move a pointer. These are reported as a
handoff block with the exact invocation, and marked UNVERIFIED. Do not tick them, do not
soften them, and do not omit the section because the rest looked clean.
| Target | What to run | Pass condition |
|---|---|---|
| Web | Chrome DevTools > Performance, record across the interaction | no frame over 16.7ms |
| Web | The page at 375 / 768 / 1024 / 1440 | no horizontal scroll, no clipped content |
| Web | The page with the OS "reduce motion" setting on | the degraded path actually runs |
| Compose | Layout Inspector > Component Tree > View Options > Show Recomposition Counts | counts stable while scrolling |
| Compose | | frame time under 16.67ms at 60fps, 8.33ms at 120fps |
| SwiftUI | Instruments > Animation Hitches | no hitch during the transition |
| SwiftUI | Reduce Motion on, Dynamic Type at 200% | nothing clipped, nothing that only moves |
| macOS | Pointer over every interactive element; keyboard through the whole view | hover states fire, focus ring visible, shortcuts bound |
If a preview or a dev server is already running and the user agrees, driving the browser to
collect the web rows is better than handing them over. Never start one just for the audit, and
never install anything for it.
Report the two groups separately, with the counts. "11 checked, 2 problems found, 8 handed
over" is an honest audit. A single list of ticks is not.
Close the report with the modules, always, as two lines of their own:
Modules loaded: motion-principles, framer-motion, design-audit
Modules not loaded: noneModules not loadedload_skillNOT LOADEDnoneAgent 无法打开性能分析器、连接设备或移动指针。这些项目应作为移交区块报告,给出准确的调用方式,并标为 UNVERIFIED。不要勾选,不要弱化表述,也不要因为其他检查结果良好就省略本节。
| 目标 | 执行内容 | 通过条件 |
|---|---|---|
| Web | Chrome DevTools > Performance,录制整个交互过程 | 没有帧超过 16.7ms |
| Web | 375 / 768 / 1024 / 1440 宽度下的页面 | 没有水平滚动,没有内容被裁切 |
| Web | 开启操作系统“减少动态效果”后的页面 | 降级路径确实能够运行 |
| Compose | Layout Inspector > Component Tree > View Options > Show Recomposition Counts | 滚动时重组合次数保持稳定 |
| Compose | 在中端设备上运行 | 60fps 时帧时间低于 16.67ms,120fps 时低于 8.33ms |
| SwiftUI | Instruments > Animation Hitches | 过渡期间没有卡顿 |
| SwiftUI | 开启 Reduce Motion,Dynamic Type 设为 200% | 没有内容被裁切,没有内容只能通过移动呈现 |
| macOS | 将指针移过每个交互元素;使用键盘遍历整个视图 | 悬停状态会触发,焦点环可见,快捷键已绑定 |
如果预览或开发服务器已经在运行且用户同意,驱动浏览器收集 Web 相关结果优于直接移交。但绝不能仅为了审查而启动服务器,也绝不能为此安装任何内容。
分别报告两组结果,并附上数量。“已检查 11 项,发现 2 个问题,移交 8 项”才是诚实的审查结果,不能只给出一串勾选框。
最后始终用两行独立列出模块:
Modules loaded: motion-principles, framer-motion, design-audit
Modules not loaded: noneModules not loadedload_skillNOT LOADEDnoneThe final report
最终报告
Plain, in this order:
- Built: the routes, per language, and where the design system and the contract live.
- Verified, with the evidence: build, type check, detector, tells, captures (where), each functional test with its measured value, the last verdicts and their dispositions.
- Not verified: the handed-over rows of the audit, marked UNVERIFIED, and anything a lens could not check.
- Left: the minor points after the last round, by page.
- For the client: every fact still missing, from and the content files, and the open questions the clones raised.
missing.md - Cost: the tier, the rounds run, the agent count per workflow, and the tokens when the host reported them.
- Assumptions, and in a headless run every gate answer marked UNVALIDATED.
- The two module lines, from the audit.
Nothing is committed, pushed or deployed until the user asks.
采用平实语言,并按以下顺序排列:
- 已构建:按语言列出的路由,以及设计系统和契约所在位置。
- 已验证,并附证据:构建、类型检查、检测器、tells、截图位置、每项功能测试的测量值、最后一次裁决及其处置结论。
- 未验证:审查中移交的各项结果,标为 UNVERIFIED,以及审查视角无法检查的内容。
- 遗留项:最后一轮之后仍然存在的轻微问题,按页面列出。
- 客户待办:来自 和内容文件的所有缺失事实,以及分身提出的开放问题。
missing.md - 成本:层级、已执行轮次、每个 workflow 的 Agent 数量,以及宿主报告的 token 消耗。
- 假设;在无头运行中,还要列出所有标为 UNVALIDATED 的门控答案。
- 审查部分要求的两行模块信息。
除非用户提出要求,否则不会 commit、push 或 deploy 任何内容。
Red Flags - You're About to Violate This Skill
危险信号——你即将违反此 skill
| Thought | Reality |
|---|---|
| "The user said go all out, I'll skip the summoning" | The tier is asked, every time. Going all out is a tier, and it has a price. |
| "Research first, the questions will be better" | Nothing heavier than reading before the tier. Skim the sources at READ; that is enough to ask well. |
| "I'll ask how they want to see the direction" | Two questions, no third. The decision page, or a rendered page announced in one line. |
| "I'll let a clone do the home page too" | The signature surface is yours. It is the reference every clone copies. |
| "Two clones can share the stylesheet, it is one line each" | One owner per file. Shared needs are requests. |
| "The build is green in the project folder, good enough" | Clones build in copies. A green build in a shared tree proves nothing. |
| "The lenses can judge from the code, captures take time" | They judge what renders. Capture, read the first screens, then review. |
| "The finish reviewer said recapture, I'll apply the plan anyway" | Invalid evidence binds nothing. Recapture first. |
| "The cold eyes gave eight tasks, I'll assign them" | Turn them into rules in the decisions file. That step is art direction, and it is yours. |
| "One more round will get the last minor points" | The stop rule decides. Minor points go in the report. |
| "No subagent tool here, I'll play the clones myself" | Then nothing is reviewed independently. Step down to paint. |
| "Impeccable is not installed, I'll install it, it is free" | Ask. A no stands. |
| "It is ready, I'll push it so they can see it" | Nothing leaves the machine unasked. |
| 想法 | 实际情况 |
|---|---|
| “用户说全力以赴,我可以跳过召唤。” | 每次都必须询问层级。全力以赴也是一种层级,而且有明确价格。 |
| “先做调研,问的问题会更好。” | 在确定层级前,只允许阅读。快速浏览来源即可支持高质量提问。 |
| “我会先询问用户希望如何查看方向。” | 只有两个问题,没有第三个。使用决策页面或渲染页面,并用一行说明。 |
| “我也会让分身构建主页。” | 标志性界面必须由你亲自完成,它是所有分身模仿的基准。 |
| “两个分身可以共用样式表,每边只改一行。” | 每个文件只有一位所有者。共享需求必须走请求流程。 |
| “项目目录中的构建已经通过,这就足够了。” | 分身在自己的副本中构建。共享目录中的绿色构建什么也证明不了。 |
| “审查视角可以只看代码,截图太耗时。” | 它们要评判实际呈现的内容。先截图、阅读首屏,再开始审查。 |
| “结束审查器要求 recapture,我直接执行计划。” | 无效证据无法约束任何内容。必须先重新截图。 |
| “冷眼审查给出了八项任务,我直接分配。” | 应将其转化为决策文件中的规则。该步骤属于艺术指导,由你负责。 |
| “再执行一轮就能解决最后的轻微问题。” | 由停止规则决定。轻微问题写入报告即可。 |
| “这里没有 subagent 工具,我自己扮演分身。” | 这样就无法进行独立审查,应降级使用 paint。 |
| “Impeccable 没安装,我直接安装,反正免费。” | 必须询问。明确的拒绝必须遵守。 |
| “已经准备好了,我先 push 出去让客户看看。” | 未经允许,任何内容都不得离开本机。 |
Quick decision tree
快速决策树
Whole-site request received
|
+- READ: stack, brief, sources, host capabilities, size
| |
| +- smaller than a site, native stack, or no subagents? -> step down (cast / paint)
|
+- SUMMON (gate 1): read, plan, host, Impeccable, stack, cost; tier + product questions
|
+- HARVEST -> RESEARCH (four clones, a synthesis) -> PRODUCT.md
|
+- DIRECTION (gate 2): seven worlds, the draw, cards with both theses; contract; tells
|
+- MATERIAL -> FOUNDATION (yours: scaffold, tokens, content model, shared, routes, signature)
|
+- CLONES: one per page, disjoint files, isolated builds, each capturing its own page
|
+- PROVE -> REVIEW (lenses + plan; recapture? rebuild? read the disposition first)
|
+- REFINE -> PROVE -> VERDICT (+ cold eyes) -> decisions, next plan
| |
| +- stop rule: minor only, round cap, or nothing fixed? -> SEAL
| +- else -> next round
|
+- SEAL: DESIGN.md, AGENTS.md, launch guard, audit, reportWhole-site request received
|
+- READ: stack, brief, sources, host capabilities, size
| |
| +- smaller than a site, native stack, or no subagents? -> step down (cast / paint)
|
+- SUMMON (gate 1): read, plan, host, Impeccable, stack, cost; tier + product questions
|
+- HARVEST -> RESEARCH (four clones, a synthesis) -> PRODUCT.md
|
+- DIRECTION (gate 2): seven worlds, the draw, cards with both theses; contract; tells
|
+- MATERIAL -> FOUNDATION (yours: scaffold, tokens, content model, shared, routes, signature)
|
+- CLONES: one per page, disjoint files, isolated builds, each capturing its own page
|
+- PROVE -> REVIEW (lenses + plan; recapture? rebuild? read the disposition first)
|
+- REFINE -> PROVE -> VERDICT (+ cold eyes) -> decisions, next plan
| |
| +- stop rule: minor only, round cap, or nothing fixed? -> SEAL
| +- else -> next round
|
+- SEAL: DESIGN.md, AGENTS.md, launch guard, audit, report