Tag any saved workflow with the literal tag `module` and the Kforge
Labs sidebar starts treating it as a reusable building block: a green
`pi pi-plus-circle` icon replaces the file glyph, left-click
**inserts** the cluster at the viewport center (with internal links
re-created and the new nodes left selected), and a distinct hover
tooltip surfaces the changed semantics. Designed for the
`EXR-output stack` / `depth-only render` / `Wan 2.2 prompt
module` pattern: small clusters the maintainer wants to drop into
many workflows without rebuilding them by hand.
What changed:
1. New non-destructive primitive `insertWorkflowOntoCanvas` in
`web/sidebar/canvas_io.js`. Pre-flights every referenced node type
against `LiteGraph.registered_node_types` and aborts cleanly with a
toast naming the missing types — a partial insert with stub nodes
is worse than no insert. Then deep-clones the saved graph, calls
`node.configure(...)` per node with `node.id = -1` so
`app.graph.add()` allocates fresh ids that can never collide with
the live canvas, and finally walks the saved `links[]` to
recreate internal connections via `originNode.connect(...)` (which
auto-allocates fresh link ids — no manual link remap needed). Bbox
placement reuses the existing CSS-pixel correction so the cluster
lands at the visible viewport center on HiDPI displays.
2. Right-click on any workflow row now offers `Insert into canvas`
alongside the existing `Load` — Load remains available for every
row regardless of tag, so a module can still be loaded as a full
session if the user wants.
3. Convention-driven module classification in
`web/sidebar/constants.js` (`MODULE_TAG = module`). Picked a
tag instead of a new `isModule` schema field so existing saved
entries can be promoted to modules with one right-click → Tags add,
no migration needed, and the existing Tags section groups them for
free. Tree rendering looks up the tag at row-render time
(`isModuleWorkflow` helper) and switches both the leaf icon
(green `pi pi-plus-circle`) and the left-click handler (Insert
instead of Load). Active rows in the Workflows section AND every
row under the Tags section honor the flip; archived rows stay on
Load (they're old versions, `review` not `splice`).
4. `showSaveWorkflowModal` gains a `Save as module` checkbox. The
selection-save toolbar button passes `defaultModule: true` (the
typical `module` candidate is a small cluster the user just
selected); the whole-canvas save passes `defaultModule: false`.
The tag is added in the SAME `persistMutation` as the entry write
(folded into the `mutate` callback in `saveAndToast`), so a
commit failure rolls back BOTH the save and the tag together — no
`module`-but-untagged ghosts.
Docs: new `Modules` section in
`docs/maintainers/workflows-sidebar.md` covering the convention, the
checkbox flow, per-surface behavior, and how to promote an existing
saved workflow to a module without re-saving.
Co-authored-by: Cursor <cursoragent@cursor.com>