seeflow

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

seeflow

SeeFlow

Turn a natural-language prompt into a registered SeeFlow flow at
<projectPath>/flow.json
, with node-attached content (scripts, detail.md, view.html) under
<projectPath>/nodes/<id>/
. Orchestrate five sub-agents and the
seeflow
CLI; never read the codebase directly, never author
flow.json
by hand (
projects:create
writes the envelope for you).
将自然语言提示转换为已注册的SeeFlow流程,存储在
<projectPath>/flow.json
中,节点附属内容(脚本、detail.md、view.html)位于
<projectPath>/nodes/<id>/
下。协调五个子Agent和
seeflow
CLI;禁止直接读取代码库,禁止手动编写
flow.json
projects:create
会为你生成基础框架)。

Project layout convention

项目布局规范

A host repo opts into seeflow by creating a
<host>/.seeflow/
directory (the only place this skill introduces a
.seeflow
folder — the studio itself is path-agnostic).
LEARN.md
is shared across every flow in the host and lives at
<host>/.seeflow/LEARN.md
; each flow lives in its own subdirectory beside it:
<host>/                          ← the user's repo
  .seeflow/                      ← container, created by this skill
    LEARN.md                     ← shared crib for this skill (project-wide, used by every flow)
    <flow-name>/                 ← seeflow project root — passed to projects:create --path
      flow.json                  ← envelope + nodes/connectors
      style.json                 ← layout/visuals (managed by `flows:layout`)
      nodes/<id>/                ← per-node sidecar files (detail.md, view.html, scripts/)
      .tmp/                      ← per-flow scratch ($SEEFLOW_TMP)
      state/                     ← per-flow runtime script state
Always call
seeflow projects:create --path "$repoPath/.seeflow/<flow-name>" --name "..."
. Inside
--path
, every CLI / file reference is relative to that project root — never re-prefix with
.seeflow/
.
~/.seeflow/
(user-home) is a separate, unrelated directory that holds the studio's global registry / config / pid / consent / feedback files; leave its paths verbatim wherever they appear.
Parallelism is the default — one message, N
Task
calls.
Phase 1's wrong/right block below is canonical; later parallel phases reference it. Narrate each phase boundary with a one-line status (e.g.
Phase 3: scaffolding skeleton flow…
) so silent waits don't feel broken.
宿主仓库可通过创建
<host>/.seeflow/
目录来启用SeeFlow(这是本技能唯一会创建
.seeflow
文件夹的位置——Studio本身与路径无关)。
LEARN.md
是宿主仓库中所有流程共享的参考文档,存储在
<host>/.seeflow/LEARN.md
;每个流程都位于其旁的独立子目录中:
<host>/                          ← 用户的仓库
  .seeflow/                      ← 容器目录,由本技能创建
    LEARN.md                     ← 本技能的共享参考文档(项目级,所有流程共用)
    <flow-name>/                 ← SeeFlow项目根目录——传递给`projects:create --path`参数
      flow.json                  ← 框架文件 + 节点/连接器
      style.json                 ← 布局/视觉配置(由`flows:layout`管理)
      nodes/<id>/                ← 每个节点的附属文件(detail.md、view.html、scripts/)
      .tmp/                      ← 每个流程的临时目录($SEEFLOW_TMP)
      state/                     ← 每个流程的运行时脚本状态
务必调用
seeflow projects:create --path "$repoPath/.seeflow/<flow-name>" --name "..."
。在
--path
指定的目录内,所有CLI/文件引用均相对于该项目根目录——切勿添加
.seeflow/
前缀。
~/.seeflow/
(用户主目录)是独立的无关目录,用于存储Studio的全局注册表/配置/PID/授权/反馈文件;无论何时出现该路径,均保持原样即可。
默认采用并行执行——一条消息,N个
Task
调用
。下文第1阶段的错误/正确示例是标准范式;后续并行阶段均遵循此规则。每个阶段结束时用一行状态说明(例如
Phase 3: 搭建流程骨架…
),避免用户因静默等待而误以为程序故障。

When NOT to invoke

请勿调用的场景

  • Editing nodes on an existing flow → use the canvas, or hit the CLI directly (
    nodes:patch
    ).
  • Deleting a flow →
    flows:delete
    .
  • Re-laying out an existing flow without semantic changes →
    flows:layout
    .
  • Empty project (nothing to analyze) → ask the user first.
  • Debugging a single broken Play/Status script → edit in-place, re-run Phase 6.
  • 编辑现有流程的节点 → 使用画布,或直接调用CLI(
    nodes:patch
    )。
  • 删除流程 →
    flows:delete
  • 仅调整现有流程布局而不修改语义 →
    flows:layout
  • 空项目(无内容可分析) → 先询问用户。
  • 调试单个故障Play/Status脚本 → 就地编辑,重新运行第6阶段。

Inputs

输入参数

  • User's prompt; project root (
    $PWD
    );
    ~/.seeflow/config.json
    (optional studio host:port).
  • Existing
    <project>/flow.json
    (skip the creation path if already present — fall back to
    register --flow flow.json
    ).
  • $learnPath
    (
    $PWD/.seeflow/LEARN.md
    ) — persistent crib sheet shared across every flow in this host repo, written by prior
    /seeflow
    runs. Read before Phase 1. Format:
    references/learn-format.md
    .
  • 用户提示;项目根目录(
    $PWD
    );
    ~/.seeflow/config.json
    (可选的Studio主机:端口)。
  • 已存在的
    <project>/flow.json
    (若已存在则跳过创建流程,改用
    register --flow flow.json
    )。
  • $learnPath
    $PWD/.seeflow/LEARN.md
    )——宿主仓库中所有流程共享的持久化参考文档,由之前的
    /seeflow
    运行生成。在第1阶段前读取。格式参考:
    references/learn-format.md

Conventions

变量约定

VariableResolution
$STUDIO_URL
SEEFLOW_STUDIO_URL
~/.seeflow/config.json
port →
http://localhost:4321
.
$repoPath
$PWD/.seeflow/<flow-name>
(the seeflow project root the skill creates and passes to
projects:create --path
).
$learnPath
$PWD/.seeflow/LEARN.md
shared across every flow in the host repo. Lives next to the flow folders, never inside one.
$SEEFLOW_TMP
$projectPath/.tmp/
— project-local scratch directory. Create on demand (
mkdir -p
), write all intermediate files here, never under system
/tmp
. Already inside the project tree, so no extra write permission is needed. Cleaned up at end of the run (see "Scratch files & cleanup").
seeflow
Locally installed
seeflow
binary if
command -v seeflow >/dev/null 2>&1
; otherwise
npx -y @tuongaz/seeflow@latest
. Resolve once at session start (e.g. `SEEFLOW="$(command -v seeflow >/dev/null 2>&1 && echo seeflow
变量名解析规则
$STUDIO_URL
优先使用
SEEFLOW_STUDIO_URL
环境变量 → 其次从
~/.seeflow/config.json
读取端口 → 默认
http://localhost:4321
$repoPath
$PWD/.seeflow/<flow-name>
(本技能创建并传递给
projects:create --path
的SeeFlow项目根目录)。
$learnPath
$PWD/.seeflow/LEARN.md
—— 宿主仓库中所有流程共享。位于流程文件夹旁,切勿放在任何流程文件夹内部。
$SEEFLOW_TMP
$projectPath/.tmp/
—— 项目级临时目录。按需创建(
mkdir -p
),所有中间文件都写入此处,禁止写入系统
/tmp
。该路径已在项目目录内,无需额外写入权限。运行结束时清理(见“临时文件与清理”)。
seeflow
若本地已安装
seeflow
二进制文件(
command -v seeflow >/dev/null 2>&1
)则使用本地版本;否则使用
npx -y @tuongaz/seeflow@latest
。在会话开始时解析一次(例如`SEEFLOW="$(command -v seeflow >/dev/null 2>&1 && echo seeflow

Scratch files & cleanup

临时文件与清理

Any intermediate file the orchestrator or a generated Play/Status script needs (curl output, jq scratch, downloaded fixtures, comparison snapshots, etc.) goes under
$SEEFLOW_TMP
— never
/tmp
,
/var/tmp
, or
$TMPDIR
. The project-local path requires no extra permission, survives the run for debugging, and is gitignored by convention (the project lives inside the host's
.seeflow/
container, which is gitignored — add
.tmp/
explicitly if not).
Lifecycle:
  1. Create on first use
    mkdir -p "$SEEFLOW_TMP"
    inside any script or wrapper that writes there. Idempotent, costs nothing.
  2. Generated scripts (Phase 5) — Play / Status bodies that need scratch space should reference
    "$SEEFLOW_TMP"
    (or hardcode
    .tmp/...
    relative to
    $repoPath
    when running outside a wrapper that exports it).
  3. Cleanup at end of run — after Phase 6 prints the final
    Flow "..." registered ...
    line, the orchestrator removes
    $SEEFLOW_TMP
    (
    rm -rf "$SEEFLOW_TMP"
    ). On a failed/aborted run, leave it in place — the contents are the debugging trail.
  4. Never check in — if
    .tmp/
    is not yet gitignored, add it before committing.
Every flow mutation goes through the CLI. The studio validates every write server-side — there is no separate validation step. Don't memorise CLI syntax — run
$SEEFLOW help
to see every subcommand and
$SEEFLOW help <command>
for synopsis, body shape, output, and error kinds. Treat the help output as the source of truth and follow what it prints. See
references/cli.md
for the resolver snippet.
编排器或生成的Play/Status脚本所需的任何中间文件(curl输出、jq临时文件、下载的测试数据、对比快照等)都必须放入
$SEEFLOW_TMP
——禁止放入
/tmp
/var/tmp
$TMPDIR
。项目级路径无需额外权限,运行期间保留用于调试,且按约定会被git忽略(项目位于宿主的
.seeflow/
容器内,该目录已被git忽略——若
.tmp/
未被忽略,需显式添加)。
生命周期:
  1. 首次使用时创建 —— 任何需要写入临时目录的脚本或包装器内执行
    mkdir -p "$SEEFLOW_TMP"
    。该操作是幂等的,无额外开销。
  2. 生成的脚本(第5阶段) —— 需要临时空间的Play/Status脚本应引用
    "$SEEFLOW_TMP"
    (或在无包装器导出该变量时,相对于
    $repoPath
    硬编码
    .tmp/...
    )。
  3. 运行结束时清理 —— 第6阶段打印最终的
    Flow "..." registered ...
    信息后,编排器删除
    $SEEFLOW_TMP
    rm -rf "$SEEFLOW_TMP"
    )。若运行失败/中止,则保留该目录——其内容可作为调试线索。
  4. 禁止提交到版本库 —— 若
    .tmp/
    尚未被git忽略,提交前需添加忽略规则。
