seeflow
Turn a natural-language prompt into a registered SeeFlow flow at
, with node-attached content (scripts, detail.md, view.html) under
<projectPath>/nodes/<id>/
. Orchestrate five sub-agents and the
CLI; never read the codebase directly, never author
by hand (
writes the envelope for you).
Project layout convention
A host repo opts into seeflow by creating a
directory (the
only place this skill introduces a
folder — the studio itself is path-agnostic).
is shared across every flow in the host and lives at
; 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
, every CLI / file reference is relative to that project root — never re-prefix with
.
(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 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.
When NOT to invoke
- Editing nodes on an existing flow → use the canvas, or hit the CLI directly ().
- Deleting a flow → .
- Re-laying out an existing flow without semantic changes → .
- Empty project (nothing to analyze) → ask the user first.
- Debugging a single broken Play/Status script → edit in-place, re-run Phase 6.
Inputs
- User's prompt; project root (); (optional studio host:port).
- Existing (skip the creation path if already present — fall back to
register --flow flow.json
).
- () — persistent crib sheet shared across every flow in this host repo, written by prior runs. Read before Phase 1. Format:
references/learn-format.md
.
Conventions
| Variable | Resolution |
|---|
| → port → . |
| $PWD/.seeflow/<flow-name>
(the seeflow project root the skill creates and passes to ). |
| — shared across every flow in the host repo. Lives next to the flow folders, never inside one. |
| — project-local scratch directory. Create on demand (), write all intermediate files here, never under system . Already inside the project tree, so no extra write permission is needed. Cleaned up at end of the run (see "Scratch files & cleanup"). |
| Locally installed 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 |
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
— never
,
, or
. 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
container, which is gitignored — add
explicitly if not).
Lifecycle:
- Create on first use — inside any script or wrapper that writes there. Idempotent, costs nothing.
- Generated scripts (Phase 5) — Play / Status bodies that need scratch space should reference (or hardcode relative to when running outside a wrapper that exports it).
- Cleanup at end of run — after Phase 6 prints the final
Flow "..." registered ...
line, the orchestrator removes (). On a failed/aborted run, leave it in place — the contents are the debugging trail.
- Never check in — if 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
to see every subcommand and
for synopsis, body shape, output, and error kinds. Treat the help output as the source of truth and follow what it prints. See
for the resolver snippet.
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).
Core rules
- No mocks. Real services, real state. If something isn't running, stop and ask.
- Bigger picture before INSERTs. Use the natural data-entry path (API, file-drop, producer, seed, webhook).
- Match the project's primary language. Use
runtimeProfile.primaryLanguage
for every script.
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 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 " behavior was data-loss-adjacent.
- Touching . The studio owns it via .
- Passing as . New anchor is the node folder — emit just .
- 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 ; always read first.
- Writing inside a flow folder (
<host>/.seeflow/<flow-name>/LEARN.md
). It is shared across every flow in the host repo — always read/write = , never anywhere else.
- Touching after the initial write. The hook owns that field — see .
- 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 (or ). Use () — 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 after a successful run. Leave it in place on failure (debugging trail); after Phase 6 prints the final line on success.
Phase 0 — pre-flight (parallel)
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
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
has already run in this turn and reported no match.
Silent consent check (see )
Read
. 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
hook handles transfer.
Create a
checklist of the six phases (
…
Phase 6 — end-to-end validation
);
each as it finishes. Phases skipped at the dynamic gate get marked completed with a one-line note. (If
/
aren't loaded, run
with
select:TaskCreate,TaskUpdate
first.)
Capability probe — run before anything else
Run
once and confirm every required subcommand is present:
,
,
,
,
,
,
,
. (Older
versions on
lack one or more —
was added with the project-local scaffold flow;
is the current new-project entry point.) For each missing subcommand, log a feedback entry and surface to the user.
- Required missing → log (, ,
details: missing <subcommand>[, <subcommand>...]
, summary: $SEEFLOW lacks required subcommands; run
npm i -g @tuongaz/seeflow@latest). Then stop — do not start Phase 1.
- All present → continue.
If
itself fails (binary not on PATH,
unavailable), log
(
,
,
summary: $SEEFLOW unresolved — neither local binary nor npx fallback available
) and stop.
Studio probe + LEARN.md (parallel)
Then in a single message:
curl --max-time 0.5 -fsS "$STUDIO_URL/health"
- Read () if present → (else ). This file is shared across every flow in this host — do not look inside any 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 , then run the CLI's subcommand. Re-probe once. If still unreachable, log (, ,
summary: studio /health unreachable after start retry
), surface and stop.
Phase 1 — discover (parallel)
Launch both analyzers in parallel — single message, two 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.
- — in: , , , . Out: , , , , , , .
- — in: , . Out: + a payload (, , , , , , , ). Every fact it learns about how to start / set up the local environment MUST land in .
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
(
,
,
summary: <agent> returned unparseable JSON after retry
), surface, and stop. The same
rule applies to every sub-agent in Phases 2 and 4.
Empty-project / design-only mode
If the project root has no source tree (no
, 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
(Phase 2) as-is — the planner already tolerates a sparse brief.
Log
(
,
,
,
summary: empty project — analyzers skipped, synthetic brief built from prompt
).
Downstream consequences:
- Phase 3 dynamic gate: default to static without re-asking. Without , 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.
- : still write the flow row, but mark it in the purpose column so the next run knows the canvas is not wired to a real system.
Phase 1 → Phase 2 overlap
Start
as soon as the code-analyzer returns — it only needs the code-analyzer's brief plus
. The system-analyzer continues in the background.
When the system-analyzer returns:
- 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 to 10, / to 8, prose fields to 400 chars, etc. Drop any inherited fact that already appears verbatim in (the merger would keep it anyway). Log once with agent: seeflow-system-analyzer, details: oversize-learnupdates-truncated (Nb → Mb)
. The trimmed payload is what feeds steps 1–3.
- Merge into ( — create 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 to ~6 KB after the merge per
references/learn-format.md
§ "Merging rules" (push oldest gotchas into a collapsed block).
- Splice + 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 (, the matching for techs in this flow, the relevant , top 5 ). The rest stays in for the next run; it doesn't need to ride along in every designer prompt.
- Merge / from the code-analyzer into the same write.
Resolve tech refs. Map each
in the merged
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
already had; the planner produces a first draft and the user reviews in Phase 3 anyway.
Phase 2 — plan nodes
Look up the current node + connector contract from the CLI first. Before drafting anything, run
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
, burning a retry.
Launch
with: the brief, the resolved tech-ref paths, the matching
, and the two CLI outputs above. No tools — pure reasoning. The planner reads each ref's
Node modelling section and treats
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
and log
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 with a matching Lucide (, , , , ) and a 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 (, ) sharing the same + + but distinct s.
Output: a single envelope carrying
,
,
,
, and
(planner-only sibling map). The
and
arrays must conform to
and
$SEEFLOW schema connector
— they are forwarded verbatim in a single body to the
subcommand in Phase 3. Any key the CLI rejects here is rejected at
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
, 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: seeflow-node-planner
,
,
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
/
ships under the planner's authority without its review.
Phase 3 — scaffold, populate, layout, review
The skeleton flow lands via four steps, in order. No
authoring by hand —
writes the empty envelope for you. Run
for each subcommand's body shape and flags.
-
Scaffold + register inside the project via . This is the entry point for a new project: the CLI writes the empty
at
(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
later returns
exit code 4 because the pre-check raced), STOP and ask via
—
never silently overwrite, never silently fall back:
A SeeFlow flow is already registered at this path. What do you want to do?
- Open the existing flow (Recommended) — skip creation; run
$SEEFLOW register --path "$repoPath"
to re-attach the existing envelope, surface , then stop. If the user wanted to inspect rather than edit, hand off to .
- 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).
- Overwrite the existing flow — destructive. Confirm once more, then
$SEEFLOW flows:delete --path "$repoPath"
(and for any sidecar leftovers), then retry this step.
Log one
per session (
,
,
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
(and
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
, and returns
(slug is derived from
).
Capture from the response and use it (not ) for every follow-up CLI call below — several commands document slug support in
but the server only resolves by id today.
Registration is a precondition for opening the canvas: the
route only works after this step succeeds, so never surface the canvas URL to the user before this step.
If
returns
(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
writes, run
.
-
Normalize the planner output: strip
(keep them in memory for the review prompt below), then for the planner's designated trigger node (the one whose
is set even as a placeholder), inject the minimum
payload the contract requires so the server accepts the batch. Look up the exact required fields by running
and
(the
shape's required keys) — do not hardcode the shape from memory. Pick the interpreter from
runtimeProfile.primaryLanguage
(falling back to
) and point
at
. The Phase 4 play-designer overwrites the placeholder with the real action via
. 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 (
,
); the studio's id producers (canvas, server auto-assign, the upload endpoint regex) use
/
. 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
that already matches
(edit-case reuse from
), keep it; only mint new canonical ids for net-new nodes. Build a
descriptiveId → canonicalId
map and rewrite:
- , ,
- keys (kept in memory for the review prompt)
2b. Log any silent corrections from steps 2 and 2a (see ). For each correction kind that fired (placeholder- injection, descriptive→canonical id rewrite, unknown-type rename, unknown-field rename, bidir-connector strip, user-to-system-rectangle retype, …), emit one entry with , ,
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.
retype rule. If the planner shipped
for a node whose
is clearly a software system (
,
,
,
,
,
,
, anything ending in
/
/
/
/
), silently retype to
with
inferred from the name (
for web/UI/frontend,
for mobile,
for CLI,
for SDK/Client). Keep
only when
is a human role (
,
,
,
,
). Log one aggregate
entry with
details: user-to-system-rectangle (×N)
. The Phase 3 canvas review surfaces the result to the user — they see the correction.
-
— atomic seed of nodes + connectors in one transactional write. Forward the normalized + id-rewritten
and
arrays as
. 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.
-
Each call validates server-side. A
exit means feed the issues back to the planner and retry — no separate validation step.
Open the canvas, surface the planner's
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
. Two quick questions:
- Layout — any additions, removals, or renames?
- 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 (, ,
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 , fixtures, data-entry paths, and tech adaptations. Re-merge any new first.
- Layout approved + static → print
Flow "<name>" registered as <slug> (static). Open: $STUDIO_URL/d/<slug>
and stop. Still merge any pending .
- Dynamic answer unclear or absent → default to static (dynamic writes executable scripts; opt-in). Log (, ,
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.)
Phase 4 — design Play + Status (parallel)
Launch
+
in parallel (Phase 1 rule). Both receive: context brief, node draft, edit target, tech-ref paths, matching
. They read each ref's
Play /
Status section and treat
as the project override. Tools:
.
Look up the action + node contract from the CLI first. Run
and
(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
, burning a retry.
Output shape (both):
{ nodeId, patch, scriptFile: {path, body, chmod}, validationSafe?, rationale }
triples.
is the exact body for
.
is project-root-relative (
nodes/<nodeId>/scripts/<name>
);
inside
is node-folder-relative (
). 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
.
(play-designer only) may inject synthetic sources (file-drop, webhook receiver) when no natural trigger exists. Shape:
— same as the planner's output.
Phase 5 — patch overlays + layout
For each overlay returned by Phase 4 (parallelise the writes when the script bodies don't depend on each other):
- Write to (Write tool).
- per (default 755).
- Call with the overlay's body. (Body shape:
$SEEFLOW help nodes:patch
.)
If the play-designer emitted
, batch them via
(one call, both arrays atomic), then re-run
. (Body shape:
$SEEFLOW help flow:add-bulk
.)
Edit-case retype routing. When the Phase 2 diff against
flags a node whose
already exists but whose
changed (e.g. a former trigger
reshaped to a decorative
), route it through
nodes:patch { type, ...required fields }
—
not +
. The patch path preserves the per-node folder under
; the delete cascade destroys it. The server validates required fields for the new type after the merge (e.g.
needs
,
needs
,
accepts an optional
string); a
exit means feed the issues to the play-designer and retry.
Retry budget: per-node
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
(
,
,
(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.
Phase 6 — end-to-end validation
Must run. Do not skip or simulate.
Run the
subcommand for the flow. Pass
with the
s of any Phase 4 overlays whose
(third-party or paid actions); skipped nodes appear in
, not as failures. Body / flag details:
.
→ print
Flow "<name>" registered as <slug>. Open: $STUDIO_URL/d/<slug>
, then
to clear project-local scratch. Done.
- Identify failing nodes from / .
- Parallel fix-up (Phase 1 rule): one sub-agent per failing script, single message. A single agent fixing N scripts cross-contaminates.
- Each agent gets the script path (under ), the specific error payload, and a concrete fix hypothesis (
play.ts: ECONNREFUSED on :3001 — start the app first
).
- Edit in-place, re-run the subcommand. Max 2 retries, then log (, ,
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
(
,
,
,
summary: e2e skipped — no runtime to validate against
).
Polish LEARN.md with anything learned
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
(
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
→
, not just
. If the code-analyzer missed a tech entirely, also append the
to
. This is what makes the next
run reuse the work.
Operations
| Topic | File |
|---|
| CLI resolver + discovery via | |
| Error handling, retry caps, sub-agent table | |
| Per-node file convention, action runtime budgets, when-to-use guidance | |
| Core rules | |
| format, lifecycle, merging, contract | references/learn-format.md
|
| Tech-specific best practices | references/tech/README.md
|
| Sub-agent prompts | |
| Feedback collection — consent, kinds, format, redaction, hook handoff | |
| Canonical id generator | $SEEFLOW ids <node|connector> <count>
|