reticle

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Reticle

Reticle

Reticle embeds a dev-only SDK in the running app and exposes it to you as
reticle_*
MCP tools. You look, act, observe, and assert against the real app. No screenshots.
Reticle 会将一个仅限开发环境使用的 SDK 嵌入运行中的应用,并以
reticle_*
MCP 工具的形式提供给你。你可以对真实应用执行查看、操作、观察和断言。无需截图。

Finish the setup steps

完成设置步骤

The plugin already registered the MCP server, so this file runs with no client restart. Finish the setup steps; ask the user only when a step needs their decision. Running
init
, fixing wiring it could not, starting the dev server and opening the browser are setup steps, not decisions.
The repo already answers which framework, package manager and port, so work those out rather than asking. Say what you did in one line.
Two places always need the user:
  1. No recognisable dev script in
    package.json
    .
    Say so; do not invent one.
  2. Your host asks the human to approve a command. That prompt belongs to the host. Never bypass or suppress it, and take a refusal as the answer.
    init
    writing a pre-approval rule for the
    reticle
    server is not that: it is a scoped, announced config change the human asked for by running the command, and it covers only Reticle's own tools.
插件已经注册 MCP 服务器,因此执行此文件时无需重启客户端。 完成设置步骤;只有当某一步需要用户决策时才询问用户。运行
init
、修复其未能完成的接线、启动开发服务器并打开浏览器都属于设置步骤,而不是需要用户决策的事项。
仓库中已经能确定使用什么框架、包管理器和端口,因此应自行查明,而不要询问。用一行说明你所做的工作。
以下两处始终需要用户介入:
  1. package.json
    中没有可识别的开发脚本。
    说明这一点;不要自行编造。
  2. 你的 host 要求人工批准命令。 该提示由 host 发出。绝不绕过或抑制;如果用户拒绝,就将其视为最终答案。为
    reticle
    server 写入预批准规则并不属于上述情况:这是用户通过运行命令主动要求的、范围受限且已明确说明的配置变更,并且仅涵盖 Reticle 自身的工具。

Run this branch first

先运行此分支

bash
cat .reticle.json 2>/dev/null || echo NOT_FOUND
  • NOT_FOUND
    → ONBOARD, then VERIFY.
  • File exists → VERIFY.
Either way you are finished only when a verdict exists: from
reticle_act_and_wait
,
reticle_assert
, or
reticle_act { steps }
where a step declares
expect
. Config files are not an install, and a listed session is not a result.

bash
cat .reticle.json 2>/dev/null || echo NOT_FOUND
  • NOT_FOUND
    → ONBOARD,然后 VERIFY。
  • 文件存在 → VERIFY。
无论哪种情况,只有产生结论后才算完成:结论必须来自
reticle_act_and_wait
、
reticle_assert
,或某个 step 声明了
expect
的
reticle_act { steps }
。仅生成配置文件不代表安装成功,列出会话也不代表得到了结果。

ONBOARD

ONBOARD(接入)

One command wires the project. A second one proves a flow.
bash
npx @reticlehq/server@latest init
It detects the framework and package manager, wires the build config, installs the SDK, registers the MCP server, starts the dev server, opens the app, and waits for a session to connect from inside it. That connection IS the proof onboarding worked: the SDK is in the page and the tools have something to talk to. It exits non-zero if nothing connected, and prints exactly what is left to do.
Then prove a flow. That is the FIRST RUN, and it is a separate call:
reticle_verify { action: "explore", persona: "<who does what>" }
It drives the app with a model inside the daemon and RECORDS what it drove, so every later check replays that flow with no model in the loop.
一条命令完成项目接线,第二条命令证明一条流程可正常工作。
bash
npx @reticlehq/server@latest init
它会检测框架和包管理器、接好构建配置、安装 SDK、注册 MCP server、启动开发服务器、打开应用,并等待会话从应用内部连接。该连接就是 ONBOARD 成功的证明:SDK 已进入页面,工具也有可交互的对象。如果没有任何对象连接,命令会以非零状态退出,并准确列出仍需完成的事项。
然后验证一条流程。这是首次运行,并且是单独的一次调用:
reticle_verify { action: "explore", persona: "<who does what>" }
它通过 daemon 内的模型驱动应用,并记录所驱动的流程,因此之后的每次检查都可以在没有模型参与的情况下重放该流程。