所有流程修改均通过CLI执行。Studio会在服务端验证每一次写入——无需单独的验证步骤。无需记忆CLI语法——运行
$SEEFLOW help
查看所有子命令,运行
$SEEFLOW help <command>
查看命令概要、请求体格式、输出及错误类型。将帮助输出作为权威来源并严格遵循。CLI解析器片段参考
references/cli.md

Pipeline

执行流程

P0    /health probe ‖ read $learnPath
P1    code-analyzer ‖ system-analyzer
P2    node-planner (kicks off when code-analyzer returns;
                   system-analyzer continues in background)
P3    projects:create (path + name → empty flow.json registered)
      → flow:add-bulk (nodes + connectors, atomic) → flows:layout
      → USER REVIEW + dynamic gate (one combined ask)
P4    play-designer ‖ status-designer
P5    write scripts to nodes/<nodeId>/scripts/
      → nodes:patch (per node, with playAction / statusAction)
      → optional newTriggerNodes via flow:add-bulk
      → flows:layout
P6    e2e
Each phase gates on the previous (with the Phase 1 → Phase 2 overlap).
P0    /健康检查 ‖ 读取$learnPath
P1    代码分析器 ‖ 系统分析器
P2    节点规划器(代码分析器返回后启动;
                   系统分析器在后台继续运行)
P3    projects:create(路径 + 名称 → 注册空flow.json)
      → flow:add-bulk(批量添加节点 + 连接器,原子操作) → flows:layout
      → 用户评审 + 动态分支选择(合并为一次询问)
P4    Play脚本设计器 ‖ Status脚本设计器
P5    将脚本写入nodes/<nodeId>/scripts/
      → nodes:patch(按节点更新,附带playAction / statusAction)
      → 可选通过flow:add-bulk添加新触发节点
      → flows:layout
P6    端到端验证
每个阶段依赖前一阶段的完成(第1阶段到第2阶段可重叠)。

Core rules

核心规则

Full text in
references/core-rules.md
:
  1. No mocks. Real services, real state. If something isn't running, stop and ask.
  2. Bigger picture before INSERTs. Use the natural data-entry path (API, file-drop, producer, seed, webhook).
  3. Match the project's primary language. Use
    runtimeProfile.primaryLanguage
    for every script.
完整内容见
references/core-rules.md
  1. 禁止模拟。使用真实服务、真实状态。若服务未运行,停止并询问用户。
  2. 先了解全局再执行插入操作。使用自然的数据输入路径(API、文件上传、生产者、种子数据、Webhook)。
  3. 匹配项目的主要语言。所有脚本均使用
    runtimeProfile.primaryLanguage
    指定的语言。

Common mistakes

常见错误

  • Serial sub-agent dispatch (N messages, one Task call each). One message, N Task calls — see Phase 1's wrong/right.
  • One sub-agent fixing multiple failing scripts in Phase 6. Each needs isolated context.
  • Authoring
    flow.json
    directly.
    Every mutation is a CLI call.
  • Silently overwriting (or silently falling back from) an existing flow at the target path. Phase 3 step 1's existing-flow gate is mandatory — open / rename / overwrite, the user decides. The old "fall back to
    register
    " behavior was data-loss-adjacent.
  • Touching
    style.json
    .
    The studio owns it via
    flows:layout
    .
  • Passing
    <slug>/scripts/…
    as
    scriptPath
    .
    New anchor is the node folder — emit just
    scripts/play.ts
    .
  • Mocking services or fake fixtures. Use real triggers; copy fixtures from integration tests.
  • Asking "what's your codebase?". Launch the analyzers — that is their job.
  • Skipping or simulating Phase 6. Mandatory; the retry budget handles flakiness.
  • Bypassing the Phase 0 consent check. Never default to
    enabled: true
    ; always read
    ~/.seeflow/consent.json
    first.
  • Writing
    LEARN.md
    inside a flow folder (
    <host>/.seeflow/<flow-name>/LEARN.md
    ).
    It is shared across every flow in the host repo — always read/write
    $learnPath
    =
    $PWD/.seeflow/LEARN.md
    , never anywhere else.
  • Touching
    status
    after the initial
    pending
    write.
    The
    SessionEnd
    hook owns that field — see
    feedback.md
    .
  • Logging without a redacted summary. If the summary would leak a path, hostname, project name, or prompt text, skip the entry rather than emit a leaky one.
  • Writing scratch files to
    /tmp
    (or
    $TMPDIR
    ).
    Use
    $SEEFLOW_TMP
    (
    <projectPath>/.tmp/
    ) — project-local, no permission prompts, and cleaned up at end of run. Same rule applies to scripts the Phase 4 designers emit.
  • Forgetting to clean
    $SEEFLOW_TMP
    after a successful run.
    Leave it in place on failure (debugging trail);
    rm -rf "$SEEFLOW_TMP"
    after Phase 6 prints the final
    Flow registered
    line on success.
  • 串行调度子Agent(N条消息,每次调用一个Task)。应使用一条消息,N个Task调用——见第1阶段的错误/正确示例。
  • 单个子Agent修复第6阶段的多个故障脚本。每个故障脚本需独立上下文。
  • 手动编写
    flow.json
    。所有修改必须通过CLI调用完成。
  • 静默覆盖(或静默回退)目标路径下的现有流程。第3阶段第1步的现有流程检查是强制要求——打开/重命名/覆盖,由用户决定。旧的“回退到
    register
    ”行为可能导致数据丢失。
  • 修改
    style.json
    。该文件由Studio通过
    flows:layout
    管理。
  • <slug>/scripts/…
    作为
    scriptPath
    传递
    。新的锚点是节点文件夹——只需传入
    scripts/play.ts
  • 模拟服务或伪造测试数据。使用真实触发器;从集成测试中复制测试数据。
  • 询问“你的代码库是什么?”。启动分析器——这是它们的职责。
  • 跳过或模拟第6阶段。该阶段是强制要求;重试机制可处理不稳定情况。
  • 绕过第0阶段的授权检查。切勿默认设置
    enabled: true
    ;务必先读取
    ~/.seeflow/consent.json
  • 在流程文件夹内编写
    LEARN.md
    <host>/.seeflow/<flow-name>/LEARN.md
    。该文件是宿主仓库中所有流程共享的——务必读写
    $learnPath
    =
    $PWD/.seeflow/LEARN.md
    ,禁止写入其他位置。
  • 初始写入
    pending
    后修改
    status
    字段
    。该字段由
    SessionEnd
    钩子管理——见
    feedback.md
  • 日志未包含脱敏摘要。若摘要会泄露路径、主机名、项目名称或提示文本,跳过该日志条目,避免泄露信息。
  • 将临时文件写入
    /tmp
    (或
    $TMPDIR
    。使用
    $SEEFLOW_TMP
    <projectPath>/.tmp/
    )——项目级路径,无需权限提示,运行结束时清理。第4阶段设计器生成的脚本也需遵循此规则。
  • 成功运行后忘记清理
    $SEEFLOW_TMP
    。失败时保留该目录(用于调试);成功运行第6阶段并打印最终
    Flow registered
    信息后,执行
    rm -rf "$SEEFLOW_TMP"

Phase 0 — pre-flight (parallel)

第0阶段 — 预检查(并行)

Lookup-first gate — run before anything else

先检查再执行 — 先于所有步骤运行

