Per-workflow agent targeting
Problem
Each ComfyUI browser tab connects to the orchestrator with atab_id, but ComfyUI can have multiple workflow tabs open inside that browser tab. Graph tools (graph_get_state, graph_add_node, …) default to whichever workflow the user is currently viewing. If the user switches workflow tabs while the agent is working, edits land on the wrong graph.
Solution
The orchestrator keeps a per-tab_id workflow target:
Active-canvas constraint (#556/#571)
The panel has no way to read or mutate a non-active workflow’s graph: every graph executor runs againstapp.canvas.graph, and the panel’s pinned-target guard (#349/#186) fails closed with a “workflow mismatch” error whenever an injected workflow_path is not the workflow currently in view. Background editing of a non-active tab is therefore not supported.
Consequently a pin is only honorable when its target is the active canvas. panel_set_workflow_target (and the panel-driven set_workflow_target event) validate at pin time via resolvePinTarget and:
- fail closed if the workflow isn’t open (#259),
- fail at pin time if it is open but not the active canvas (#556/#571) — never accept-then-defer,
- canonicalize an honorable pin to the workflow’s stable
key.
workflow_path then acts as a guard: if the user later switches away, the next graph command fails loudly instead of silently editing the wrong graph.
Orchestrator API
- MCP tools:
panel_get_workflow_target,panel_set_workflow_target - Bridge event (panel → orchestrator):
{ type: "set_workflow_target", tab_id, mode, path?, filename? } - Bridge push (orchestrator → panel):
{ type: "workflow_target", target } - Ack:
{ type: "ack", ok, kind: "workflow_target", target? }
Command injection
When pinned, the orchestrator addsworkflow_path to:
- All
graph_*commands workflow_save,workflow_save_as,workflow_rename,workflow_closewhenpathis omitted
workflow_list, workflow_new, workflow_open.
Panel implementation (comfyui-mcp-panel)
Graph executors run against the active canvas (app.canvas.graph); the panel cannot address a non-active workflow document. So each executor:
- Reads optional
workflow_pathon the incoming{ rid, cmd, … }frame. - Treats it as a guard: if
workflow_pathdoes not identify the active canvas, it fails closed with a retryable “workflow mismatch” error (#349/#186) — it never blindly mutates the active graph under a mismatched pin. - Otherwise applies the mutation on the active canvas.
Files
src/services/workflow-target-store.ts— store + injection helpersrc/orchestrator/panel-tools.ts— MCP tools +makePanelToolCtxinjectionsrc/orchestrator/index.ts— bridge handler + hello sync