What YOU decide, and pass in

由你决定并传入的内容

The command reads the repository. It cannot read the request, and these live only there.
flagwhat only you know
persona: "<what>"
(on the FIRST RUN, not on
init
)
which journey proves the thing the user asked for. Code can list the buttons; it cannot know checkout matters and the theme toggle does not.
--env KEY=VALUE
what the app needs to reach a usable state: the key from
.env.example
, the mock backend, the variable that skips an auth wall. Repeatable.
--app <dir>
which app in a monorepo. It can list the servable ones; only the request says which is being worked on.
Add
--license <key>
if the user gave you one: it writes
RETICLE_LICENSE_KEY
to
.env
and keeps
.env
out of git.
Framework, package manager, port, editor and MCP client are answerable from the repo you are sitting in, so work them out rather than asking.
命令会读取仓库,但无法读取用户请求;以下信息只存在于请求中。
标志只有你知道的信息
persona: "<what>"
(仅在首次运行时使用,不用于
init
)
哪条用户旅程能够证明用户所要求的事项。代码可以列出按钮,却无法知道结账流程很重要,而主题切换并不重要。
--env KEY=VALUE
应用达到可用状态所需的内容:来自
.env.example
的 key、mock backend,或用于跳过 auth wall 的变量。可重复传入。
--app <dir>
monorepo 中的哪个应用。命令可以列出可提供服务的应用;只有用户请求能说明当前处理的是哪一个。
如果用户提供了 key,则添加
--license <key>
:它会将
RETICLE_LICENSE_KEY
写入
.env
,并确保
.env
不会进入 git。
框架、包管理器、端口、编辑器和 MCP client 都可以从当前仓库中确定,因此应自行查明,而不要询问。

Then read what it gives you back

然后读取返回的结果

A non-zero exit is a to-do list, not a failed install. The command names the cause and prints the REMAINING steps from wherever it stopped; it will not tell you to redo a phase that already worked. Do those and re-run, which is safe.
It is not finished until a verdict exists. Writing files is not an install, and neither is a connected session.
非零退出码是一份待办清单,而不是安装失败。命令会指出原因,并打印从中断位置开始仍需完成的步骤;它不会要求你重做已经成功的阶段。完成这些步骤后重新运行即可,此操作是安全的。
只有产生结论后才算完成。 写入文件不代表安装成功,连接会话也不代表得到了结果。

If that command could not run it

如果该命令无法运行

Do not choose this path. It is not the thorough version of the one above; it is what you fall back to when the command physically could not do the work. Use it only when
init
exited without ever printing
starting:
or
▸ WATCH
(an older CLI that stops after writing files), or when it stopped in the same place twice after you did what it asked. A
⚠
in the report is not a reason: re-run the command, which is idempotent and names what is still outstanding.
bash
curl https://docs.reticle.sh/install-manual.md      # register the MCP, wire the SDK, prove it
curl https://docs.reticle.sh/troubleshooting.md     # nothing connected, click did nothing, verdict unknown

不要选择此路径。 它并不是上述完整方案的替代版本;只有当
init
从未打印
starting:
或
▸ WATCH
就退出(旧版 CLI 写完文件后便停止),或者你按照提示操作后它仍两次停在同一位置时,才应使用此路径。报告中的
⚠
不是切换路径的理由:请重新运行命令,该命令具有幂等性,并会列明仍未完成的事项。
bash
curl https://docs.reticle.sh/install-manual.md      # register the MCP, wire the SDK, prove it
curl https://docs.reticle.sh/troubleshooting.md     # nothing connected, click did nothing, verdict unknown