If the user's prompt reads as inspection rather than creation — any of "show me", "show the", "how does", "how do", "what does", "diagram", "explain", "where does", "what handles" — STOP and route through
/seeflow-lookup
instead. That skill catalogues registered flows and only hands back here if nothing matches. Going straight to creation when a flow already exists wastes the run and surfaces a duplicate. The same gate applies when the user names a flow by slug or title without an explicit verb ("the CRN Enhancement flow", "the checkout flow") — assume inspection unless they prefix it with "create / scaffold / generate / add".
Creation-only triggers (skip the gate): the prompt explicitly says "create / scaffold / generate / add a flow", or
/seeflow-lookup
has already run in this turn and reported no match.
若用户提示属于检查类而非创建类——例如“show me”“show the”“how does”“how do”“what does”“diagram”“explain”“where does”“what handles”——停止操作并将请求路由至
/seeflow-lookup
。该技能会列出已注册的流程,仅当未找到匹配流程时才会转交至此处。若已存在流程却直接创建,会浪费资源并生成重复流程。当用户通过别名或标题指定流程但未明确说明操作(例如“CRN增强流程”“结账流程”)时,同样假设为检查请求,除非用户前缀包含“create / scaffold / generate / add”。
仅触发创建的场景(跳过检查):用户明确说明“create / scaffold / generate / add a flow”,或本次会话中已运行
/seeflow-lookup
且未找到匹配流程。

Silent consent check (see
feedback.md
)

静默授权检查(见
feedback.md

Read
~/.seeflow/consent.json
. If absent, run the first-run prompt and write the file before continuing. The result governs whether qualifying events get logged to
~/.seeflow/feedback.jsonl
for the rest of the run — the skill only writes locally; a
SessionEnd
hook handles transfer.
Create a
TaskCreate
checklist of the six phases (
Phase 1 — discover
Phase 6 — end-to-end validation
);
TaskUpdate
each as it finishes. Phases skipped at the dynamic gate get marked completed with a one-line note. (If
TaskCreate
/
TaskUpdate
aren't loaded, run
ToolSearch
with
select:TaskCreate,TaskUpdate
first.)
读取
~/.seeflow/consent.json
。若文件不存在,运行首次启动提示并在继续前写入该文件。检查结果将决定后续运行中符合条件的事件是否会记录到
~/.seeflow/feedback.jsonl
——本技能仅在本地写入;
SessionEnd
钩子负责数据传输。
创建一个包含六个阶段的
TaskCreate
检查清单(
Phase 1 — 发现
Phase 6 — 端到端验证
);每个阶段完成时调用
TaskUpdate
更新状态。动态分支中跳过的阶段需标记为已完成并添加一行说明。(若未加载
TaskCreate
/
TaskUpdate
,先运行
ToolSearch
并指定
select:TaskCreate,TaskUpdate
。)

Capability probe — run before anything else

能力检查 — 先于所有步骤运行

Run
$SEEFLOW help
once and confirm every required subcommand is present:
projects:create
,
register
,
flow:add-bulk
,
flows:layout
,
nodes:patch
,
schema
,
ids
,
e2e
. (Older
@tuongaz/seeflow
versions on
npx
lack one or more —
ids
was added with the project-local scaffold flow;
projects:create
is the current new-project entry point.) For each missing subcommand, log a feedback entry and surface to the user.
  • Required missing → log
    env-capability-mismatch
    (
    severity: blocker
    ,
    phase: P0
    ,
    details: missing <subcommand>[, <subcommand>...]
    ,
    summary: $SEEFLOW lacks required subcommands; run 
    npm i -g @tuongaz/seeflow@latest
     and retry
    ). Then stop — do not start Phase 1.
  • All present → continue.
If
$SEEFLOW help
itself fails (binary not on PATH,
npx
unavailable), log
env-tool-missing
(
severity: blocker
,
phase: P0
,
summary: $SEEFLOW unresolved — neither local binary nor npx fallback available
) and stop.
运行一次
$SEEFLOW help
并确认所有必需的子命令均存在:
projects:create
register
flow:add-bulk
flows:layout
nodes:patch
schema
ids
e2e
。(旧版本的
@tuongaz/seeflow
可能缺少部分子命令——
ids
是随项目级流程骨架新增的;
projects:create
是当前创建新项目的入口。)对于每个缺失的子命令,记录反馈并告知用户。
  • 必需子命令缺失 → 记录
    env-capability-mismatch
    severity: blocker
    phase: P0
    details: missing <subcommand>[, <subcommand>...]
    summary: $SEEFLOW缺少必需的子命令;请运行
    npm i -g @tuongaz/seeflow@latest
    后重试
    )。然后停止操作——切勿启动第1阶段
  • 所有必需子命令均存在 → 继续。
$SEEFLOW help
本身执行失败(二进制文件不在PATH中,
npx
不可用),记录
env-tool-missing
severity: blocker
phase: P0
summary: $SEEFLOW无法解析——本地二进制文件和npx备用方案均不可用
)并停止操作。

Studio probe + LEARN.md (parallel)

Studio健康检查 + LEARN.md(并行)

Then in a single message:
  1. curl --max-time 0.5 -fsS "$STUDIO_URL/health"
  2. Read
    $learnPath
    (
    $PWD/.seeflow/LEARN.md
    ) if present →
    learnContext
    (else
    null
    ). This file is shared across every flow in this host — do not look inside any
    <flow-name>/
    folder for it. Format:
    references/learn-format.md
    .
  • 200 → Phase 1.
  • !200 → tell the user the studio isn't running, warn the first launch can take a minute or two if it has to fall back to
    npx
    , then run the CLI's
    start
    subcommand. Re-probe
    /health
    once. If still unreachable, log
    env-service-unreachable
    (
    severity: blocker
    ,
    phase: P0
    ,
    summary: studio /health unreachable after start retry
    ), surface and stop.
然后在一条消息中执行以下操作:
  1. curl --max-time 0.5 -fsS "$STUDIO_URL/health"
  2. $learnPath
    $PWD/.seeflow/LEARN.md
    )存在则读取 → 存入
    learnContext
    (否则为
    null
    )。该文件由宿主仓库中所有流程共享——切勿在任何
    <flow-name>/
    文件夹内查找。格式参考:
    references/learn-format.md
  • 返回200 → 进入第1阶段。
  • 未返回200 → 告知用户Studio未运行,提醒首次启动若回退到
    npx
    可能需要一两分钟,然后运行CLI的
    start
    子命令。重新检查
    /health
    一次。若仍无法访问,记录
    env-service-unreachable
    severity: blocker
    phase: P0
    summary: 启动重试后Studio /health仍无法访问
    ),告知用户并停止操作。

Phase 1 — discover (parallel)

第1阶段 — 发现(并行)

Launch both analyzers in parallel — single message, two
Task
calls.
Serial launch roughly doubles wall-clock for zero benefit.
Wrong:
message 1: Task(seeflow-code-analyzer, …) → wait
message 2: Task(seeflow-system-analyzer, …)
Right:
message 1: Task(seeflow-code-analyzer, …)
           Task(seeflow-system-analyzer, …)
Every later parallel phase (Phase 4 designers, Phase 5 retries spanning both overlay families, Phase 6 per-script fix-up) follows this pattern.
  • seeflow-code-analyzer
    — in:
    userPrompt
    ,
    projectRoot
    ,
    existingDemo
    ,
    learnContext
    . Out:
    userIntent
    ,
    audienceFraming
    ,
    scope
    ,
    codePointers
    ,
    knownEndpoints
    ,
    techStack
    ,
    existingDemo
    .
  • seeflow-system-analyzer
    — in:
    projectRoot
    ,
    learnContext
    . Out:
    runtimeProfile
    + a
    learnUpdates
    payload (
    localDevSetup
    ,
    integrationTests
    ,
    fixtures
    ,
    factories
    ,
    seedCommands
    ,
    dataEntryPaths
    ,
    gotchas
    ,
    techAdaptations
    ). Every fact it learns about how to start / set up the local environment MUST land in
    learnUpdates
    .
Tools:
Read, Grep, Glob, LS, Bash
(read-only). Schemas:
agents/seeflow-code-analyzer.md
,
agents/seeflow-system-analyzer.md
,
references/learn-format.md
. Unparseable output: retry that single agent once, then log
agent-output-unparseable
(
severity: failure
,
agent: <slug>
,
summary: <agent> returned unparseable JSON after retry
), surface, and stop. The same
agent-output-unparseable
rule applies to every sub-agent in Phases 2 and 4.
并行启动两个分析器——一条消息,两个
Task
调用
。串行启动会将运行时间大致翻倍且无任何收益。
错误示例:
消息1: Task(seeflow-code-analyzer, …) → 等待
消息2: Task(seeflow-system-analyzer, …)
正确示例:
消息1: Task(seeflow-code-analyzer, …)
           Task(seeflow-system-analyzer, …)
