Panel agent operations

On-demand procedures for the ComfyUI sidebar panel agent that are too long to sit in the system prompt.

How to install

How to install

  1. Setup differs for this server — follow the Installation part of the README below.
  2. Claude Code: claude mcp add <name> -- <command>.
  3. Claude Desktop / Cursor: add it under mcpServers in the MCP config file.
Claude Code — installs the whole folder, not just SKILL.md
npx degit artokun/comfyui-mcp/plugin/skills/panel-operations#main ~/.claude/skills/panel-operations

For one project only, change the path to .claude/skills/panel-operations.

This one runs on your machine and can reach your files. Read the README below before you connect it.

Not working?
  • Check which app you pasted it into — the steps above name the right one.
  • Some skills need the paid tier of Claude or ChatGPT.
Step-by-step guide with screenshots · Ask in the forum

Paste into Claude, ChatGPT or Cursor.

Show the full text390 lines
panel-operations/SKILL.md390 lines23.0 KBpushed 22d agoRawView on GitHub

Panel agent operations

These are the procedures the panel system prompt points at rather than carries. Each tool named here also has its own full MCP description — that description is the authority on parameters and edge cases. This file is the procedure: the order of calls, and the traps that only show up when you string them together.

Jump to the section you need:

Subgraphs

Refactor a big graph into toggleable units. Do not reconstruct group membership by hand. panel_query_graph reports every group with its member node_ids on each result's groups — groups are geometric and do not own nodes, so trust that list, not coordinates. To make a region readable and switchable as a UNIT (e.g. a "REPLACEMENT MODE" group), call panel_subgraph_group(group:<title or id>): it wraps that group's nodes into one subgraph node in a single step. Then toggle the whole region with panel_set_node_mode(<subgraph node id>, 'bypass' to turn it OFF / 'active' to turn it ON). To compare variants, queue it twice — panel_run with the subgraph active, then bypass and panel_run again. For an arbitrary node set that is not a group, use panel_create_subgraph with explicit node_ids.

Reading and editing inside one. Call panel_enter_subgraph(node_id) first — then panel_query_graph / panel_graph_outline and the panel_* edit tools operate on the subgraph's inner nodes — and panel_exit_subgraph when you are done.

Exposing interior nodes to the boundary. To wire an interior node to the subgraph's boundary from INSIDE it, do NOT panel_connect to a guessed rail node id — that is the rail and you will get it wrong. Use:

  • panel_expose_subgraph_output(from_node_id, from_output) to expose an interior OUTPUT on the output rail, so the parent graph can wire the subgraph node's new output.
  • panel_expose_subgraph_input(to_node_id, to_input) to expose an interior INPUT on the input rail.

Read panel_query_graph's rails field (present when viewing a subgraph) to see the current boundary slots — what is already exposed and what still needs it.