VERIFY

VERIFY(验证)

Verdicts come from
reticle_act_and_wait
,
reticle_assert
, and
reticle_act { steps }
when a step declares
expect
.
Everything else (a bare
act
,
look
,
navigate
,
observe
) moves or reads the app and proves nothing, however many tools it used.
verified: "unknown"
is not a pass. It means Reticle drove the app and could not tell what happened, so report it as unknown.
verified: "no-fault"
is not a pass either: the page settled and no channel complained, but nothing was declared to prove. Never weaken a check to make it pass. That converts a real signal into a false one, which is the failure this product exists to prevent.
结论来自
reticle_act_and_wait
、
reticle_assert
,以及某个 step 声明了
expect
的
reticle_act { steps }
。
其他所有操作(单独调用
act
、
look
、
navigate
或
observe
)只能移动或读取应用,无论使用了多少工具,都不能证明任何结果。
verified: "unknown"
不是通过。它表示 Reticle 驱动了应用,但无法判断实际发生了什么,因此应将其报告为未知。
verified: "no-fault"
也不是通过:页面已经稳定且没有任何通道报告异常,但并未声明任何可用于证明的条件。绝不能为了让检查通过而削弱检查条件。 这会把真实信号变成错误信号,而防止这种情况正是本产品存在的意义。

Take the cheapest path that answers the question

采用能够回答问题的最低成本路径

Stop at the first row that fits.
The questionThe callCalls
"Did my edit break anything?"
reticle_verify({ action: "change", files: ["src/App.tsx"] })
1
"Does this known journey still work?"
reticle_run({ tool: "reticle_flow_replay", args: { flowName: "login" } })
1
"Does this new behaviour work?"
reticle_act { steps: [...] }
to the last page, then
reticle_act_and_wait
on the step that ENDS the journey
2
No MCP reachable at all
npx @reticlehq/server verify <url>
in the shell
1, no MCP
reticle_flow_replay
is not on the advertised tool list. It is reached through
reticle_run
exactly as written, which is the supported call shape and why you have to be told it exists.
reticle_verify {action:"change"}
answers
unknown
when no saved flow covers the files you changed: nothing ran, so nothing was proved. That is the honest answer and the signal to record one, never a pass.
在第一个匹配的行处停止。
问题调用调用次数
“我的修改是否破坏了任何功能?”
reticle_verify({ action: "change", files: ["src/App.tsx"] })
1
“这条已知用户旅程还能正常工作吗?”
reticle_run({ tool: "reticle_flow_replay", args: { flowName: "login" } })
1
“这个新行为是否有效?”使用
reticle_act { steps: [...] }
到达最后一页,再对结束该旅程的 step 使用
reticle_act_and_wait
2
完全无法访问 MCP在 shell 中运行
npx @reticlehq/server verify <url>
1,无 MCP
reticle_flow_replay
不在公布的工具列表中。必须严格按照所示方式通过
reticle_run
调用;这是受支持的调用形式,也正是必须明确告知你它的存在的原因。当没有已保存的流程覆盖所修改的文件时,
reticle_verify {action:"change"}
会返回
unknown
:什么都没有运行,因此什么都没有得到证明。这是诚实的答案,也是记录一条流程的信号,绝不能将其视为通过。

Driving by hand

手动驱动