后续所有并行阶段(第4阶段设计器、第5阶段跨覆盖家族的重试、第6阶段按脚本修复)均遵循此模式。
  • seeflow-code-analyzer
    —— 输入:
    userPrompt
    projectRoot
    existingDemo
    learnContext
    。输出:
    userIntent
    audienceFraming
    scope
    codePointers
    knownEndpoints
    techStack
    existingDemo
  • seeflow-system-analyzer
    —— 输入:
    projectRoot
    learnContext
    。输出:
    runtimeProfile
    +
    learnUpdates
    payload(
    localDevSetup
    integrationTests
    fixtures
    factories
    seedCommands
    dataEntryPaths
    gotchas
    techAdaptations
    )。它所了解的关于本地环境启动/设置的所有信息必须存入
    learnUpdates
工具:
Read, Grep, Glob, LS, Bash
(只读)。Schema:
agents/seeflow-code-analyzer.md
agents/seeflow-system-analyzer.md
references/learn-format.md
。若输出无法解析:重试该Agent一次,然后记录
agent-output-unparseable
severity: failure
agent: <slug>
summary: <agent>重试后仍返回无法解析的JSON
),告知用户并停止操作。此规则同样适用于第2阶段和第4阶段的所有子Agent。

Empty-project / design-only mode

空项目/仅设计模式

If the project root has no source tree (no
package.json
, no Go module, no Python project, no language source files), the "When NOT to invoke" rule kicks in: ask the user first. If they say "design anyway" (mockups, demo skeletons, architectural sketches), skip both analyzers and build a synthetic brief by hand from the user's prompt:
json
{
  "userIntent":     "<extracted verbatim from the user's prompt>",
  "audienceFraming":"design-only sketch — no running system to observe",
  "scope":          { "rootEntities": [<inferred from prompt>], "outOfScope": [] },
  "codePointers":   [],
  "knownEndpoints": [],
  "techStack":      [<user-stated, or empty>],
  "existingDemo":   null,
  "runtimeProfile": null
}
Forward that brief to
seeflow-node-planner
(Phase 2) as-is — the planner already tolerates a sparse brief.
Log
mode-fallback
(
severity: degraded
,
phase: P1
,
details: design-only
,
summary: empty project — analyzers skipped, synthetic brief built from prompt
).
Downstream consequences:
  • Phase 3 dynamic gate: default to static without re-asking. Without
    runtimeProfile
    , Phase 4 designers cannot pick a real interpreter or fixture; tell the user to populate code first if they later want dynamic.
  • Phase 6 (e2e): N/A — skip with a one-line note when summarising the run.
  • $learnPath
    :
    still write the flow row, but mark it
    (design-only)
    in the purpose column so the next run knows the canvas is not wired to a real system.
若项目根目录无源代码树(无
package.json
、Go模块、Python项目或语言源文件),则触发“请勿调用的场景”规则:先询问用户。若用户表示“仍要设计”(原型、演示骨架、架构草图),跳过两个分析器,根据用户提示手动构建合成概要:
json
{
  "userIntent":     "<从用户提示中提取的原文>",
  "audienceFraming":"仅设计草图——无运行中的系统可观察",
  "scope":          { "rootEntities": [<从提示中推断>], "outOfScope": [] },
  "codePointers":   [],
  "knownEndpoints": [],
  "techStack":      [<用户指定,或为空>],
  "existingDemo":   null,
  "runtimeProfile": null
}
将该概要直接转发给
seeflow-node-planner
(第2阶段)——规划器已兼容精简概要。
记录
mode-fallback
severity: degraded
phase: P1
details: design-only
summary: 空项目——跳过分析器,根据提示构建合成概要
)。
下游影响:
  • 第3阶段动态分支选择:默认采用静态模式,无需再次询问。若无
    runtimeProfile
    ,第4阶段设计器无法选择真实解释器或测试数据;若用户后续需要动态模式,告知用户先填充代码。
  • 第6阶段(端到端验证):不适用——运行总结时跳过该阶段并添加一行说明。
  • $learnPath
    :仍需写入流程记录,但在purpose列标记为
    (design-only)
    ,以便下次运行时了解画布未连接到真实系统。

Phase 1 → Phase 2 overlap

第1阶段 → 第2阶段重叠

Start
seeflow-node-planner
as soon as the code-analyzer returns — it only needs the code-analyzer's brief plus
techStack
. The system-analyzer continues in the background.
When the system-analyzer returns:
  1. Size-check the payload first. Measure the JSON byte length. If > 16 KB (twice the agent's budget — see
    agents/seeflow-system-analyzer.md
    § "Output budget"), the analyzer drifted. Apply the per-field caps from that section before merging: truncate
    gotchas[]
    to 10,
    fixtures[]
    /
    factories[]
    to 8, prose fields to 400 chars, etc. Drop any inherited fact that already appears verbatim in
    $learnPath
    (the merger would keep it anyway). Log
    agent-output-corrected
    once with
    agent: seeflow-system-analyzer, details: oversize-learnupdates-truncated (Nb → Mb)
    . The trimmed payload is what feeds steps 1–3.
  2. Merge
    learnUpdates
    into
    $learnPath
    (
    $PWD/.seeflow/LEARN.md
    — create
    $PWD/.seeflow/
    if missing; the file is shared across every flow in this host). Anything about boot, ports, env vars, fixtures, gotchas, or tech adaptations MUST land in the file. Re-cap
    $learnPath
    to ~6 KB after the merge per
    references/learn-format.md
    § "Merging rules" (push oldest gotchas into a collapsed
    <details>
    block).
  3. Splice
    runtimeProfile
    +
    $learnPath
    facts into the in-memory context brief used by Phase 4. Forward the trimmed payload — never the raw analyzer output — and only the fields each designer actually consumes (
    runtimeProfile
    , the matching
    techAdaptations.<techId>
    for techs in this flow, the relevant
    dataEntryPaths
    , top 5
    gotchas
    ). The rest stays in
    $learnPath
    for the next run; it doesn't need to ride along in every designer prompt.
  4. Merge
    knownEndpoints
    /
    techStack
    from the code-analyzer into the same write.
Resolve tech refs. Map each
techId
in the merged
## Tech stack
to
references/tech/<techId>.md
. Forward those paths and the matching
## Tech stack adaptations
into Phase 2 / 4 prompts (~3–5 refs per flow). If the system-analyzer hasn't returned yet, forward whatever
techAdaptations
$learnPath
already had; the planner produces a first draft and the user reviews in Phase 3 anyway.
代码分析器返回后立即启动
seeflow-node-planner
——它仅需代码分析器的概要和
techStack
。系统分析器在后台继续运行。
系统分析器返回后:
  1. 首先检查payload大小。测量JSON字节长度。若超过16 KB(Agent预算的两倍——见
    agents/seeflow-system-analyzer.md
    § "Output budget"),说明分析器输出超出范围。合并前应用该章节的字段限制:将
    gotchas[]
    截断为10条,
    fixtures[]
    /
    factories[]
    截断为8条, prose字段截断为400字符等。删除任何已在
    $learnPath
    中存在的重复事实(合并时也会自动忽略)。记录一次
    agent-output-corrected
    ,参数为
    agent: seeflow-system-analyzer, details: oversize-learnupdates-truncated (Nb → Mb)
    。修剪后的payload将用于步骤1–3。
  2. learnUpdates
    合并到
    $learnPath
    $PWD/.seeflow/LEARN.md
    ——若
    $PWD/.seeflow/
    不存在则创建;该文件由宿主仓库中所有流程共享)。任何关于启动、端口、环境变量、测试数据、注意事项或技术适配的信息必须写入该文件。合并后按照
    references/learn-format.md
    § "Merging rules"将
    $learnPath
    压缩至约6 KB(将最旧的注意事项放入折叠的
    <details>
    块中)。
  3. runtimeProfile
    +
    $learnPath
    中的信息插入第4阶段使用的内存上下文概要中。仅转发修剪后的payload——切勿转发原始分析器输出——且仅转发每个设计器实际需要的字段(
    runtimeProfile
    、与当前流程技术匹配的
    techAdaptations.<techId>
    、相关的
    dataEntryPaths
    、前5条
    gotchas
    )。其余信息保留在
    $learnPath
    中供下次运行使用;无需随每个设计器提示传递。
  4. 将代码分析器的
    knownEndpoints
    /
    techStack
    合并到同一文件中。
解析技术引用。将合并后的
## Tech stack
中的每个
techId
映射到
references/tech/<techId>.md
。将这些路径和匹配的
## Tech stack adaptations
转发到第2/4阶段的提示中(每个流程约3–5个引用)。若系统分析器尚未返回,转发
$learnPath
中已有的
techAdaptations
;规划器会生成初稿,用户将在第3阶段评审。

Phase 2 — plan nodes

第2阶段 — 节点规划