Unexposing a boundary slot. panel_unexpose_subgraph_input / _output remove a named rail slot. Host SubgraphNode slots are positional: removing a slot that is not last shifts every later host link. panel_query_graph and panel_graph_outline will still show those later host links as connected (same positional lens); panel_run can then fail with Required input is missing (#2437). The unexpose reply only warns when a later slot remains and the panel did not already reindex (host_links_reindexed); removing the last slot, or a panel ≥0.15.120 that reports reindexed, is not that hazard. Do not trust that connectedness. Repair: panel_exit_subgraph, then disconnect and reconnect each remaining later host link by NAME (not index). Reconnecting by name re-resolves the index. Then re-enter if you still need the interior. Do not invent a reindex via panel_disconnect on a guessed index — a SubgraphNode disconnect can cascade into deleting unrelated nodes.

Dissolving one. panel_unpack_subgraph(node_id) inlines the inner nodes back into the parent graph and rewires external links, removing the wrapper — the inverse of panel_create_subgraph. All of these are undoable with Ctrl+Z.

Merging and composing workflows

To bring nodes from ONE workflow into ANOTHER (combine two graphs, copy a section across tabs, reuse part of a saved workflow), use copy/paste:

  1. panel_open_workflow — the source.
  2. panel_select_nodes — the section you want, or select all the ids from panel_query_graph {fields:'ids'}.
  3. panel_copy_nodes.
  4. panel_open_workflow or panel_new_workflow — the destination.
  5. panel_paste_nodes — returns the new node ids.
  6. Wire and tidy them, applying the workflow-layout skill so the merged result is clean with no overlaps.

The clipboard SURVIVES the workflow switch, so the copied nodes carry across tabs. Use connect_inputs only when you want the pasted nodes to auto-reconnect to matching existing nodes; the default (false) drops a clean disconnected copy you wire yourself.

Reusing subgraphs (blueprint library)

When the user builds a useful subgraph and wants to reuse it — now or in other workflows — SAVE it: panel_create_subgraph to group the nodes (if not already a subgraph), then panel_save_subgraph(node_id, name) publishes it to their library programmatically (no dialog). To drop a saved one into ANY workflow later, list them with panel_list_subgraphs and add with panel_add_subgraph(name).

This is the durable way to reuse a building block across projects — distinct from copy/paste, which is a one-off merge of the current clipboard.

Targeting a specific workflow

By default your panel_* graph edits follow whichever workflow tab the user is currently viewing. The panel can only read or edit the workflow currently IN VIEW, so to work on a specific open workflow, make it the active canvas first with panel_open_workflow, then call panel_set_workflow_target(mode:"pinned", path:<from panel_list_workflows>) to bind your edits to it. panel_get_workflow_target shows the current binding.

Pinning to a background (open but not active) workflow is REJECTED at pin time — it cannot route edits to a tab that is not in view. A pin does NOT switch what the user sees; it binds your edits to that workflow so that if the user later switches away, your next graph call fails loudly instead of silently editing the wrong graph. Set mode:"current" to follow the user's active tab again.

Tabs are managed with panel_list_workflows / panel_open_workflow / panel_rename_workflow / panel_close_workflow. To label, move, resize, recolor, collapse, or pin a node for presentation, use panel_edit_node.

Opening a staged or downloaded workflow

When you have saved or downloaded a workflow .json into the user's ComfyUI workflows folder (e.g. an example you fetched), open it with panel_open_workflow(path:<name-or-path>) — it REFRESHES the frontend's cached workflow list before searching, so a just-staged file is found and opened natively in its own tab.

For a workflow .json that lives OUTSIDE the workflows folder (any absolute path on the ComfyUI machine, or a downloaded example you did not move into workflows/), load it directly onto the live canvas with panel_load_workflow(path:<file>) — the orchestrator reads and parses the JSON server-side and drops it on the canvas in one shot, so even a large (100KB+) workflow never has to shuttle through the chat. Prefer panel_load_workflow(path:<file>) over pasting a big workflow JSON inline as the graph argument.

Untangling a Get/Set-bus or toggle-heavy graph

Expert and community graphs are often thick with VIRTUAL WIRING — GetNode/SetNode buses and Reroutes that hide the real connections — and rgthree "Fast Groups Bypasser/Muter" TOGGLED PIPELINES (one graph holding several pipelines, only one active at a time). Do NOT hand-trace GetNode to SetNode links or guess which branches are live.

  • To get the REAL wiring: panel_strip_workflow(path:<file> | pack:<name> | graph:<json>), or with no argument to read the LIVE canvas. It resolves Get/Set buses, Reroutes, subgraph definitions, and bypassed/muted nodes into REAL connections and returns the flat, runnable graph (read server-side, never shuttled through chat).
  • If the file is a MULTI-PIPELINE monolith and you want only ONE pipeline, FIRST panel_slice_workflow(path:<file>, groups:[<group-title substrings>]) to carve that pipeline into a standalone activated graph — it seeds from the output nodes in those groups, takes their backward closure through links and Set/Get buses, and un-bypasses the kept nodes — THEN panel_strip_workflow to flatten the buses.

Reach for panel_strip_workflow whenever a graph is too tangled to read directly or you need to UNDERSTAND or REBUILD its actual wiring; reach for panel_slice_workflow when an ULTRA-style monolith bundles several toggled pipelines and you want just one. The same two exist as get_workflow (action:"strip") and get_workflow (action:"slice") for non-panel sessions.

Authoring rgthree Fast Groups toggles

The counterpart to reading them, above. Fast Groups Bypasser/Muter are FRONTEND-ONLY — registered by the pack's JS and absent from /object_info BY DESIGN, so their absence there is NOT evidence they are unavailable. panel_add_node adds them: it exempts a small allowlist of genuinely frontend-only types covering the Fast (Groups) Bypasser/Muter, Label, Reroute and Node Collector — but NOT Bookmark, the Mute/Bypass Relay/Repeater, Fast Actions Button or Random Unmuter, which it refuses fail-closed.

Procedure and traps:

  • They are configured with panel_set_property, NOT panel_set_widgetmatchTitle, matchColors, sort and toggleRestriction are node PROPERTIES, and panel_set_widget refuses them.
  • They take no wiring and enumerate GROUPS by title, so create and NAME the groups FIRST, and ALWAYS set matchTitle or the node lists every group in the workflow.
  • Set matchTitle immediately after adding the node, then re-read the node. Fast Groups do NOT implement onPropertyChanged, so the first write stores the filter but may leave leftover Enable rows or widgets:{} (unbuilt, not "no matches"). If the list is wrong, set matchTitle AGAIN — do NOT delete and re-add the node.
  • Group membership is GEOMETRIC (any node whose centre lands in the box). When panel_create_group returns extra_node_ids / missing_node_ids and a warning, FIX IT before toggling, or a toggle disables part of the wrong stage.

Load the rgthree skill (list_packs (action:"skill_read", name:"rgthree")) before configuring these.

LoRA Manager autocomplete nodes

panel_add_node cannot add "Lora Loader (LoraManager)", "Lora Stacker (LoraManager)", or other LoRA Manager nodes whose required input is AUTOCOMPLETE_TEXT_LORAS / AUTOCOMPLETE_TEXT_PROMPT — the add waits 5s and refuses even when the pack and its UI are healthy. That is NOT a missing extension: reloading, panel_refresh_nodes, and retrying will keep failing.

Use "LoRA Text Loader (LoraManager)" instead (lora_syntax is a STRING socket you can drive) or the core LoraLoader. Load the lora-manager skill (list_packs (action:"skill_read", name:"lora-manager")) before authoring these.

Recommending CivitAI models

SHOW, don't just tell. When the user asks about — or you are recommending — specific CivitAI resources (a "good relight LoRA?", "which Flux checkpoint?", "find me an anime style"), LEAN TOWARD opening the docked CivitAI browser and highlighting your picks rather than answering with only a text table:

  1. panel_open_civitai — docked, with a matched query/tab/filters.
  2. panel_civitai_search — refine.
  3. panel_civitai_results — read the metadata and URLs.
  4. panel_civitai_highlight — the one(s) you recommend, with a BRIEF text summary of why each fits.

This docks beside the chat so both stay visible, and lets the user SEE the actual cards. You read metadata and URLs only, not the images. It is a nudge, not a mandate — a quick factual answer, or a resource the user already named, is fine as text; reach for the browser when they are choosing between options or exploring.

Downloading model weights

Use download_model (action:"download"), or action:"download_civitai" for CivitAI — NOT a raw shell download. It streams the file into the correct ComfyUI models/ subfolder AND surfaces live progress in the panel's download tray so the user can watch it. Pass target_subfolder to land the file exactly where it belongs (e.g. loras, checkpoints, vae, text_encoders, or a nested path like loras/<subdir>).

Do NOT shell out to curl/wget/aria2 for model files — a raw shell download has no progress in the panel and can drop the file in the wrong place. Reserve the shell for things download_model cannot do.

Hardware and runtime stats

For GPU / VRAM / CPU / RAM, CUDA/torch/python versions, and ComfyUI runtime stats, call get_system_stats (raw /system_stats) or install_comfyui (action:"environment") (a summarized snapshot). Both read the CONNECTED ComfyUI's /system_stats and work for LOCAL and REMOTE targets alike.

Do NOT shell out (nvidia-smi, PowerShell, wmic, python) for hardware info: the managed shell is sandboxed and read-only, rejects multi-line scripts, and only ever reaches the orchestrator host — not a remote ComfyUI. The startup ENVIRONMENT line already summarizes the machine; when you need current or more detail, these two tools are the source of truth.

Prompt Director awareness

When the graph contains PromptDirector, PromptDirectorAuto, PromptDirectorContext, PromptProducer, or PromptDirectorResultCritic nodes, call panel_audit_prompt_director BEFORE declaring that the prompt/model/LoRA setup is correct, or diagnosing a failed edit.

The audit correlates live wiring and loader widgets with the nodes' resolved Model Explorer metadata, edit plan, LoRA compatibility and strengths, the exact final prompt, warnings, and the critic verdict. Surface concise, useful observations proactively — including when the configuration is coherent. Its recommendations are READ-ONLY proposals: ask before applying panel_set_widget / panel_connect changes unless the user already explicitly asked you to fix the workflow.

Crash recovery for a broken custom node

If your turn begins with a "⚠️ ComfyUI crashed …" note — it names the fatal log block and the most likely culprit custom node plus file:line — or a run dies with a node-level error you can pin to one pack, do NOT just re-run the same graph. ESCALATE to actually fix that node, narrating each step to the user as you go:

  1. UPDATE it to the latest code. Call panel_update_node with the culprit's id, or the comfyui MCP install_custom_node with action:"update" / action:"fix". Try version nightly to grab a just-landed upstream fix. Poll panel_node_queue_status, then panel_restart_comfyui — you resume and RETRY the action to see if the crash is gone.
  2. If updating does not fix it, reach into the source. Go to COMFYUI_PATH/custom_nodes/<NodeDir> with your shell. If it is a git repo (a .git dir), run git fetch && git pull, or check out the nightly branch, to force the latest; reinstall its requirements if needed; then restart and retry.
  3. If there is no git or it is still broken, patch the source. Attempt a TARGETED patch of the crashing file:line, then VERIFY the fix actually resolves the crash — restart and retry the same action, confirming it no longer faults.
  4. Offer it upstream. Once verified, OFFER to suggest the fix to the repo owner (open an issue or PR describing the crash and your patch). Describe it and ask the user first; do NOT auto-file anything against a third party.

This combines cleanly with the normal install → restart → continue flow: a fresh install that crashes on first use is the same loop — update or patch the just-installed node, do not abandon it.

Debugging a wrong render with run-to-node

For a render that COMPLETES but comes out WRONG — artifacts, wrong subject, pose, composition or colour, blur, a ControlNet/IPAdapter/mask/LoRA not taking, a refiner or upscale stage degrading it. (For runs that FAIL with an error, OOM, or a missing node, use the troubleshooting skill instead.)

Do NOT just re-roll the whole graph. LOCALIZE the fault — render only up to one stage and LOOK at what that stage produces:

  • panel_run takes to_node_id to run ONE output branch (ComfyUI partial execution). Only that output node plus everything upstream of it renders; the rest is skipped, so it is fast and cheap, and the result is delivered to you automatically like any run.
  • to_node_id MUST be an OUTPUT node (is_output:true in panel_query_graph detail rows).
  • To inspect a point that is NOT an output — a latent, a preprocessor/depth/pose map, a mask, an intermediate image — TAP it: add a PreviewImage on an IMAGE wire, or VAEDecodePreviewImage on a LATENT, or MaskToImagePreviewImage on a MASK. Then panel_run(to_node_id=that preview), read the delivered image, and panel_remove_node the tap when done.
  • Bisect upstream to downstream until you find the FIRST stage whose output is bad — that node, or its inputs and widgets, is what to fix. Run-to-node there again to confirm before a full run.

For the full method (probe recipes, symptom-to-probe map) read the debug-render skill via list_packs (action:"skill_read").

Multi-stage pipelines on one canvas

For example Krea2 image → LTX video → WAN extend, all built on one canvas.

Chain a stage's output into the next stage's loader. When the next stage's loader (LoadImage / VHS_LoadVideo / LoadAudio) needs the previous stage's OUTPUT, call upload_image (action:"stage") with the output's { filename, subfolder?, type? } and drop the returned input filename into the loader's image/video/audio widget. For a file already on disk, use upload_image (action:"image") / (action:"video") / (action:"audio") instead.

NEVER copy the output file into, or guess, a filesystem input/ path: ComfyUI's input AND output directories may be CUSTOM (launched with --input-directory / --output-directory), so a guessed path makes LoadImage reject the file ("Invalid image file") and wastes the render. upload_image (action:"stage") goes through the server API (/view then /upload/image), which resolves the real directories correctly every time.

Verify a video render via the filesystem, not /history. VHS_VideoCombine and similar video nodes write the .mp4 but frequently do NOT register an output in ComfyUI's /history — the prompt shows done with no output and no error. So do NOT conclude a clip "silently dropped" from get_history or queue (action:"status"). Confirm it with get_image (action:"list_outputs"), which lists videos each tagged kind:"video", by filename/prefix plus a fresh mtime — then chain it forward with upload_image (action:"stage").

Bypass completed stages before queuing the next one. Once a stage has RUN and you have captured/staged its output, BYPASS that stage's nodes with panel_set_node_mode(mode:"bypass") BEFORE you queue the next stage — so panel_run does not re-execute (and make the user pay for and wait on) work that is already done. Re-running the whole graph because an earlier stage was left active is a real, costly failure mode: explicitly bypass each finished stage and keep only the ACTIVE stage live.

Connecting MCP servers

panel_list_mcp lists the MCP servers in the user's Claude config, panel_add_mcp writes a new one there, and panel_remove_mcp removes one.

Only the Claude backend is handed those servers. Every other backend (codex, gemini, grok, antigravity, qwen, the ollama family) is spawned with exactly two MCP servers — the headless comfyui one and the live-canvas panel one — so on those, the user's Claude config is their configuration and not your toolset. panel_reload does not change that; switching the panel to the Claude backend is what would.

So panel_list_mcp answers PER SERVER with declared_to_this_spawn, and that field is what you read before saying a capability is connected. Two things to know about it:

  • A false on a non-Claude backend is settled — we handed you nothing. (Your own CLI config may separately provide a server of the same name; that one is not this one.)
  • A true means we handed it to this session at spawn. It is not proof you have the tools: a session that RESUMED after a restart keeps the MCP set recorded with it rather than the one we just read, and a declared server can still fail to start. The only proof is calling one of its tools and having it work.

panel_add_mcp and panel_remove_mcp are still worth offering on any backend — they edit the user's real Claude config, so the change reaches their own claude sessions and this panel's Claude backend. Say that is what you are doing, rather than that you are gaining the capability.

For example, if a task needs CivitAI model search and it is not connected, offer to add the official CivitAI MCP (transport http, url https://mcp.civitai.com/mcp). ALWAYS ask the user before connecting a remote MCP — it is an external service connection. On the Claude backend, panel_reload then loads it into this session (it restarts you and resumes automatically).

After panel frontend or comfyui-tool code changes you can also call panel_reload to pick them up without a ComfyUI restart. But changes to the orchestrator process itself — the panel_* tools and the services they use — only take effect when the user restarts that process, so never claim such a change is live after a panel_reload.

Sources

  • Official: the panel and comfyui MCP tool descriptions in comfyui-mcp (this repo) — each tool named above is the authority on its own parameters.
  • Empirical: the panel agent system preamble these procedures were moved out of, plus the failure modes they were written for (issues #1398, #1551, #1708, #2234, #2437, #2491).
1---
2name: panel-operations
3description: On-demand procedures for the ComfyUI sidebar panel agent that are too long to sit in the system prompt. Read it when a task lands in one of these areas. subgraph boundary rails and blueprint reuse, merging or composing workflows across tabs, pinning your edits to one workflow, opening staged or downloaded workflow files, untangling Get/Set-bus and rgthree toggle-heavy graphs, authoring rgthree Fast Groups nodes, the LoRA Manager autocomplete-node limitation, the CivitAI browser flow, downloading model weights, reading hardware and runtime stats, Prompt Director audits, custom-node crash recovery, run-to-node render debugging, and multi-stage pipeline chaining. Each section is a lookup, not background reading. Reach for the one you need instead of guessing, and follow the tool's own description for parameter detail.
4---
5 
6# Panel agent operations
7 
8These are the procedures the panel system prompt points at rather than carries.
9Each tool named here also has its own full MCP description — that description is the
10authority on parameters and edge cases. This file is the *procedure*: the order of
11calls, and the traps that only show up when you string them together.
12 
13Jump to the section you need:
14 
15- [Subgraphs](#subgraphs)
16- [Merging and composing workflows](#merging-and-composing-workflows)
17- [Reusing subgraphs (blueprint library)](#reusing-subgraphs-blueprint-library)
18- [Targeting a specific workflow](#targeting-a-specific-workflow)
19- [Opening a staged or downloaded workflow](#opening-a-staged-or-downloaded-workflow)
20- [Untangling a Get/Set-bus or toggle-heavy graph](#untangling-a-getset-bus-or-toggle-heavy-graph)
21- [Authoring rgthree Fast Groups toggles](#authoring-rgthree-fast-groups-toggles)
22- [LoRA Manager autocomplete nodes](#lora-manager-autocomplete-nodes)
23- [Recommending CivitAI models](#recommending-civitai-models)
24- [Downloading model weights](#downloading-model-weights)
25- [Hardware and runtime stats](#hardware-and-runtime-stats)
26- [Prompt Director awareness](#prompt-director-awareness)
27- [Crash recovery for a broken custom node](#crash-recovery-for-a-broken-custom-node)
28- [Debugging a wrong render with run-to-node](#debugging-a-wrong-render-with-run-to-node)
29- [Multi-stage pipelines on one canvas](#multi-stage-pipelines-on-one-canvas)
30- [Connecting MCP servers](#connecting-mcp-servers)
31 
32## Subgraphs
33 
34**Refactor a big graph into toggleable units.** Do not reconstruct group membership by
35hand. `panel_query_graph` reports every group with its member `node_ids` on each
36result's `groups` — groups are geometric and do not own nodes, so trust that list, not
37coordinates. To make a region readable and switchable as a UNIT (e.g. a "REPLACEMENT
38MODE" group), call `panel_subgraph_group(group:<title or id>)`: it wraps that group's
39nodes into one subgraph node in a single step. Then toggle the whole region with
40`panel_set_node_mode(<subgraph node id>, 'bypass'` to turn it OFF / `'active'` to turn
41it ON). To compare variants, queue it twice — `panel_run` with the subgraph active,
42then bypass and `panel_run` again. For an arbitrary node set that is not a group, use
43`panel_create_subgraph` with explicit `node_ids`.
44 
45**Reading and editing inside one.** Call `panel_enter_subgraph(node_id)` first — then
46`panel_query_graph` / `panel_graph_outline` and the `panel_*` edit tools operate on the
47subgraph's inner nodes — and `panel_exit_subgraph` when you are done.
48 
49**Exposing interior nodes to the boundary.** To wire an interior node to the subgraph's
50boundary from INSIDE it, do NOT `panel_connect` to a guessed rail node id — that is the
51rail and you will get it wrong. Use:
52 
53- `panel_expose_subgraph_output(from_node_id, from_output)` to expose an interior OUTPUT
54 on the output rail, so the parent graph can wire the subgraph node's new output.
55- `panel_expose_subgraph_input(to_node_id, to_input)` to expose an interior INPUT on the
56 input rail.
57 
58Read `panel_query_graph`'s `rails` field (present when viewing a subgraph) to see the
59current boundary slots — what is already exposed and what still needs it.
60 
61**Unexposing a boundary slot.** `panel_unexpose_subgraph_input` / `_output` remove a
62named rail slot. Host SubgraphNode slots are positional: removing a slot that is not
63last shifts every later host link. `panel_query_graph` and `panel_graph_outline` will
64still show those later host links as connected (same positional lens); `panel_run` can
65then fail with `Required input is missing` (#2437). The unexpose reply only warns
66when a later slot remains *and* the panel did not already reindex (`host_links_reindexed`);
67removing the last slot, or a panel ≥0.15.120 that reports reindexed, is not that hazard.
68Do not trust that connectedness.
69Repair: `panel_exit_subgraph`, then disconnect and reconnect each remaining later host
70link **by NAME** (not index). Reconnecting by name re-resolves the index. Then re-enter
71if you still need the interior. Do not invent a reindex via `panel_disconnect` on a
72guessed index — a SubgraphNode disconnect can cascade into deleting unrelated nodes.
73 
74**Dissolving one.** `panel_unpack_subgraph(node_id)` inlines the inner nodes back into
75the parent graph and rewires external links, removing the wrapper — the inverse of
76`panel_create_subgraph`. All of these are undoable with Ctrl+Z.
77 
78## Merging and composing workflows
79 
80To bring nodes from ONE workflow into ANOTHER (combine two graphs, copy a section
81across tabs, reuse part of a saved workflow), use copy/paste:
82 
831. `panel_open_workflow` — the source.
842. `panel_select_nodes` — the section you want, or select all the ids from
85 `panel_query_graph {fields:'ids'}`.
863. `panel_copy_nodes`.
874. `panel_open_workflow` or `panel_new_workflow` — the destination.
885. `panel_paste_nodes` — returns the new node ids.
896. Wire and tidy them, applying the `workflow-layout` skill so the merged result is
90 clean with no overlaps.
91 
92The clipboard SURVIVES the workflow switch, so the copied nodes carry across tabs. Use
93`connect_inputs` only when you want the pasted nodes to auto-reconnect to matching
94existing nodes; the default (false) drops a clean disconnected copy you wire yourself.
95 
96## Reusing subgraphs (blueprint library)
97 
98When the user builds a useful subgraph and wants to reuse it — now or in other
99workflows — SAVE it: `panel_create_subgraph` to group the nodes (if not already a
100subgraph), then `panel_save_subgraph(node_id, name)` publishes it to their library
101programmatically (no dialog). To drop a saved one into ANY workflow later, list them
102with `panel_list_subgraphs` and add with `panel_add_subgraph(name)`.
103 
104This is the durable way to reuse a building block across projects — distinct from
105copy/paste, which is a one-off merge of the current clipboard.
106 
107## Targeting a specific workflow
108 
109By default your `panel_*` graph edits follow whichever workflow tab the user is
110currently viewing. The panel can only read or edit the workflow currently IN VIEW, so
111to work on a specific open workflow, make it the active canvas first with
112`panel_open_workflow`, then call
113`panel_set_workflow_target(mode:"pinned", path:<from panel_list_workflows>)` to bind
114your edits to it. `panel_get_workflow_target` shows the current binding.
115 
116Pinning to a background (open but not active) workflow is REJECTED at pin time — it
117cannot route edits to a tab that is not in view. A pin does NOT switch what the user
118sees; it binds your edits to that workflow so that if the user later switches away,
119your next graph call fails loudly instead of silently editing the wrong graph. Set
120`mode:"current"` to follow the user's active tab again.
121 
122Tabs are managed with `panel_list_workflows` / `panel_open_workflow` /
123`panel_rename_workflow` / `panel_close_workflow`. To label, move, resize, recolor,
124collapse, or pin a node for presentation, use `panel_edit_node`.
125 
126## Opening a staged or downloaded workflow
127 
128When you have saved or downloaded a workflow `.json` into the user's ComfyUI workflows
129folder (e.g. an example you fetched), open it with
130`panel_open_workflow(path:<name-or-path>)` — it REFRESHES the frontend's cached
131workflow list before searching, so a just-staged file is found and opened natively in
132its own tab.
133 
134For a workflow `.json` that lives OUTSIDE the workflows folder (any absolute path on
135the ComfyUI machine, or a downloaded example you did not move into `workflows/`), load
136it directly onto the live canvas with `panel_load_workflow(path:<file>)` — the
137orchestrator reads and parses the JSON server-side and drops it on the canvas in one
138shot, so even a large (100KB+) workflow never has to shuttle through the chat. Prefer
139`panel_load_workflow(path:<file>)` over pasting a big workflow JSON inline as the
140`graph` argument.
141 
142## Untangling a Get/Set-bus or toggle-heavy graph
143 
144Expert and community graphs are often thick with VIRTUAL WIRING — GetNode/SetNode
145buses and Reroutes that hide the real connections — and rgthree "Fast Groups
146Bypasser/Muter" TOGGLED PIPELINES (one graph holding several pipelines, only one active
147at a time). Do NOT hand-trace GetNode to SetNode links or guess which branches are
148live.
149 
150- To get the REAL wiring: `panel_strip_workflow(path:<file> | pack:<name> |
151 graph:<json>)`, or with no argument to read the LIVE canvas. It resolves Get/Set
152 buses, Reroutes, subgraph definitions, and bypassed/muted nodes into REAL connections
153 and returns the flat, runnable graph (read server-side, never shuttled through chat).
154- If the file is a MULTI-PIPELINE monolith and you want only ONE pipeline, FIRST
155 `panel_slice_workflow(path:<file>, groups:[<group-title substrings>])` to carve that
156 pipeline into a standalone activated graph — it seeds from the output nodes in those
157 groups, takes their backward closure through links and Set/Get buses, and un-bypasses
158 the kept nodes — THEN `panel_strip_workflow` to flatten the buses.
159 
160Reach for `panel_strip_workflow` whenever a graph is too tangled to read directly or
161you need to UNDERSTAND or REBUILD its actual wiring; reach for `panel_slice_workflow`
162when an ULTRA-style monolith bundles several toggled pipelines and you want just one.
163The same two exist as `get_workflow (action:"strip")` and `get_workflow
164(action:"slice")` for non-panel sessions.
165 
166## Authoring rgthree Fast Groups toggles
167 
168The counterpart to reading them, above. Fast Groups Bypasser/Muter are FRONTEND-ONLY —
169registered by the pack's JS and absent from `/object_info` BY DESIGN, so their absence
170there is NOT evidence they are unavailable. `panel_add_node` adds them: it exempts a
171small allowlist of genuinely frontend-only types covering the Fast (Groups)
172Bypasser/Muter, Label, Reroute and Node Collector — but NOT Bookmark, the Mute/Bypass
173Relay/Repeater, Fast Actions Button or Random Unmuter, which it refuses fail-closed.
174 
175Procedure and traps:
176 
177- They are configured with `panel_set_property`, NOT `panel_set_widget``matchTitle`,
178 `matchColors`, `sort` and `toggleRestriction` are node PROPERTIES, and
179 `panel_set_widget` refuses them.
180- They take no wiring and enumerate GROUPS by title, so create and NAME the groups
181 FIRST, and ALWAYS set `matchTitle` or the node lists every group in the workflow.
182- Set `matchTitle` immediately after adding the node, then re-read the node. Fast Groups
183 do NOT implement `onPropertyChanged`, so the first write stores the filter but may
184 leave leftover Enable rows or `widgets:{}` (unbuilt, not "no matches"). If the list is
185 wrong, set `matchTitle` AGAIN — do NOT delete and re-add the node.
186- Group membership is GEOMETRIC (any node whose centre lands in the box). When
187 `panel_create_group` returns `extra_node_ids` / `missing_node_ids` and a warning, FIX
188 IT before toggling, or a toggle disables part of the wrong stage.
189 
190Load the `rgthree` skill (`list_packs (action:"skill_read", name:"rgthree")`) before
191configuring these.
192 
193## LoRA Manager autocomplete nodes
194 
195`panel_add_node` cannot add "Lora Loader (LoraManager)", "Lora Stacker (LoraManager)",
196or other LoRA Manager nodes whose required input is `AUTOCOMPLETE_TEXT_LORAS` /
197`AUTOCOMPLETE_TEXT_PROMPT` — the add waits 5s and refuses even when the pack and its UI
198are healthy. That is NOT a missing extension: reloading, `panel_refresh_nodes`, and
199retrying will keep failing.
200 
201Use "LoRA Text Loader (LoraManager)" instead (`lora_syntax` is a STRING socket you can
202drive) or the core `LoraLoader`. Load the `lora-manager` skill (`list_packs
203(action:"skill_read", name:"lora-manager")`) before authoring these.
204 
205## Recommending CivitAI models
206 
207SHOW, don't just tell. When the user asks about — or you are recommending — specific
208CivitAI resources (a "good relight LoRA?", "which Flux checkpoint?", "find me an anime
209style"), LEAN TOWARD opening the docked CivitAI browser and highlighting your picks
210rather than answering with only a text table:
211 
2121. `panel_open_civitai` — docked, with a matched query/tab/filters.
2132. `panel_civitai_search` — refine.
2143. `panel_civitai_results` — read the metadata and URLs.
2154. `panel_civitai_highlight` — the one(s) you recommend, with a BRIEF text summary of
216 why each fits.
217 
218This docks beside the chat so both stay visible, and lets the user SEE the actual
219cards. You read metadata and URLs only, not the images. It is a nudge, not a mandate —
220a quick factual answer, or a resource the user already named, is fine as text; reach for
221the browser when they are choosing between options or exploring.
222 
223## Downloading model weights
224 
225Use `download_model (action:"download")`, or `action:"download_civitai"` for CivitAI —
226NOT a raw shell download. It streams the file into the correct ComfyUI `models/`
227subfolder AND surfaces live progress in the panel's download tray so the user can watch
228it. Pass `target_subfolder` to land the file exactly where it belongs (e.g. `loras`,
229`checkpoints`, `vae`, `text_encoders`, or a nested path like `loras/<subdir>`).
230 
231Do NOT shell out to curl/wget/aria2 for model files — a raw shell download has no
232progress in the panel and can drop the file in the wrong place. Reserve the shell for
233things `download_model` cannot do.
234 
235## Hardware and runtime stats
236 
237For GPU / VRAM / CPU / RAM, CUDA/torch/python versions, and ComfyUI runtime stats, call
238`get_system_stats` (raw `/system_stats`) or `install_comfyui (action:"environment")` (a
239summarized snapshot). Both read the CONNECTED ComfyUI's `/system_stats` and work for
240LOCAL and REMOTE targets alike.
241 
242Do NOT shell out (nvidia-smi, PowerShell, wmic, python) for hardware info: the managed
243shell is sandboxed and read-only, rejects multi-line scripts, and only ever reaches the
244orchestrator host — not a remote ComfyUI. The startup ENVIRONMENT line already
245summarizes the machine; when you need current or more detail, these two tools are the
246source of truth.
247 
248## Prompt Director awareness
249 
250When the graph contains `PromptDirector`, `PromptDirectorAuto`, `PromptDirectorContext`,
251`PromptProducer`, or `PromptDirectorResultCritic` nodes, call
252`panel_audit_prompt_director` BEFORE declaring that the prompt/model/LoRA setup is
253correct, or diagnosing a failed edit.
254 
255The audit correlates live wiring and loader widgets with the nodes' resolved Model
256Explorer metadata, edit plan, LoRA compatibility and strengths, the exact final prompt,
257warnings, and the critic verdict. Surface concise, useful observations proactively —
258including when the configuration is coherent. Its recommendations are READ-ONLY
259proposals: ask before applying `panel_set_widget` / `panel_connect` changes unless the
260user already explicitly asked you to fix the workflow.
261 
262## Crash recovery for a broken custom node
263 
264If your turn begins with a "⚠️ ComfyUI crashed …" note — it names the fatal log block
265and the most likely culprit custom node plus `file:line` — or a run dies with a
266node-level error you can pin to one pack, do NOT just re-run the same graph. ESCALATE
267to actually fix that node, narrating each step to the user as you go:
268 
2691. **UPDATE it to the latest code.** Call `panel_update_node` with the culprit's id, or
270 the comfyui MCP `install_custom_node` with `action:"update"` / `action:"fix"`. Try
271 version `nightly` to grab a just-landed upstream fix. Poll
272 `panel_node_queue_status`, then `panel_restart_comfyui` — you resume and RETRY the
273 action to see if the crash is gone.
2742. **If updating does not fix it, reach into the source.** Go to
275 `COMFYUI_PATH/custom_nodes/<NodeDir>` with your shell. If it is a git repo (a `.git`
276 dir), run `git fetch && git pull`, or check out the nightly branch, to force the
277 latest; reinstall its requirements if needed; then restart and retry.
2783. **If there is no git or it is still broken, patch the source.** Attempt a TARGETED
279 patch of the crashing `file:line`, then VERIFY the fix actually resolves the crash —
280 restart and retry the same action, confirming it no longer faults.
2814. **Offer it upstream.** Once verified, OFFER to suggest the fix to the repo owner
282 (open an issue or PR describing the crash and your patch). Describe it and ask the
283 user first; do NOT auto-file anything against a third party.
284 
285This combines cleanly with the normal install → restart → continue flow: a fresh
286install that crashes on first use is the same loop — update or patch the just-installed
287node, do not abandon it.
288 
289## Debugging a wrong render with run-to-node
290 
291For a render that COMPLETES but comes out WRONG — artifacts, wrong subject, pose,
292composition or colour, blur, a ControlNet/IPAdapter/mask/LoRA not taking, a refiner or
293upscale stage degrading it. (For runs that FAIL with an error, OOM, or a missing node,
294use the `troubleshooting` skill instead.)
295 
296Do NOT just re-roll the whole graph. LOCALIZE the fault — render only up to one stage
297and LOOK at what that stage produces:
298 
299- `panel_run` takes `to_node_id` to run ONE output branch (ComfyUI partial execution).
300 Only that output node plus everything upstream of it renders; the rest is skipped, so
301 it is fast and cheap, and the result is delivered to you automatically like any run.
302- `to_node_id` MUST be an OUTPUT node (`is_output:true` in `panel_query_graph` detail
303 rows).
304- To inspect a point that is NOT an output — a latent, a preprocessor/depth/pose map, a
305 mask, an intermediate image — TAP it: add a `PreviewImage` on an IMAGE wire, or
306 `VAEDecode``PreviewImage` on a LATENT, or `MaskToImage``PreviewImage` on a
307 MASK. Then `panel_run(to_node_id=that preview)`, read the delivered image, and
308 `panel_remove_node` the tap when done.
309- Bisect upstream to downstream until you find the FIRST stage whose output is bad —
310 that node, or its inputs and widgets, is what to fix. Run-to-node there again to
311 confirm before a full run.
312 
313For the full method (probe recipes, symptom-to-probe map) read the `debug-render` skill
314via `list_packs (action:"skill_read")`.
315 
316## Multi-stage pipelines on one canvas
317 
318For example Krea2 image → LTX video → WAN extend, all built on one canvas.
319 
320**Chain a stage's output into the next stage's loader.** When the next stage's loader
321(`LoadImage` / `VHS_LoadVideo` / `LoadAudio`) needs the previous stage's OUTPUT, call
322`upload_image (action:"stage")` with the output's `{ filename, subfolder?, type? }` and
323drop the returned input filename into the loader's image/video/audio widget. For a file
324already on disk, use `upload_image (action:"image")` / `(action:"video")` /
325`(action:"audio")` instead.
326 
327NEVER copy the output file into, or guess, a filesystem `input/` path: ComfyUI's input
328AND output directories may be CUSTOM (launched with `--input-directory` /
329`--output-directory`), so a guessed path makes `LoadImage` reject the file ("Invalid
330image file") and wastes the render. `upload_image (action:"stage")` goes through the
331server API (`/view` then `/upload/image`), which resolves the real directories
332correctly every time.
333 
334**Verify a video render via the filesystem, not /history.** `VHS_VideoCombine` and
335similar video nodes write the `.mp4` but frequently do NOT register an output in
336ComfyUI's `/history` — the prompt shows done with no output and no error. So do NOT
337conclude a clip "silently dropped" from `get_history` or `queue (action:"status")`.
338Confirm it with `get_image (action:"list_outputs")`, which lists videos each tagged
339`kind:"video"`, by filename/prefix plus a fresh mtime — then chain it forward with
340`upload_image (action:"stage")`.
341 
342**Bypass completed stages before queuing the next one.** Once a stage has RUN and you
343have captured/staged its output, BYPASS that stage's nodes with
344`panel_set_node_mode(mode:"bypass")` BEFORE you queue the next stage — so `panel_run`
345does not re-execute (and make the user pay for and wait on) work that is already done.
346Re-running the whole graph because an earlier stage was left active is a real, costly
347failure mode: explicitly bypass each finished stage and keep only the ACTIVE stage live.
348 
349## Connecting MCP servers
350 
351`panel_list_mcp` lists the MCP servers in the user's Claude config, `panel_add_mcp`
352writes a new one there, and `panel_remove_mcp` removes one.
353 
354**Only the Claude backend is handed those servers.** Every other backend
355(codex, gemini, grok, antigravity, qwen, the ollama family) is spawned with exactly two
356MCP servers — the headless `comfyui` one and the live-canvas `panel` one — so on those,
357the user's Claude config is their configuration and not your toolset. `panel_reload`
358does not change that; switching the panel to the Claude backend is what would.
359 
360So `panel_list_mcp` answers PER SERVER with `declared_to_this_spawn`, and that field is
361what you read before saying a capability is connected. Two things to know about it:
362 
363- A `false` on a non-Claude backend is settled — we handed you nothing. (Your own CLI
364 config may separately provide a server of the same name; that one is not this one.)
365- A `true` means we handed it to this session at spawn. It is **not** proof you have the
366 tools: a session that RESUMED after a restart keeps the MCP set recorded with it
367 rather than the one we just read, and a declared server can still fail to start. The
368 only proof is calling one of its tools and having it work.
369 
370`panel_add_mcp` and `panel_remove_mcp` are still worth offering on any backend — they
371edit the user's real Claude config, so the change reaches their own `claude` sessions
372and this panel's Claude backend. Say that is what you are doing, rather than that you
373are gaining the capability.
374 
375For example, if a task needs CivitAI model search and it is not connected, offer to add
376the official CivitAI MCP (transport `http`, url `https://mcp.civitai.com/mcp`). ALWAYS
377ask the user before connecting a remote MCP — it is an external service connection. On
378the Claude backend, `panel_reload` then loads it into this session (it restarts you and
379resumes automatically).
380 
381After panel frontend or comfyui-tool code changes you can also call `panel_reload` to
382pick them up without a ComfyUI restart. But changes to the orchestrator process itself
383— the `panel_*` tools and the services they use — only take effect when the user
384restarts that process, so never claim such a change is live after a `panel_reload`.
385 
386## Sources
387 
388- **Official:** the panel and comfyui MCP tool descriptions in comfyui-mcp (this repo) — each tool named above is the authority on its own parameters.
389- **Empirical:** the panel agent system preamble these procedures were moved out of, plus the failure modes they were written for (issues #1398, #1551, #1708, #2234, #2437, #2491).
390 

Discussion

Alternatives

Also in Language patterns