---
path: /isis/workflow-editor
surface: admin
domain: isis
auth: signed-in (admin)
source: apps/oshun/admin/src/app/isis/workflow-editor/page.tsx
status: drafted
last_walked: '—'
---

# Isis ops · Workflow editor

## Purpose

ComfyUI workflow-class editor (§24.3): typed node palette bound to the node
registry, a parameter inspector that validates the candidate graph against the
workflow class's guardrails, save-as-class flow, and a version-pin affordance
(semver bump). Bindings are injected — production wires the BFF + the
`@yemaya/comfyui-integration` node registry.

## Entry points

- Direct URL — `/isis/workflow-editor`
- External runbooks / deep links
- Not in canonical IA — no sidebar entry

## Layout regions

Page does NOT wrap in `AdminShell`. Server entry calls `loadEditorContext()`
from `./workflow-editor-loader` and renders
`<WorkflowEditorPanel approvedClass availableNodeTypes />`:

- **WorkflowEditorPanel**:
  - Initial state: `graphNodes` empty unless `initialParameters` provided;
    `parameters` and `nodeTypeAt` derived from `initialParameters`; `version`
    initialized to `approvedClass.semverVersion`
  - **Add node** action → appends `node-<n>` id, defaults its `nodeTypeAt` to
    `availableNodeTypes[0] ?? ''`
  - **Parameter inspector** — per node, editable params; values coerced numeric
    when parseable (`Number(v)` finite check)
  - **Validation outcome** —
    `checkGraphAgainstClass({ workflowClass, graphParameters, graphNodeTypes })`
    returns `ParameterCheckOutcome` consumed by the panel; status surfaces as
    the inspector's validation report
  - **Remove node** action → strips the node from `graphNodes`, `parameters`,
    `nodeTypeAt`
  - **Version pin** — `version` input bound to `approvedClass.semverVersion`

## States

- [ ] Anonymous → global middleware redirects
- [ ] `loadEditorContext` returns a valid `approvedClass` and
      `availableNodeTypes` → editor renders with empty graph (or
      `initialParameters` if seeded)
- [ ] No `availableNodeTypes` → "Add node" still works, but new nodes default to
      empty `nodeTypeAt`
- [ ] Graph validates → `outcome` reflects ok status (verify surface in full
      source)
- [ ] Graph violates class guardrails → `outcome` exposes violations; inspector
      surfaces them
- [ ] Version pin changed → state updated; persistence path not visible in
      inspected portion

## Interactions

- [ ] **Add node** (button)
  - Function: `addNode()` appends `node-<graphNodes.length + 1>`
- [ ] **Remove node** (per node)
  - Function: `removeNode(id)` strips from three state maps
- [ ] **Node type selector** (per node) — choice from `availableNodeTypes`
- [ ] **Parameter inputs** (per node, per param) — store as string; numeric
      coercion at validation time
- [ ] **Version pin input** — bound to `approvedClass.semverVersion`; semver
      bump

## Data & contracts

- **Reads**: `loadEditorContext()` returns
  `{ approvedClass: WorkflowClass, availableNodeTypes: readonly string[] }`
  (production wires BFF + node registry from `@yemaya/comfyui-integration`)
- **Writes**: in-component state only in the inspected portion; save-as-class
  likely posts to a downstream endpoint
- **Realtime**: _None._
- **Auth/role check**: only the global middleware

## Cross-references

- Shell: `shell/02-routing-layouts.md`
- Sibling Isis route: `isis-comfy-nodes.md` (the node registry browser this
  editor binds to)
- Library: `@isis/comfyui-factory` — `checkGraphAgainstClass`,
  `ParameterCheckOutcome`, `WorkflowClass`
- Component source:
  `apps/oshun/admin/src/app/isis/workflow-editor/WorkflowEditorPanel.tsx`
- Loader:
  `apps/oshun/admin/src/app/isis/workflow-editor/workflow-editor-loader.ts`

## Open questions / known gaps

- [ ] No session / scope check at the page level
- [ ] Save-as-class persistence path is not visible in the inspected portion;
      document the endpoint that consumes the saved workflow class
- [ ] Parameter coercion treats numeric-looking strings as numbers at validation
      time but stores them as strings; verify whether the BFF expects typed JSON