Look up the current node + connector contract from the CLI first. Before drafting anything, run
$SEEFLOW schema node
and
$SEEFLOW schema connector
(parallel; one message, two Bash calls) and capture both outputs. Pass them to the planner alongside the brief — the planner has no shell, so what you don't forward, it doesn't know. Skipping this step lets the planner invent fields the CLI rejects on
flow:add-bulk
, burning a retry.
Launch
seeflow-node-planner
with: the brief, the resolved tech-ref paths, the matching
techAdaptations
, and the two CLI outputs above. No tools — pure reasoning. The planner reads each ref's Node modelling section and treats
techAdaptations
as the project-specific override.
Connectors conform to
$SEEFLOW schema connector
and nothing more.
If the planner emits any field the contract rejects, strip it before
flow:add-bulk
and log
agent-output-corrected
with
details: connector-extras-stripped (×N)
. Do not enumerate the legal fields here — re-run the schema command whenever in doubt.
  • Resource nodes first — every DB, queue, event bus, cache, file store, external SaaS gets its own node, typed
    rectangle
    with a matching Lucide
    icon
    (
    database
    ,
    list-ordered
    ,
    radio-tower
    ,
    cloud
    ,
    server
    ) and a
    statusAction
    capability when state is worth probing.
  • Abstraction — one node per service / workflow / worker / queue / DB. Exceptions: independently-meaningful pipeline stages, fan-out consumers, branches, and services hosting multiple independent state machines.
  • Duplicate shared resources for clarity. When a DB / queue / bus is referenced by many nodes and the lines tangle the canvas, split it into role-specific copies (
    orders-db-read
    ,
    orders-db-write
    ) sharing the same
    type
    +
    data.icon
    +
    data.name
    but distinct
    id
    s.
Output: a single envelope carrying
name
,
slug
,
nodes
,
connectors
, and
rationales
(planner-only sibling map). The
nodes
and
connectors
arrays must conform to
$SEEFLOW schema node
and
$SEEFLOW schema connector
— they are forwarded verbatim in a single body to the
flow:add-bulk
subcommand in Phase 3. Any key the CLI rejects here is rejected at
flow:add-bulk
too. One retry on unparseable output, then surface and stop. Full contract:
agents/seeflow-node-planner.md
.
Validate the envelope before continuing. A parseable JSON blob is not the same as a complete envelope. After
JSON.parse
, assert every required key is present and non-empty:
  • typeof name === 'string' && name.length > 0
  • typeof slug === 'string' && slug.length > 0
  • Array.isArray(nodes) && nodes.length > 0
  • Array.isArray(connectors)
    (may be empty for single-node flows)
  • rationales && typeof rationales === 'object' && Object.keys(rationales).length === nodes.length
    (one entry per node id)
If any assertion fails, re-dispatch the planner once with the specific gap echoed back in the prompt (
Your previous output was missing: name, rationales[3 of 5 nodes]. Re-emit the full envelope.
). On second failure, log
agent-output-incomplete
(
severity: failure
,
phase: P2
,
agent: seeflow-node-planner
,
details: <missing-keys>
,
summary: planner returned partial envelope after retry
), surface, and stop. Never silently synthesise the missing fields — losing the planner's own justifications at the Phase 3 review gate is a real loss of signal, and a fabricated
name
/
slug
ships under the planner's authority without its review.
首先从CLI获取当前节点 + 连接器的契约。在起草任何内容前,并行运行
$SEEFLOW schema node
$SEEFLOW schema connector
(一条消息,两个Bash调用)并捕获输出。将输出与概要一起传递给规划器——规划器无shell权限,未转发的信息它无法获取。跳过此步骤会导致规划器生成CLI在
flow:add-bulk
时拒绝的字段,浪费重试机会。
启动
seeflow-node-planner
,传入:概要、解析后的技术引用路径、匹配的
techAdaptations
、上述两个CLI输出。无需工具——纯推理。规划器会读取每个引用的Node modelling章节,并将
techAdaptations
作为项目特定的覆盖规则。
连接器必须严格遵循
$SEEFLOW schema connector
。若规划器输出契约中未定义的字段,在
flow:add-bulk
前删除这些字段并记录
agent-output-corrected
,参数为
details: connector-extras-stripped (×N)
。无需在此枚举合法字段——如有疑问重新运行schema命令即可。
  • 优先创建资源节点 —— 每个数据库、队列、事件总线、缓存、文件存储、外部SaaS服务都要有独立节点,类型为
    rectangle
    ,并匹配Lucide图标(
    database
    list-ordered
    radio-tower
    cloud
    server
    );若状态值得探测,需具备
    statusAction
    能力。
  • 抽象原则 —— 每个服务/工作流/ worker/队列/数据库对应一个节点。例外情况:独立有意义的流水线阶段、扇出消费者、分支、托管多个独立状态机的服务。
  • 为清晰起见复制共享资源。当数据库/队列/总线被多个节点引用导致连线混乱时,将其拆分为角色特定的副本(
    orders-db-read
    orders-db-write
    ),它们共享相同的
    type
    +
    data.icon
    +
    data.name
    id
    不同。
输出:包含
name
slug
nodes
connectors
rationales
(规划器专用的节点映射)的单个框架文件。
nodes
connectors
数组必须符合
$SEEFLOW schema node
$SEEFLOW schema connector
——它们将原样转发给第3阶段的
flow:add-bulk
子命令。CLI在此处拒绝的任何键也会在
flow:add-bulk
时被拒绝。若输出无法解析,重试一次,然后告知用户并停止操作。完整契约见
agents/seeflow-node-planner.md
继续前验证框架文件。可解析的JSON blob不代表完整的框架文件。
JSON.parse
后,断言所有必需键均存在且非空:
  • typeof name === 'string' && name.length > 0
  • typeof slug === 'string' && slug.length > 0
  • Array.isArray(nodes) && nodes.length > 0
  • Array.isArray(connectors)
    (单节点流程可为空)
  • rationales && typeof rationales === 'object' && Object.keys(rationales).length === nodes.length
    (每个节点id对应一个条目)
若任何断言失败,重新调度规划器一次,并在提示中回显具体缺失项(
Your previous output was missing: name, rationales[3 of 5 nodes]. Re-emit the full envelope.
)。若第二次失败,记录
agent-output-incomplete
severity: failure
phase: P2
agent: seeflow-node-planner
details: <missing-keys>
summary: 规划器重试后仍返回不完整的框架文件
),告知用户并停止操作。切勿静默合成缺失字段——第3阶段评审时丢失规划器自身的理由会导致信号丢失,且伪造的
name
/
slug
会在未经规划器评审的情况下生效。

Phase 3 — scaffold, populate, layout, review

第3阶段 — 搭建、填充、布局、评审