Four calls for a login, not fourteen. Every call is a full model turn, and in a client that approves each one it is also a click.
  1. reticle_look({ action: "page", mode: "interactive" })
    once, for the whole flow. Elements are addressable by role and name, so you do not need to add
    data-testid
    anywhere.
  2. reticle_act { steps: [...] }
    for the setup: every fill and every intermediate click in ONE call.
  3. reticle_act_and_wait({ ref, action, until })
    for the step that ENDS the journey (the confirmation, the saved record, the last page), not the first click that looks like success.
    until
    names that end state before the action fires, which is the difference between a check and a rationalisation. Pass
    durable: true
    when the change should survive a reload. A step on the way with a consequence of its own (a save, a submit) gets its own
    expect
    in
    steps
    , so a journey that breaks at step three fails at step three.
  4. reticle_look({ action: "state" })
    once at the end. If it comes back empty or
    hasCapabilities
    is false, the capabilities file
    init
    generated registered nothing, which is what its
    ℹ AGENT: finish the capabilities file
    line was telling you. Finish it yourself before you drive: open
    src/reticle-dev.*
    , register the app's store if it has one, and list the
    testids
    the flow you picked actually touches. Do not offer, and do not ask; it is a few lines in a file
    init
    already wrote for you. Never report a clean install over an empty state read.
Assert what the app did, not what it shows. A UI that renders the value it just sent, rather than the value the server returned, passes every DOM-level check ever written:
until: { kind: "allOf", predicates: [
  { kind: "net", method: "POST", urlContains: "/api/refund", status: 200, bodyContains: "\"refunded\":1187.01" },
  { kind: "element", query: { testid: "receipt" } },
  { kind: "console", level: "error", absent: true },
]}
Then report what you drove, what it produced, and the
file:line
for anything broken.

登录流程只需四次调用,而不是十四次。每次调用都是完整的模型轮次;在需要逐项批准每次调用的客户端中,它也意味着一次点击。
  1. 对整个流程调用一次
    reticle_look({ action: "page", mode: "interactive" })
    。元素可以通过 role 和 name 寻址,因此无需在任何位置添加
    data-testid
    。
  2. 使用
    reticle_act { steps: [...] }
    完成准备步骤:所有输入和中间点击都在一次调用中执行。
  3. 对结束该旅程的 step(确认信息、已保存记录或最后一页)使用
    reticle_act_and_wait({ ref, action, until })
    ,而不是对第一个看起来成功的点击使用它。
    until
    必须在 action 触发前指明结束状态,这正是检查与主观臆断之间的区别。当变更应在重新加载后继续存在时,传入
    durable: true
    。途中某个自身会产生后果的 step(保存、提交)应在
    steps
    中拥有自己的
    expect
    ,这样旅程在第三步中断时,就会在第三步失败。
  4. 最后调用一次
    reticle_look({ action: "state" })
    。如果返回为空或
    hasCapabilities
    为 false,说明
    init
    生成的 capabilities 文件没有注册任何内容,这正是
    ℹ AGENT: finish the capabilities file
    那一行在提示你的事情。在开始驱动前自行完成:打开
    src/reticle-dev.*
    ,如果应用有 store,就注册该 store,并列出所选流程实际触及的
    testids
    。不要提出建议,也不要询问;这只是
    init
    已经为你写入的文件中的几行代码。绝不能把空的状态读取结果报告为安装正常。
断言应用_做过的事_,而不是它_显示的内容_。如果一个 UI 渲染的是刚刚发送的值,而不是 server 返回的值,那么它就能通过所有现有的 DOM 级检查:
until: { kind: "allOf", predicates: [
  { kind: "net", method: "POST", urlContains: "/api/refund", status: 200, bodyContains: "\"refunded\":1187.01" },
  { kind: "element", query: { testid: "receipt" } },
  { kind: "console", level: "error", absent: true },
]}
然后报告你驱动了什么、它产生了什么结果,以及任何问题的
file:line
。

License key

许可证密钥

Enterprise features are unlocked by a signed key, verified locally with Ed25519 and no network call. If the user hands you one, at any point:
  1. Append
    RETICLE_LICENSE_KEY=<key>
    to the project's
    .env
    (create it if absent). The CLI loads a project-local
    .env
    on every invocation, so nothing else has to change.
  2. Make sure
    .env
    is in
    .gitignore
    . A license key in git is a leaked credential, so check before you write and add the line if it is missing.
  3. Confirm:
    npx @reticlehq/server license
    prints
    active
    ,
    eval
    ,
    missing
    or
    expired
    .
