review

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tailr — the review loop

Tailr — 评审循环

Tailr lets the person you are working with mark up their running dev server in the browser — click an element, say what is wrong — and hand you every mark at once as a batch. You apply the batch and report each mark as it lands.
The rules below are the whole protocol. They are the same rules
tailr init
writes into a project's
AGENTS.md
/
CLAUDE.md
; this plugin carries them instead, so nothing in the user's repository has to be edited.
<!-- tailr:start -->
Tailr 允许你的协作对象在浏览器中对运行中的开发服务器进行标记——点击元素、说明问题——并将所有标记一次性批量提交给你。你需要批量应用这些标记,并在每个标记落地时同步反馈。
以下规则是完整的协议。这些规则与
tailr init
写入项目
AGENTS.md
/
CLAUDE.md
中的规则完全一致;本插件直接内置了这些规则,因此无需修改用户代码仓库中的任何内容。
<!-- tailr:start -->

Tailr — visual markup from the reviewer

Tailr — 来自评审者的视觉标记

The reviewer marks up the running app in the browser and hands you the changes as one batch. A session is up when
.tailr/session.json
exists; if it doesn't, start one as a long-running background process — it must stay up, so don't block your turn waiting on it:
npx tailr --target http://localhost:<dev server port>
It prints a review URL (usually http://localhost:4100). Tell the reviewer to use that URL, not the original port. Tailr proxies the app and injects its overlay; the source is not modified.
The loop is
wait
→
pull
→
progress
per mark →
done
or
fail
.
CommandMCP tool
npx tailr status
tailr_status
is a batch waiting? exit 0 yes · 3 session up, nothing waiting · 2 no session
npx tailr wait
tailr_wait
block until Send is pressed; exit 0 a batch is waiting · 3 timed out, start it again · 2 session ended
npx tailr pull
tailr_pull
lease the batch, printed as JSON
npx tailr variants <ref> <names…>
tailr_variants
name the versions you built for one mark
npx tailr slider <ref> --min --max
tailr_slider
report the continuous parameter you wired for a slider mark
npx tailr progress <ref>
tailr_progress
report one mark as applied
npx tailr done
tailr_done
the run finished
npx tailr fail "reason"
tailr_fail
it returned incomplete
npx tailr config [name:value…]
tailr_config
their settings —
sfx
,
modifier
. Only when they ask
Each mark carries a
ref
("01"), a
type
, the
route
it was made on, a best-effort source
address
, a CSS
selector
, the element's text, and the reviewer's
comment
.
  • comment
    — change that element as described
  • remove
    — delete that element
  • text
    — carries
    before
    /
    after
    ; change the text to
    after
  • point
    — carries page
    x
    /
    y
    instead of an element. The reviewer marked a place, not a thing: they may want something new there, or may just be noting the spot. Their comment says which.
  • choice
    — the reviewer picked between versions you built, or kept a value on a slider you built. See below.
评审者在浏览器中对运行中的应用进行标记,并将所有变更作为一个批量提交给你。当
.tailr/session.json
存在时,表示会话已启动;如果不存在,需要将其作为长期运行的后台进程启动——会话必须保持运行,因此不要阻塞你的处理流程来等待它:
npx tailr --target http://localhost:<dev server port>
它会输出一个评审URL(通常是 http://localhost:4100)。告知评审者使用该URL,而非原始端口。Tailr 会代理应用并注入其覆盖层;不会修改源代码。
循环流程为
wait
→
pull
→ 每个标记执行
progress
→
done
或
fail
。
CommandMCP tool
npx tailr status
tailr_status
是否有批量任务等待处理?退出码 0 表示有 · 3 表示会话运行中,无等待任务 · 2 表示无会话
npx tailr wait
tailr_wait
阻塞直到按下发送按钮;退出码 0 表示有批量任务等待 · 3 表示超时,需重新启动 · 2 表示会话已结束
npx tailr pull
tailr_pull
获取批量任务的租约,以JSON格式输出
npx tailr variants <ref> <names…>
tailr_variants
为单个标记构建的版本命名
npx tailr slider <ref> --min --max
tailr_slider
上报你为滑块标记配置的连续参数
npx tailr progress <ref>
tailr_progress
上报单个标记已应用
npx tailr done
tailr_done
运行完成
npx tailr fail "reason"
tailr_fail
运行未完成(失败)
npx tailr config [name:value…]
tailr_config
用户设置——
sfx
、
modifier
。仅在用户询问时使用
每个标记包含
ref
(如"01")、
type
、标记所在的
route
、尽力匹配的源
address
、CSS
selector
、元素文本以及评审者的
comment
。
  • comment
    — 按照描述修改对应元素
  • remove
    — 删除对应元素
  • text
    — 包含
    before
    /
    after
    字段;将文本修改为
    after
    的内容
  • point
    — 包含页面
    x
    /
    y
    坐标而非元素。评审者标记的是一个位置而非某个元素:他们可能想在那里添加新内容,或者只是标注该位置。具体意图见其评论。
  • choice
    — 评审者在你构建的版本中做出了选择,或确定了你构建的滑块的数值。详见下文。

Versions

版本

A
comment
or
point
mark can carry
"variations": 3
. That asks for three different answers to the same comment, all built at once, so the reviewer can compare them on the running page and keep one.
Build every version into the source together, each guarded on the switch Tailr sets for that mark: the attribute
data-tailr-var-<ref>
on
<html>
, whose value is the version number.
/* mark 03, version 2 */
[data-tailr-var-03="2"] .cart-total { font-size: 24px; border-radius: 14px }
Version 1 must also be what renders when the attribute is absent, so the page is never broken for anyone who isn't looking through Tailr. Anything that has to re-render rather than restyle reads
document.documentElement.dataset.tailrVar03
and listens for the
tailr:variant
event on
document
; its
detail
carries
{ ref, variant, label }
.
Then name them, in order, before you report that mark applied:
npx tailr variants 03 "Softer edges" "Full width" "Two columns"
One to three concrete words each. They are the whole basis on which someone who cannot read the diff decides, so
"Two columns"
earns its place and
"Option B"
does not.
comment
或
point
类型的标记可能包含
"variations": 3
字段。这要求针对同一条评论构建三个不同的版本,且需一次性全部构建完成,以便评审者在运行的页面上对比并保留其中一个。
将所有版本同时构建到源代码中,每个版本都由Tailr为该标记设置的开关控制:即
<html>
标签上的
data-tailr-var-<ref>
属性,其值为版本号。
/* mark 03, version 2 */
[data-tailr-var-03="2"] .cart-total { font-size: 24px; border-radius: 14px }
版本1必须也是属性不存在时的渲染内容,这样对于不通过Tailr访问页面的用户来说,页面永远不会出错。任何需要重新渲染(而非仅修改样式)的内容,需要读取
document.documentElement.dataset.tailrVar03
并监听
document
上的
tailr:variant
事件;事件的
detail
包含
{ ref, variant, label }
。
在上报该标记已应用之前,按顺序为这些版本命名:
npx tailr variants 03 "Softer edges" "Full width" "Two columns"
每个名称使用1-3个具体的词汇。对于无法阅读代码差异的评审者来说,这些名称是他们做决策的全部依据,因此
"Two columns"
是合格的命名,而
"Option B"
则不合格。

Sliders

滑块

A
comment
or
point
mark can carry
"slider": true
. That asks you to make the element numerically variable — glow intensity, a bevel depth, a 3d parameter, anything the reviewer can scrub. Build one continuous parameter into the source, guarded on the switch Tailr sets for that mark: the attribute
data-tailr-slide-<ref>
on
<html>
, whose value is the number.
/* mark 03, intensity driven by the slider */
[data-tailr-slide-03] .hero { --glow: attr(data-tailr-slide-03 number) }
The default value must also be what renders when the attribute is absent. Anything that has to re-render rather than restyle reads
document.documentElement.dataset.tailrSlide03
and listens for the
tailr:slide
event on
document
; its
detail
carries
{ ref, value, label, min, max, unit }
.
Then report the range, before you report that mark applied:
npx tailr slider 03 --min 0 --max 100 --value 40 --label "Glow" --unit "%"
A mark may ask for versions and a slider together; do both.
A
choice
mark closes either kind. For versions it carries
variantOf
and
variant
:
  • variant: 2
    — keep version 2 as the plain, unguarded code. Delete the other versions and every
    data-tailr-var-<ref>
    guard for that ref.
  • variant: 0
    — keep none of them. Remove all the versions and the guards, and put the element back the way it was before you built them.
For a slider it carries
sliderOf
and
value
:
  • value: 42
    — bake that number into the source as the plain value. Remove the
    data-tailr-slide-<ref>
    switch.
  • value: null
    (or
    variant: 0
    ) — discard the slider. Remove the switch and put the element back as it was.
comment
或
point
类型的标记可能包含
"slider": true
字段。这要求你将元素设置为可通过数值调节的——比如光晕强度、斜角深度、3D参数等任何评审者可以拖动调整的内容。在源代码中构建一个连续参数,由Tailr为该标记设置的开关控制:即
<html>
标签上的
data-tailr-slide-<ref>
属性,其值为调节的数值。
/* mark 03, intensity driven by the slider */
[data-tailr-slide-03] .hero { --glow: attr(data-tailr-slide-03 number) }
当该属性不存在时,必须渲染默认值。任何需要重新渲染(而非仅修改样式)的内容,需要读取
document.documentElement.dataset.tailrSlide03
并监听
document
上的
tailr:slide
事件;事件的
detail
包含
{ ref, value, label, min, max, unit }
。
在上报该标记已应用之前,上报参数的取值范围:
npx tailr slider 03 --min 0 --max 100 --value 40 --label "Glow" --unit "%"
一个标记可能同时要求版本和滑块功能,需同时实现两者。
choice
类型的标记用于结束上述两种场景。对于版本场景,它包含
variantOf
和
variant
字段:
  • variant: 2
    — 保留版本2作为无开关的常规代码。删除其他版本以及该ref对应的所有
    data-tailr-var-<ref>
    开关。
  • variant: 0
    — 不保留任何版本。删除所有版本和开关,将元素恢复到构建版本之前的状态。
对于滑块场景,它包含
sliderOf
和
value
字段:
  • value: 42
    — 将该数值作为常规值固化到源代码中。移除
    data-tailr-slide-<ref>
    开关。
  • value: null
    (或
    variant: 0
    )—— 弃用滑块。移除开关并将元素恢复到原有状态。

Rules that matter

重要规则

  • Run
    wait
    as a long-running background process and treat its exit as the notification. Never ask the reviewer to tell you a batch has arrived, and never poll for one. Start it again after each run you close.
  • The reviewer can end the session from the page, which stops the server.
    wait
    then exits 2 and
    .tailr/session.json
    is gone. That is them finishing, not a crash: don't restart the session, and don't ask them to reopen the review URL. A last batch of
    choice
    marks usually arrives just before it — that is the cleanup, and it is the one batch worth closing quickly, because they are waiting on it to leave.
  • Report each mark with
    progress
    as you land it, not all at once at the end. The reviewer watches them clear on screen; batching makes it look like nothing is happening.
  • Always close the run with
    done
    or
    fail
    . Until you do, the reviewer cannot send another batch. If you hit something you can't do,
    fail
    with what actually went wrong — Tailr won't invent an explanation, it points them back to you.
  • The guards are scaffolding, not code. They live for exactly one round trip: you write them when a mark asks for versions or a slider, and the
    choice
    mark that comes back is what takes them out. Never leave a guard standing after its choice has landed, and never write one for anything the reviewer didn't ask to see versions or a slider of.
  • When the source address and the selector disagree, trust the source address.
  • A mark with
    "orphaned": true
    lost its element before it was sent. Don't guess at what was meant — raise it with the reviewer.
  • If a mark is ambiguous, ask rather than picking an interpretation.
  • Run these commands from the project directory; that's how Tailr finds the session.
<!-- tailr:end -->
  • 将
    wait
    作为长期运行的后台进程执行,并将其退出视为通知。永远不要让评审者告知你批量任务已到达,也不要轮询查询。每次关闭运行后重新启动该进程。
  • 评审者可以从页面端结束会话,这会停止服务器。此时
    wait
    退出码为2,且
    .tailr/session.json
    会被删除。这是正常结束而非崩溃:不要重启会话,也不要要求他们重新打开评审URL。通常在会话结束前会收到最后一批
    choice
    标记——这是清理步骤,也是值得快速处理完成的一批任务,因为评审者正等着结束离开。
  • 每应用一个标记就用
    progress
    上报一次,不要等到最后一次性上报。评审者会在屏幕上看到标记逐个被处理;批量上报会让他们看起来像什么都没发生一样。
  • 始终使用
    done
    或
    fail
    结束运行。在你结束之前,评审者无法发送下一批任务。如果遇到无法处理的问题,用
    fail
    说明实际出错原因——Tailr 不会编造解释,它会将用户引导回你这里。
  • 这些开关是临时脚手架,而非正式代码。它们的生命周期恰好是一次往返:当标记要求版本或滑块功能时你添加这些开关,而返回的
    choice
    标记会将它们移除。在对应选择落地后,永远不要保留开关,也永远不要为评审者没有要求版本或滑块的内容添加开关。
  • 当源地址和选择器不一致时,以源地址为准。
  • 带有
    "orphaned": true
    的标记在发送前已失去对应的元素。不要猜测其含义——向评审者确认。
  • 如果标记含义模糊,要询问而非自行选择一种解释。
  • 在项目目录下运行这些命令;Tailr 以此来找到对应的会话。
<!-- tailr:end -->

Running the commands from this plugin

从本插件运行命令

This plugin registers Tailr's MCP server, so
tailr_status
,
tailr_wait
,
tailr_pull
,
tailr_progress
,
tailr_done
and
tailr_fail
are available to you directly. Prefer them to the CLI: they are always present, whereas the
npx tailr
shorthand only resolves in a project that has installed Tailr.
Where you do reach for the CLI, use the full package name so it works in a project that has not installed anything:
npx -y @gcrft123/tailr <command>
Starting a session is the one step with no MCP tool, because the session is the server those tools talk to. Start it as a long-running background process — it has to stay up, so don't block your turn waiting on it:
npx -y @gcrft123/tailr --target http://localhost:<dev server port>
If the project has Tailr as a dependency, plain
npx tailr
is equivalent and shorter.
本插件注册了Tailr的 MCP 服务器,因此你可以直接使用
tailr_status
、
tailr_wait
、
tailr_pull
、
tailr_progress
、
tailr_done
和
tailr_fail
。优先使用这些工具而非CLI:它们始终可用,而
npx tailr
简写仅在已安装Tailr的项目中才能使用。
当你确实需要使用CLI时,请使用完整的包名,这样在未安装任何依赖的项目中也能运行:
npx -y @gcrft123/tailr <command>
启动会话是唯一没有对应MCP工具的步骤,因为会话本身就是这些工具通信的服务器。将其作为长期运行的后台进程启动——会话必须保持运行,因此不要阻塞你的处理流程来等待它:
npx -y @gcrft123/tailr --target http://localhost:<dev server port>
如果项目已将Tailr作为依赖项,直接使用
npx tailr
是等效且更简短的方式。