The skeleton flow lands via four steps, in order. No
flow.json
authoring by hand —
projects:create
writes the empty envelope for you. Run
$SEEFLOW help <command>
for each subcommand's body shape and flags.
  1. Scaffold + register inside the project via
    projects:create
    .
    This is the entry point for a new project: the CLI writes the empty
    flow.json
    at
    <repoPath>/flow.json
    (project root) and registers it in one shot.
    Existing-flow gate — check before the CLI write. Test
    test -f "$repoPath/flow.json"
    . If the file exists (or
    projects:create
    later returns
    alreadyExists
    exit code 4 because the pre-check raced), STOP and ask via
    AskUserQuestion
    never silently overwrite, never silently fall back:
    A SeeFlow flow is already registered at this path. What do you want to do?
    1. Open the existing flow (Recommended) — skip creation; run
      $SEEFLOW register --path "$repoPath"
      to re-attach the existing envelope, surface
      $STUDIO_URL/d/<slug>
      , then stop. If the user wanted to inspect rather than edit, hand off to
      /seeflow-lookup
      .
    2. Create a new flow with a different name — ask the user for a new flow name, recompute
      $repoPath = $PWD/.seeflow/<new-slug>
      , then retry this step (Phase 1/2 only rerun if the user's intent also changed).
    3. Overwrite the existing flow — destructive. Confirm once more, then
      $SEEFLOW flows:delete --path "$repoPath"
      (and
      rm -rf "$repoPath"
      for any sidecar leftovers), then retry this step.
    Log one
    plan-revision
    per session (
    severity: friction
    ,
    phase: P3
    ,
    summary: existing flow at target path; user picked <open|rename|overwrite>
    ). Debounce — even if the user toggles between options, the entry is written once.
    Gate clear → forward the planner-supplied
    name
    (and
    description
    if the planner provided one):
    bash
    $SEEFLOW projects:create --path "$repoPath" --name "$plannerName" [--description "$plannerDescription"]
    The studio writes the envelope, adds a registry entry under
    ~/.seeflow/registry.json
    , and returns
    { id, slug }
    (slug is derived from
    name
    ). Capture
    id
    from the response and use it (not
    slug
    ) for every follow-up CLI call below
    — several commands document slug support in
    help
    but the server only resolves by id today. Registration is a precondition for opening the canvas: the
    $STUDIO_URL/d/<slug>
    route only works after this step succeeds, so never surface the canvas URL to the user before this step.
    If
    projects:create
    returns
    alreadyExists
    (code 4) after the pre-check passed (filesystem race), loop back to the gate above and let the user decide — do not auto-fall-back. Do not hardcode the envelope shape from memory; if you need to inspect what
    projects:create
    writes, run
    $SEEFLOW schema flow
    .
  2. Normalize the planner output: strip
    rationales
    (keep them in memory for the review prompt below), then for the planner's designated trigger node (the one whose
    data.playAction
    is set even as a placeholder), inject the minimum
    playAction
    payload the contract requires so the server accepts the batch. Look up the exact required fields by running
    $SEEFLOW schema action
    and
    $SEEFLOW schema node
    (the
    PlayAction
    shape's required keys) — do not hardcode the shape from memory. Pick the interpreter from
    runtimeProfile.primaryLanguage
    (falling back to
    bun
    ) and point
    scriptPath
    at
    scripts/play.ts
    . The Phase 4 play-designer overwrites the placeholder with the real action via
    nodes:patch
    . The script file does not need to exist yet — Phase 5 writes it, Phase 6 runs it. 2a. Mint canonical ids. Planner ids are descriptive (
    checkout-api
    ,
    c-order-server-event-bus
    ); the studio's id producers (canvas, server auto-assign, the upload endpoint regex) use
    node-<10 base62>
    /
    conn-<10 base62>
    . Rewrite at the boundary so flow.json matches. Use the CLI — it shares the exact alphabet and rejection-sampling logic with every other id producer in the studio:
    bash
    mapfile -t nodeIds < <($SEEFLOW ids node "${#nodes[@]}")
    mapfile -t connIds < <($SEEFLOW ids connector "${#connectors[@]}")
    For each
    nodes[i].id
    that already matches
    ^node-[A-Za-z0-9]{10}$
    (edit-case reuse from
    editTarget
    ), keep it; only mint new canonical ids for net-new nodes. Build a
    descriptiveId → canonicalId
    map and rewrite:
    • nodes[].id
    • connectors[].id
      ,
      connectors[].source
      ,
      connectors[].target
    • rationales
      keys (kept in memory for the review prompt) 2b. Log any silent corrections from steps 2 and 2a (see
      feedback.md
      ). For each correction kind that fired (placeholder-
      playAction
      injection, descriptive→canonical id rewrite, unknown-type rename, unknown-field rename, bidir-connector strip, user-to-system-rectangle retype, …), emit one
      agent-output-corrected
      entry with
      severity: corrected
      ,
      phase: P3
      ,
      agent: seeflow-node-planner
      , and
      details: <correction-kind> (×N)
      where N is the count. Aggregate across nodes — never one entry per node. If no corrections were needed, log nothing. This is the signal that the planner drifted from the contract; without it, the orchestrator's silent patching is invisible.
    user-to-system-rectangle
    retype rule.
    If the planner shipped
    type:'user'
    for a node whose
    data.name
    is clearly a software system (
    Web UI
    ,
    Mobile App
    ,
    Browser
    ,
    SPA
    ,
    Desktop Client
    ,
    CLI
    ,
    SDK
    , anything ending in
    Client
    /
    App
    /
    UI
    /
    Frontend
    /
    Service
    ), silently retype to
    rectangle
    with
    data.icon
    inferred from the name (
    monitor
    for web/UI/frontend,
    smartphone
    for mobile,
    terminal
    for CLI,
    plug
    for SDK/Client). Keep
    type:'user'
    only when
    data.name
    is a human role (
    Customer
    ,
    Support Agent
    ,
    Reviewer
    ,
    Approver
    ,
    Operator
    ). Log one aggregate
    agent-output-corrected
    entry with
    details: user-to-system-rectangle (×N)
    . The Phase 3 canvas review surfaces the result to the user — they see the correction.
  3. flow:add-bulk
    — atomic seed of nodes + connectors in one transactional write. Forward the normalized + id-rewritten
    nodes
    and
    connectors
    arrays as
    { nodes, connectors }
    . Connectors may reference nodes from the same call — the server validates the merged graph as a whole, so a dangling source/target or a malformed node rolls back both arrays together. No two-phase commit to reason about; no orphan nodes if connectors fail.
  4. flows:layout
    — run ELK and write
    style.json
    .
Each call validates server-side. A
badSchema
exit means feed the issues back to the planner and retry — no separate validation step.
Open the canvas, surface the planner's
rationales
per node — prefix each with
<data.name> (<canonical id>):
so the human sees a readable anchor despite the opaque id (
POST /orders (node-Ab12cd34Ef): Single HTTP service — internal routes are implementation detail.
) — and ask one combined question (layout review + dynamic gate in a single round-trip — two consecutive waits is interrogation):
bash
URL="$STUDIO_URL/d/$slug"
(open "$URL" 2>/dev/null || xdg-open "$URL" 2>/dev/null || start "$URL" 2>/dev/null) &
Opened the canvas at
<url>
. Two quick questions:
  1. Layout — any additions, removals, or renames?
  2. Dynamic or static — continue with Play scripts + Status probes so the canvas reacts to your running system, or stop with the static layout?
Wait once. Parse both answers from the reply.
  • Layout changes requested → log
    plan-revision
    (
    severity: friction
    ,
    phase: P3
    ,
    summary: user requested layout changes at canvas review gate
    ), re-run node-planner with the feedback, repeat the combined ask. The dynamic answer (if given) is remembered but not acted on until the layout is approved. Debounce — log once per session even if the user revises multiple times.
  • Layout approved + dynamic → Phase 4. If the system-analyzer is still running, await it now; Phase 4 designers need its
    runtimeProfile
    , fixtures, data-entry paths, and tech adaptations. Re-merge any new
    learnUpdates
    first.
  • Layout approved + static → print
    Flow "<name>" registered as <slug> (static). Open: $STUDIO_URL/d/<slug>
    and stop. Still merge any pending
    learnUpdates
    .
  • Dynamic answer unclear or absent → default to static (dynamic writes executable scripts; opt-in). Log
    mode-fallback
    (
    severity: degraded
    ,
    phase: P3
    ,
    details: dynamic-to-static
    ,
    summary: dynamic gate unclear; auto-downgraded to static
    ).
(Design-only mode from Phase 1's empty-project branch defaults to static here without re-asking.)
流程骨架通过四个步骤依次生成。禁止手动编写
flow.json
——
projects:create
会为你生成空框架文件。每个子命令的请求体格式和参数见
$SEEFLOW help <command>
  1. 通过
    projects:create
    在项目内搭建并注册
    。这是创建新项目的入口:CLI在
    <repoPath>/flow.json
    (项目根目录)写入空
    flow.json
    并完成注册。
    现有流程检查——CLI写入前执行。测试
    test -f "$repoPath/flow.json"
    。若文件存在(或
    projects:create
    因检查竞态返回
    alreadyExists
    退出码4),停止操作并通过
    AskUserQuestion
    询问用户——切勿静默覆盖,切勿静默回退
    该路径已注册一个SeeFlow流程。你想要执行什么操作?
    1. 打开现有流程(推荐)——跳过创建;运行
      $SEEFLOW register --path "$repoPath"
      重新关联现有框架文件,显示
      $STUDIO_URL/d/<slug>
      ,然后停止。若用户想要检查而非编辑,转交至
      /seeflow-lookup
    2. 使用不同名称创建新流程——询问用户新流程名称,重新计算
      $repoPath = $PWD/.seeflow/<new-slug>
      ,然后重试此步骤(仅当用户意图改变时才重新运行第1/2阶段)。
    3. 覆盖现有流程——破坏性操作。再次确认,然后执行
      $SEEFLOW flows:delete --path "$repoPath"
      (并执行
      rm -rf "$repoPath"
      删除任何附属文件),然后重试此步骤。
    每个会话记录一次
    plan-revision
    severity: friction
    phase: P3
    summary: 目标路径存在现有流程;用户选择<open|rename|overwrite>
    )。去重——即使用户多次切换选项,仅记录一次。
    检查通过后,转发规划器提供的
    name
    (若规划器提供了
    description
    也一并转发):
    bash
    $SEEFLOW projects:create --path "$repoPath" --name "$plannerName" [--description "$plannerDescription"]
    Studio写入框架文件,在
    ~/.seeflow/registry.json
    中添加注册表条目,并返回
    { id, slug }
    (slug由
    name
    派生)。从响应中捕获
    id
    并在后续所有CLI调用中使用(而非
    slug
    ——多个命令在
    help
    中说明支持slug,但服务器目前仅通过id解析。注册是打开画布的前提
    $STUDIO_URL/d/<slug>
    路由仅在此步骤成功后生效,因此切勿在此步骤前向用户显示画布URL。
    若预检查通过后
    projects:create
    仍返回
    alreadyExists
    (代码4,文件系统竞态),回到上述检查步骤让用户决定——切勿自动回退。切勿凭记忆硬编码框架文件格式;若需要查看
    projects:create
    写入的内容,运行
    $SEEFLOW schema flow
  2. 规范化规划器输出:删除
    rationales
    (保留在内存中用于下文的评审提示),然后对于规划器指定的触发节点(
    data.playAction
    已设置为占位符的节点),注入契约要求的最小
    playAction
    payload,确保服务器接受批量操作。通过运行
    $SEEFLOW schema action
    $SEEFLOW schema node
    PlayAction
    形状的必需键)查找确切的必需字段——切勿凭记忆硬编码形状。从
    runtimeProfile.primaryLanguage
    选择解释器(回退到
    bun
    ),并将
    scriptPath
    指向
    scripts/play.ts
    。第4阶段的Play设计器会通过
    nodes:patch
    用真实操作覆盖占位符。脚本文件无需提前存在——第5阶段会写入,第6阶段会运行。 2a. 生成标准id。规划器生成的id是描述性的(
    checkout-api
    c-order-server-event-bus
    );Studio的id生成器(画布、服务器自动分配、上传端点正则)使用
    node-<10位base62>
    /
    conn-<10位base62>
    格式。在边界处重写id,使flow.json匹配该格式。使用CLI——它与Studio中所有其他id生成器共享完全相同的字符集和拒绝采样逻辑:
    bash
    mapfile -t nodeIds < <($SEEFLOW ids node "${#nodes[@]}")
    mapfile -t connIds < <($SEEFLOW ids connector "${#connectors[@]}")
    对于已匹配
    ^node-[A-Za-z0-9]{10}$
    nodes[i].id
    (来自
    editTarget
    的编辑复用),保留原id;仅为新增节点生成新的标准id。构建
    描述性id → 标准id
    映射并重写:
    • nodes[].id
    • connectors[].id
      connectors[].source
      connectors[].target
    • rationales
      的键(保留在内存中用于评审提示) 2b. 记录步骤2和2a中的任何静默修正(见
      feedback.md
      )。对于每种触发的修正类型(占位符
      playAction
      注入、描述性id→标准id重写、未知类型重命名、未知字段重命名、双向连接器删除、用户节点→系统矩形重命名等),记录一条
      agent-output-corrected
      条目,参数为
      severity: corrected
      phase: P3
      agent: seeflow-node-planner
      details: <correction-kind> (×N)
      (N为数量)。按节点聚合——切勿为每个节点记录一条。若无需修正,无需记录。这是规划器偏离契约的信号;若无此记录,编排器的静默修补将不可见。
    用户节点→系统矩形重命名规则。若规划器为
    data.name
    明显是软件系统的节点(
    Web UI
    Mobile App
    Browser
    SPA
    Desktop Client
    CLI
    SDK
    、任何以
    Client
    /
    App
    /
    UI
    /
    Frontend
    /
    Service
    结尾的名称)设置了
    type:'user'
    ,静默将其重命名为
    rectangle
    类型,并根据名称推断
    data.icon
    (web/UI/frontend对应
    monitor
    ,mobile对应
    smartphone
    ,CLI对应
    terminal
    ,SDK/Client对应
    plug
    )。仅当
    data.name
    是人类角色(
    Customer
    Support Agent
    Reviewer
    Approver
    Operator
    )时保留
    type:'user'
    。记录一条聚合的
    agent-output-corrected
    条目,参数为
    details: user-to-system-rectangle (×N)
    。第3阶段的画布评审会将结果展示给用户——用户会看到修正后的内容。
  3. flow:add-bulk
    —— 原子性批量写入节点 + 连接器。将规范化并完成id重写的
    nodes
    connectors
    数组作为
    { nodes, connectors }
    转发。连接器可引用本次调用中的节点——服务器会整体验证合并后的图,因此悬空的源/目标或格式错误的节点会回滚两个数组。无需考虑两阶段提交;若连接器失败,不会产生孤立节点。
  4. flows:layout
    —— 运行ELK算法并写入
    style.json
每个调用都会在服务端验证。若返回
badSchema
退出码,将问题反馈给规划器并重试——无需单独的验证步骤。
打开画布,按节点展示规划器的
rationales
——每个条目前缀为
<data.name> (<标准id>):
,以便用户在id不透明的情况下看到可读的锚点(例如
POST /orders (node-Ab12cd34Ef): 单个HTTP服务——内部路由是实现细节。
)——并询问一个合并后的问题(布局评审 + 动态分支选择合并为一次往返——连续两次等待会让用户感到被审问):
bash
URL="$STUDIO_URL/d/$slug"
(open "$URL" 2>/dev/null || xdg-open "$URL" 2>/dev/null || start "$URL" 2>/dev/null) &
已在<url>打开画布。两个快速问题:
  1. 布局——是否需要添加、删除或重命名节点?
  2. 动态或静态——继续添加Play脚本 + Status探针使画布能响应运行中的系统,还是停止并保留静态布局?
等待一次回复。从回复中解析两个问题的答案。
  • 用户要求修改布局 → 记录
    plan-revision
    severity: friction
    phase: P3
    summary: 用户在画布评审阶段要求修改布局
    ),将反馈转发给节点规划器重新运行,重复合并询问。动态选择的答案(若已提供)会被记住,但需等到布局批准后才生效。去重——即使用户多次修改,每个会话仅记录一次。
  • 布局批准 + 动态模式 → 进入第4阶段。若系统分析器仍在运行,等待其完成;第4阶段设计器需要其
    runtimeProfile
    、测试数据、数据输入路径和技术适配信息。先合并任何新的
    learnUpdates
  • 布局批准 + 静态模式 → 打印
    Flow "<name>" 已注册为<slug>(静态)。打开:$STUDIO_URL/d/<slug>
    并停止操作。仍需合并任何待处理的
    learnUpdates
  • 动态选择答案不明确或未提供 → 默认采用静态模式(动态模式会写入可执行脚本;需用户主动选择)。记录
    mode-fallback
    severity: degraded
    phase: P3
    details: dynamic-to-static
    summary: 动态分支选择不明确;自动降级为静态模式
    )。