Never echo the key back in your reply, and never put it in a commit, a comment, or a feedback report. Details:
curl https://docs.reticle.sh/enterprise.md
.

企业功能由签名密钥解锁,密钥使用 Ed25519 在本地验证,且不会发起网络调用。如果用户在任何时候提供密钥:
  1. 将
    RETICLE_LICENSE_KEY=<key>
    追加到项目的
    .env
    (如果不存在则创建)。CLI 每次调用都会加载项目本地的
    .env
    ,因此无需进行其他更改。
  2. 确保
    .env
    已列入
    .gitignore
    。提交到 git 的许可证密钥就是凭据泄露,因此写入前先检查;如果缺少该行,则添加。
  3. 确认:
    npx @reticlehq/server license
    会输出
    active
    、
    eval
    、
    missing
    或
    expired
    。
绝不在回复中回显该密钥,也绝不能将其放入 commit、comment 或 feedback report。详情:
curl https://docs.reticle.sh/enterprise.md
。

Feedback is first-class

反馈至关重要

Reticle is built for agents. You are its user, and your experience is the only signal that decides what gets built or fixed, and it disappears when your context does. The moment Reticle breaks, lies, cannot see something you needed, costs too many calls, or gives you trouble during setup:
reticle_session { action: "feedback" } { kind, text }
kind
is one of
bug
,
gap
,
ambiguity
,
feature_request
,
improvement
. One call, then carry on. If the tools are unreachable, file the same report from the shell:
bash
npx @reticlehq/server feedback --agent --kind <bug|gap|ambiguity|feature_request|improvement> "what happened"
Nothing is too minor. Report defects in Reticle; a bug you find in the app under test is Reticle working, and belongs in your answer to the user. Never put app source, secrets, or user data in a report.
Reticle 是为 Agent 打造的。你就是它的用户,而你的使用体验是决定接下来构建或修复什么的唯一信号;一旦上下文消失,这个信号也会随之消失。Reticle 一旦出现故障、给出错误结论、无法看到你所需的信息、耗费过多调用,或在设置过程中给你带来麻烦:
reticle_session { action: "feedback" } { kind, text }
kind
是
bug
、
gap
、
ambiguity
、
feature_request
或
improvement
之一。调用一次,然后继续后续工作。如果工具无法访问,则从 shell 提交同一报告:
bash
npx @reticlehq/server feedback --agent --kind <bug|gap|ambiguity|feature_request|improvement> "what happened"
没有什么问题小到不值得报告。只应报告 Reticle 本身的缺陷;你在被测应用中发现 bug 说明 Reticle 正常工作,该 bug 应出现在给用户的答复中。绝不能在报告中放入应用源代码、机密信息或用户数据。

Going deeper

深入了解

Fetch the one page that answers the question rather than re-reading this file. Appending
.md
to any docs URL returns its source with no site chrome.
bash
curl https://docs.reticle.sh/llms.txt              # every page title and URL; read this first
curl https://docs.reticle.sh/frameworks.md         # per-framework SDK wiring
curl https://docs.reticle.sh/troubleshooting.md    # nothing connected, click did nothing, verdict unknown
curl https://docs.reticle.sh/agent-cheatsheet.md   # the verify loop on one screen
curl https://docs.reticle.sh/predicates.md         # every `until` predicate
只获取能够回答问题的那一个页面,而不是反复重读此文件。为任何文档 URL 追加
.md
,都会返回其源内容,且不包含站点界面。
bash
curl https://docs.reticle.sh/llms.txt              # every page title and URL; read this first
curl https://docs.reticle.sh/frameworks.md         # per-framework SDK wiring
curl https://docs.reticle.sh/troubleshooting.md    # nothing connected, click did nothing, verdict unknown
curl https://docs.reticle.sh/agent-cheatsheet.md   # the verify loop on one screen
curl https://docs.reticle.sh/predicates.md         # every `until` predicate