(第1阶段空项目分支的仅设计模式在此处默认采用静态模式,无需再次询问。)

Phase 4 — design Play + Status (parallel)

第4阶段 — 设计Play + Status(并行)

Launch
seeflow-play-designer
+
seeflow-status-designer
in parallel (Phase 1 rule). Both receive: context brief, node draft, edit target, tech-ref paths, matching
techAdaptations
. They read each ref's Play / Status section and treat
techAdaptations
as the project override. Tools:
Read, Grep, Glob, LS
.
Look up the action + node contract from the CLI first. Run
$SEEFLOW schema action
and
$SEEFLOW schema node
(parallel; one message, two Bash calls) and capture both outputs. Pass them to each designer alongside the brief — designers have no shell, so what you don't forward, they don't know. The same outputs serve both designers; reuse them. Skipping this step lets the designer invent fields the CLI rejects on
nodes:patch
, burning a retry.
Output shape (both):
{ nodeId, patch, scriptFile: {path, body, chmod}, validationSafe?, rationale }
triples.
patch
is the exact body for
seeflow nodes:patch
.
scriptFile.path
is project-root-relative (
nodes/<nodeId>/scripts/<name>
);
playAction.scriptPath
inside
patch
is node-folder-relative (
scripts/play.ts
). Full contracts:
agents/seeflow-play-designer.md
,
agents/seeflow-status-designer.md
.
Sample data priority: integration/e2e fixtures (
runtimeProfile.integrationTestDir
, copy verbatim) → seed / migration / ORM factories → README / OpenAPI / Postman examples → invent last, note in
rationale
.
newTriggerNodes
(play-designer only) may inject synthetic sources (file-drop, webhook receiver) when no natural trigger exists. Shape:
{nodes, connectors}
— same as the planner's output.
并行启动
seeflow-play-designer
+
seeflow-status-designer
(遵循第1阶段规则)。两者均接收:上下文概要、节点草稿、编辑目标、技术引用路径、匹配的
techAdaptations
。它们会读取每个引用的Play / Status章节,并将
techAdaptations
作为项目覆盖规则。工具:
Read, Grep, Glob, LS
首先从CLI获取操作 + 节点的契约。并行运行
$SEEFLOW schema action
$SEEFLOW schema node
(一条消息,两个Bash调用)并捕获输出。将输出与概要一起传递给每个设计器——设计器无shell权限,未转发的信息它无法获取。同一输出可用于两个设计器;复用即可。跳过此步骤会导致设计器生成CLI在
nodes:patch
时拒绝的字段,浪费重试机会。
输出格式(两者相同):
{ nodeId, patch, scriptFile: {path, body, chmod}, validationSafe?, rationale }
三元组。
patch
seeflow nodes:patch
的精确请求体。
scriptFile.path
是相对于项目根目录的路径(
nodes/<nodeId>/scripts/<name>
);
patch
内的
playAction.scriptPath
是相对于节点文件夹的路径(
scripts/play.ts
)。完整契约见
agents/seeflow-play-designer.md
agents/seeflow-status-designer.md
测试数据优先级: 集成/端到端测试数据(
runtimeProfile.integrationTestDir
,原样复制) → 种子/迁移/ORM工厂 → README/OpenAPI/Postman示例 → 最后才自行生成,并在
rationale
中说明。
newTriggerNodes
(仅Play设计器可用)可在无自然触发器时注入合成源(文件上传、Webhook接收器)。格式:
{nodes, connectors}
——与规划器的输出格式相同。

Phase 5 — patch overlays + layout

第5阶段 — 修补覆盖层 + 布局

For each overlay returned by Phase 4 (parallelise the writes when the script bodies don't depend on each other):
  1. Write
    scriptFile.body
    to
    scriptFile.path
    (Write tool).
  2. chmod
    per
    scriptFile.chmod
    (default 755).
  3. Call
    nodes:patch
    with the overlay's
    patch
    body. (Body shape:
    $SEEFLOW help nodes:patch
    .)
If the play-designer emitted
newTriggerNodes
, batch them via
flow:add-bulk
(one call, both arrays atomic), then re-run
flows:layout
. (Body shape:
$SEEFLOW help flow:add-bulk
.)
Edit-case retype routing. When the Phase 2 diff against
editTarget
flags a node whose
id
already exists but whose
type
changed (e.g. a former trigger
rectangle
reshaped to a decorative
database
), route it through
nodes:patch { type, ...required fields }
not
nodes:delete
+
flow:add-bulk
. The patch path preserves the per-node folder under
nodes/<id>/
; the delete cascade destroys it. The server validates required fields for the new type after the merge (e.g.
* → image
needs
path
,
* → icon
needs
icon
,
* → html
accepts an optional
html
string); a
badSchema
exit means feed the issues to the play-designer and retry.
Retry budget: per-node
nodes:patch
failure → re-dispatch that one designer with the CLI's reported issues, retry, max 3 per node. Parallelise re-dispatches when more than one node failed (Phase 1 rule). When the budget is exhausted for a node, log
retry-exhausted
(
severity: failure
,
phase: P5
,
code: badSchema
(or the actual code),
summary: nodes:patch retries exhausted on <kind> (N nodes)
). Aggregate across nodes — one entry per (kind, code) pair, not one per node.
对于第4阶段返回的每个覆盖层(当脚本内容互不依赖时并行写入):
  1. scriptFile.body
    写入
    scriptFile.path
    (使用Write工具)。
  2. scriptFile.chmod
    设置权限(默认755)。
  3. 使用覆盖层的
    patch
    请求体调用
    nodes:patch
    。(请求体格式见
    $SEEFLOW help nodes:patch
    。)
若Play设计器输出了
newTriggerNodes
,通过
flow:add-bulk
批量添加(一次调用,原子性写入两个数组),然后重新运行
flows:layout
。(请求体格式见
$SEEFLOW help flow:add-bulk
。)
编辑场景下的类型重命名路由。当第2阶段与
editTarget
的差异标记显示某个节点的
id
已存在但
type
已更改(例如原触发节点
rectangle
改为装饰性
database
),通过
nodes:patch { type, ...required fields }
处理——禁止使用
nodes:delete
+
flow:add-bulk
。修补路径会保留
nodes/<id>/
下的节点文件夹;删除操作会级联销毁该文件夹。服务器会在合并后验证新类型的必需字段(例如
* → image
需要
path
* → icon
需要
icon
* → html
接受可选的
html
字符串);若返回
badSchema
退出码,将问题反馈给Play设计器并重试。
重试预算: 按节点的
nodes:patch
失败 → 重新调度该节点对应的设计器并传入CLI报告的问题,重试,每个节点最多3次。当多个节点失败时并行重新调度(遵循第1阶段规则)。当某个节点的重试预算耗尽,记录
retry-exhausted
severity: failure
phase: P5
code: badSchema
(或实际错误码),
summary: nodes:patch在<kind>上重试耗尽(N个节点)
)。按节点聚合——每个(类型,错误码)对记录一条,而非每个节点一条。

Phase 6 — end-to-end validation

第6阶段 — 端到端验证

Must run. Do not skip or simulate.
Run the
e2e
subcommand for the flow. Pass
--skip-nodes
with the
nodeId
s of any Phase 4 overlays whose
validationSafe === false
(third-party or paid actions); skipped nodes appear in
skipped[]
, not as failures. Body / flag details:
$SEEFLOW help e2e
.
ok: true
→ print
Flow "<name>" registered as <slug>. Open: $STUDIO_URL/d/<slug>
, then
rm -rf "$SEEFLOW_TMP"
to clear project-local scratch. Done.
ok: false
fix-up loop:
  1. Identify failing nodes from
    plays[*].error
    /
    statuses[*].outcome
    .
  2. Parallel fix-up (Phase 1 rule): one sub-agent per failing script, single message. A single agent fixing N scripts cross-contaminates.
  3. Each agent gets the script path (under
    nodes/<nodeId>/scripts/
    ), the specific error payload, and a concrete fix hypothesis (
    play.ts: ECONNREFUSED on :3001 — start the app first
    ).
  4. Edit in-place, re-run the
    e2e
    subcommand. Max 2 retries, then log
    seeflow:e2e-fail
    (
    severity: failure
    ,
    phase: P6
    ,
    details: <N> failing scripts after fix-up
    ,
    summary: e2e ok:false after retry budget exhausted
    ) and ask retry / stop.
If the run is design-only (Phase 1 fallback), skip Phase 6 entirely and log
phase-skipped
(
severity: degraded
,
phase: P6
,
details: design-only
,
summary: e2e skipped — no runtime to validate against
).
必须运行。禁止跳过或模拟。
运行流程的
e2e
子命令。对于第4阶段覆盖层中
validationSafe === false
的节点(第三方或付费操作),传入
--skip-nodes
参数指定其
nodeId
;跳过的节点会出现在
skipped[]
中,不会被标记为失败。请求体/参数细节见
$SEEFLOW help e2e
ok: true
→ 打印
Flow "<name>" 已注册为<slug>。打开:$STUDIO_URL/d/<slug>
,然后执行
rm -rf "$SEEFLOW_TMP"
清理项目级临时目录。操作完成。
ok: false
修复循环:
  1. plays[*].error
    /
    statuses[*].outcome
    中识别失败节点。
  2. 并行修复(遵循第1阶段规则):每个故障脚本对应一个子Agent,一条消息。单个Agent修复N个脚本会导致上下文交叉污染。
  3. 每个Agent会收到脚本路径(位于
    nodes/<nodeId>/scripts/
    下)、具体错误payload和明确的修复假设(例如
    play.ts: ECONNREFUSED on :3001 — 先启动应用
    )。
  4. 就地编辑,重新运行
    e2e
    子命令。最多重试2次,然后记录
    seeflow:e2e-fail
    severity: failure
    phase: P6
    details: <N>个脚本修复后仍失败
    summary: 重试预算耗尽后端到端验证ok:false
    )并询问用户是否重试/停止。
若为仅设计模式(第1阶段回退),完全跳过第6阶段并记录
phase-skipped
severity: degraded
phase: P6
details: design-only
summary: 跳过端到端验证——无运行时可验证
)。

Polish LEARN.md with anything learned

用新发现的内容完善LEARN.md

If Phases 5-6 surfaced something the next run would want — port mismatch, fixture path, missed env var, working seed command, useful data-entry path — append to
$learnPath
(
Gotchas
bullet or the relevant section). Also append the flow to the "Flows already created" table with today's date and a one-line purpose. Skip if nothing new — empty updates are noise. The file is shared across every flow in this host, so the table accumulates every flow the skill has ever scaffolded here.
Tech-specific learnings (a helper, a required attribute, an emulator quirk, a fixture path) go in
## Tech stack adaptations
### <techId>
, not just
## Gotchas
. If the code-analyzer missed a tech entirely, also append the
techId
to
## Tech stack
. This is what makes the next
/seeflow
run reuse the work.
若第5-6阶段发现了下次运行需要的信息——端口不匹配、测试数据路径、遗漏的环境变量、可用的种子命令、有用的数据输入路径——追加到
$learnPath
Gotchas
项目符号或相关章节)。同时将该流程追加到“已创建流程”表格中,包含日期和一行说明。若无新内容则跳过——空更新是冗余信息。该文件由宿主仓库中所有流程共享,因此表格会累积本技能在此处搭建的所有流程。
技术特定的经验(助手、必需属性、模拟器 quirks、测试数据路径)应放入
## Tech stack adaptations
### <techId>
,而非仅放入
## Gotchas
。若代码分析器完全遗漏了某项技术,还需将
techId
追加到
## Tech stack
中。这能让下次
/seeflow
运行复用已有工作。

Operations

操作参考

TopicFile
CLI resolver + discovery via
$SEEFLOW help
references/cli.md
Error handling, retry caps, sub-agent table
references/operations.md
Per-node file convention, action runtime budgets, when-to-use guidance
references/schema.md
Core rules
references/core-rules.md
$learnPath
format, lifecycle, merging,
learnUpdates
contract
references/learn-format.md
Tech-specific best practices
references/tech/README.md
Sub-agent prompts
agents/seeflow-*.md
Feedback collection — consent, kinds, format, redaction, hook handoff
feedback.md
Canonical id generator
$SEEFLOW ids <node|connector> <count>
主题文件
CLI解析器 + 通过
$SEEFLOW help
发现命令
references/cli.md
错误处理、重试上限、子Agent表格
references/operations.md
按节点的文件约定、操作运行时预算、使用场景指南
references/schema.md
核心规则
references/core-rules.md
$learnPath
格式、生命周期、合并规则、
learnUpdates
契约
references/learn-format.md
技术特定最佳实践
references/tech/README.md
子Agent提示
agents/seeflow-*.md
反馈收集——授权、类型、格式、脱敏、钩子转交
feedback.md
标准id生成器
$SEEFLOW ids <node|connector> <count>