Context is Everything logo

Workflow Editor POC Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Build a workflow editor inside Sasha Studio that makes Workflow the first-class concept, with a React Flow canvas, CodeMirror code view, three template models, and two working examples.

Architecture: Workflow .md files stored in workflows/ directory, parsed to AST (frontmatter + fenced blocks), rendered as React Flow graph. Server syncs files to a workflows DB table on startup. Executions use the existing unified executions table. The editor launches from a renamed "Workflows" tab (was "Tasks").

Tech Stack: React 18, React Flow, CodeMirror 6 (existing), Vitest, Express, better-sqlite3 (existing), Tailwind CSS (existing), Phosphor Icons (existing)

Design doc: docs/plans/2026-02-28-workflow-editor-design.md

Spec repo: https://github.com/context-is-everything/sasha-workflow


Task 1: Install React Flow dependency

Files:

  • Modify: claudecodeui/package.json

Step 1: Install reactflow

Run: cd claudecodeui && npm install @xyflow/react

Step 2: Verify install

Run: npm ls @xyflow/react
Expected: Shows installed version

Step 3: Verify build still works

Run: npx vite build
Expected: Build succeeds with no errors

Step 4: Commit

git add package.json package-lock.json
git commit -m "chore(deps): add @xyflow/react for workflow editor"

Task 2: Build the workflow file parser

The parser converts Agent Flow .md files into a typed AST. This is the foundation everything else depends on.

Files:

  • Create: claudecodeui/src/utils/workflowParser.js
  • Create: claudecodeui/src/utils/__tests__/workflowParser.test.js

Step 1: Write the failing tests

Test cases needed:

  • parseFrontmatter: extracts YAML frontmatter, handles missing frontmatter, parses nested objects (budgets, triggers)
  • parseFencedBlocks: extracts step/agent/bundle/runtime/observability blocks, returns empty arrays for missing sections
  • parseWorkflow: full parse, layer inference (0=no steps, 1=linear, 2=parallel/conditions, 3=runtime with waitpoints)
  • Round-trip: parse the example files from all-project-files/workflows/

Step 2: Run tests to verify they fail

Run: cd claudecodeui && npx vitest run src/utils/__tests__/workflowParser.test.js
Expected: All tests FAIL (module not found)

Step 3: Implement the parser

Key functions:

  • parseFrontmatter(md){ frontmatter: object, body: string } — regex extract --- delimited YAML, parse with js-yaml
  • parseFencedBlocks(body){ steps[], agents[], bundles[], runtime, observability } — regex for ```step, ```agent, etc., parse each with js-yaml
  • inferLayer(steps, blocks)0|1|2|3 — check for runtime waitpoints (3), parallel/conditions (2), any steps (1), none (0)
  • parseWorkflow(md) → full AST combining frontmatter + blocks + derived layer

Uses js-yaml for YAML parsing (check if already in dependencies, install if not).

Step 4: Run tests to verify they pass

Run: cd claudecodeui && npx vitest run src/utils/__tests__/workflowParser.test.js
Expected: All tests PASS

Step 5: Verify build

Run: cd claudecodeui && npx vite build
Expected: Build succeeds

Step 6: Commit

git add src/utils/workflowParser.js src/utils/__tests__/workflowParser.test.js
git commit -m "feat(workflow): add Agent Flow markdown parser with tests"

Task 3: Build the workflow serializer (AST to Markdown)

The serializer converts the AST back to a valid Agent Flow .md file. This powers the visual-to-code direction.

Files:

  • Create: claudecodeui/src/utils/workflowSerializer.js
  • Create: claudecodeui/src/utils/__tests__/workflowSerializer.test.js

Step 1: Write the failing tests

Test cases:

  • Round-trip: serialize then re-parse, verify AST matches
  • Includes agents/bundles/runtime/observability sections only when present
  • Omits empty optional sections
  • Frontmatter includes triggers, budgets, tools when set

Step 2: Implement the serializer

Key function:

  • serializeWorkflow(ast) → markdown string

Structure:

  1. Build frontmatter object (only non-empty fields)
  2. Dump as YAML between --- delimiters
  3. Add # Purpose heading with description
  4. Add ## Agents with ```agent blocks (if any)
  5. Add ## Steps with ```step blocks
  6. Add ## Bundles with ```bundle blocks (if any)
  7. Add ## Runtime with ```runtime block (if present)
  8. Add ## Observability with ```observability block (if present)

Step 3: Run tests, verify pass

Step 4: Commit

git add src/utils/workflowSerializer.js src/utils/__tests__/workflowSerializer.test.js
git commit -m "feat(workflow): add workflow serializer (AST to markdown)"

Task 4: Build the server-side workflow API

Files:

  • Create: claudecodeui/server/routes/workflows.js
  • Create: claudecodeui/server/database/workflowDb.js
  • Modify: claudecodeui/server/database/init.sql (add workflows table after line ~607)
  • Modify: claudecodeui/server/index.js (register route near line 2266, add sync on startup)

Step 1: Add workflows table to init.sql

CREATE TABLE IF NOT EXISTS workflows (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  file_path TEXT NOT NULL,
  description TEXT,
  kind TEXT,
  version TEXT,
  status TEXT DEFAULT 'draft',
  layer INTEGER DEFAULT 0,
  triggers_json TEXT,
  enabled INTEGER DEFAULT 1,
  last_synced_at TEXT,
  created_at TEXT DEFAULT (datetime('now')),
  updated_at TEXT DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_workflows_name ON workflows(name);
CREATE INDEX IF NOT EXISTS idx_workflows_enabled ON workflows(enabled);

Step 2: Create workflowDb.js

Functions: listWorkflows(), getWorkflow(name), upsertWorkflow({...}), deleteWorkflow(name)

Follow the pattern in schedulerDb.js:

  • formatWorkflow(row) converts DB row to camelCase
  • Prepared statements for each operation
  • upsertWorkflow uses INSERT ... ON CONFLICT(name) DO UPDATE

Step 3: Create workflows.js routes

Endpoints:

  • GET / — list all workflows
  • GET /:name — get workflow metadata + file content
  • PUT /:name — save workflow content + sync metadata to DB
  • DELETE /:name — delete workflow file + DB record
  • POST /sync — rescan workflows directory and sync to DB

The syncWorkflowsFromDisk() function scans workflows/ directory, parses frontmatter from each .md file, and upserts to DB.

Path to workflows directory: process.env.PROJECT_FILES_PATH || path.join(process.cwd(), 'all-project-files') + /workflows

Step 4: Register in server/index.js

  • Import: import workflowRoutes, { syncWorkflowsFromDisk } from './routes/workflows.js';
  • Mount: app.use('/api/workflows', workflowRoutes);
  • Startup sync: call syncWorkflowsFromDisk() after scheduler init

Step 5: Verify build

Run: cd claudecodeui && npx vite build

Step 6: Commit

git add server/routes/workflows.js server/database/workflowDb.js server/database/init.sql server/index.js
git commit -m "feat(workflow): add server-side workflow API and database"

Task 5: Create the two example workflow files

Files:

  • Create: claudecodeui/all-project-files/workflows/report-publisher-pipeline.md
  • Create: claudecodeui/all-project-files/workflows/transcript-to-report.md

Step 1: Copy examples from spec repo

mkdir -p claudecodeui/all-project-files/workflows
cp /Users/lindsay/Documents/work/sasha-workflow/examples/report-publisher-pipeline.md claudecodeui/all-project-files/workflows/
cp /Users/lindsay/Documents/work/sasha-workflow/examples/transcript-to-report.md claudecodeui/all-project-files/workflows/

Step 2: Commit

git add claudecodeui/all-project-files/workflows/
git commit -m "feat(workflow): add example workflow files (report-publisher, transcript-to-report)"

Task 6: Build the three workflow templates

Files:

  • Create: claudecodeui/src/utils/workflowTemplates.js

Step 1: Create templates module

Export TEMPLATES array with three entries:

  1. Simple Pipeline (id: 'simple'): validate_input → process → format_output. Layer 1. Low budgets.
  2. Agentic Workflow (id: 'agentic'): validate → specialist → QA gate → assemble. Layer 2. Two agents (specialist, critic). Medium budgets.
  3. Parallel Fan-out (id: 'parallel'): validate → parallel extract → confirmation gate → assemble. Layer 2. Three workers in a bundle with merge config. Higher budgets.

Each template has:

  • id, name, description, icon, layer
  • generate(workflowName) → full workflow AST with best-practice budgets, reason codes, and observability pre-configured

Export helper: generateFromTemplate(templateId, workflowName) → AST

Step 2: Commit

git add src/utils/workflowTemplates.js
git commit -m "feat(workflow): add three workflow template models (simple, agentic, parallel)"

Task 7: Build the Workflow Manager panel (list view)

Files:

  • Create: claudecodeui/src/components/WorkflowManager.jsx
  • Modify: claudecodeui/src/components/MainContent.jsx (swap tab)
  • Modify: claudecodeui/src/utils/api.js (add workflow API methods)

Step 1: Add workflow API methods to api.js

Add api.workflows object with: list(), get(name), save(name, content, metadata), delete(name), sync()

Step 2: Build WorkflowManager component

Follow SchedulesPanel.jsx pattern exactly for structure and styling. Key sections:

  • Header: "Workflows" title + "+ New Workflow" button
  • Workflow list: Cards showing name, description, layer badge (L0-L3 with color), trigger summary, last execution status, [Edit] [Run Now] buttons
  • Template picker modal: Shown when "+ New" clicked. Three cards (Simple, Agentic, Parallel) with name, description, icon. Click → prompt for workflow name → generate from template → save → open editor.
  • Legacy prompts section: Collapsed section at bottom showing existing scheduled prompts with "Convert to Workflow" badge (not functional in POC)
  • Search/filter: Debounced search across workflow names and descriptions

State management: useState for workflows list, loading, search filter, template picker visibility. Fetch on mount via api.workflows.list().

Step 3: Update MainContent.jsx

  • Import WorkflowManager
  • Add state: showWorkflowManager, editingWorkflow
  • Change schedules tab to workflows tab with TreeStructure icon and "Workflows" label
  • Wire tab click to setShowWorkflowManager(true)
  • Render <WorkflowManager isOpen={showWorkflowManager} onClose={...} onEdit={(name) => setEditingWorkflow(name)} />
  • Keep SchedulesPanel import and rendering (legacy prompts accessible)

Step 4: Verify build

Run: cd claudecodeui && npx vite build

Step 5: Commit

git add src/components/WorkflowManager.jsx src/components/MainContent.jsx src/utils/api.js
git commit -m "feat(workflow): add Workflow Manager panel with template picker"

Task 8: Build the Workflow Editor (React Flow canvas)

Files:

  • Create: claudecodeui/src/components/WorkflowEditor.jsx
  • Create: claudecodeui/src/components/workflow/StepNode.jsx
  • Create: claudecodeui/src/components/workflow/StepInspector.jsx
  • Create: claudecodeui/src/components/workflow/workflowToGraph.js
  • Modify: claudecodeui/src/components/MainContent.jsx (render editor overlay)

Step 1: Create workflowToGraph.js

Converts parsed AST to React Flow nodes and edges:

  • Each step becomes a node at position (250, index * 120 + 50)
  • Node data includes step properties + color + iconName from type lookup tables
  • Edges derived from reads/writes: if step B reads what step A writes, edge A→B
  • Sequential fallback edges (dashed) for steps without dependency edges
  • Explicit edges for goto (orange) and fallback (red dashed)

Color map: transform=blue, skill=purple, tool=green, decision=orange, gate=red, parallel=teal, end=gray.

Step 2: Create StepNode.jsx

Custom React Flow node component:

  • Renders as a card: colored left border, icon, step id (bold), type badge, one-line description
  • Gate steps: octagon shape via CSS clip-path
  • Decision steps: diamond rotation via CSS transform
  • Parallel steps: double border
  • Source and target handles for edge connections

Step 3: Create StepInspector.jsx

Bottom panel form for selected step. Fields:

  • id (readonly text)
  • type (dropdown: transform, skill, tool, decision, gate, parallel, end)
  • description (text input)
  • reads (comma-separated text, parsed to array)
  • writes (comma-separated text, parsed to array)
  • when (text input, optional)
  • on_error (dropdown: stop, skip, fallback, retry)
  • fallback (dropdown of other step IDs, shown when on_error=fallback)
  • expected_output (textarea, optional)
  • reason_code (text input)
  • agent (dropdown of agent IDs, shown for skill/gate types)
  • bundle (dropdown of bundle names, shown for parallel type)

Changes call onStepChange(stepId, updates) prop.

Step 4: Build WorkflowEditor.jsx

Full-screen overlay (z-[300], same pattern as CodeEditor modal). Structure:

  • Toolbar: Back button, workflow name (editable), version, status badge, [Save] [Run Now] buttons
  • View toggle: [Canvas] [Code] [Split] buttons
  • Main area:
    • Canvas mode: React Flow full width
    • Code mode: CodeMirror full width (read-only for POC, shows serialized MD)
    • Split mode: 60/40 split with resizable divider
  • Inspector: Bottom panel, 200px height, shown when node selected
  • React Flow config: nodeTypes: { stepNode: StepNode }, background dots, minimap, controls

State flow:

  1. Load: api.workflows.get(name) → content string
  2. Parse: parseWorkflow(content) → AST
  3. Graph: workflowToGraph(ast){ nodes, edges }
  4. Edit: Inspector changes → update AST → workflowToGraph(newAst) → update nodes/edges + serializeWorkflow(newAst) → update code pane
  5. Save: serializeWorkflow(ast)api.workflows.save(name, md, metadata)

Step 5: Wire into MainContent.jsx

  • Import WorkflowEditor
  • Render as overlay when editingWorkflow is set
  • Pass onClose={() => setEditingWorkflow(null)}

Step 6: Verify build

Run: cd claudecodeui && npx vite build

Step 7: Commit

git add src/components/WorkflowEditor.jsx src/components/workflow/
git commit -m "feat(workflow): add React Flow workflow editor with canvas and inspector"

Task 9: Add workflow icons to icon management

Files:

  • Modify: claudecodeui/src/components/icons/index.jsx

Step 1: Check which icons need adding

Required icons: TreeStructure, Funnel, Lightning, Wrench, GitBranch, ShieldCheck, ArrowsSplit, Flag

Check existing exports in icons/index.jsx, add any missing.

Step 2: Commit

git add src/components/icons/index.jsx
git commit -m "feat(icons): add workflow step type icons"

Task 10: Docker build and integration test

Step 1: Verify local dev

Run: cd /Users/lindsay/Documents/work/sasha && ./dev.sh

Open http://localhost:3007, verify:

  • "Workflows" tab appears (was "Tasks")
  • Two example workflows listed
  • "+ New Workflow" opens template picker with three models
  • Clicking "Edit" opens the workflow editor
  • Canvas shows nodes with correct colors and edges
  • Code pane shows valid Agent Flow markdown
  • Clicking a node opens inspector with editable fields
  • Inspector changes update the canvas and code
  • Save persists to file and DB
  • Existing "Tasks" functionality still accessible

Step 2: Verify Docker build

Run: cd /Users/lindsay/Documents/work/sasha && ./docker-local.sh
Open http://localhost:3006, same verification.

Step 3: Fix any issues, commit fixes


Task 11: Bump version and push

Step 1: Bump version

Run: ./docker-build-ghcr.sh patch

Step 2: Push

Run: git push origin main


Dependency Graph

Task 1 (React Flow)  ──────────────────────────┐
Task 2 (Parser)  ────── Task 3 (Serializer) ───┤
Task 4 (Server API)  ──────────────────────────┤
Task 5 (Example files) ────────────────────────┤
Task 6 (Templates)  ───────────────────────────┤── Task 7 (Manager UI) ── Task 8 (Editor) ── Task 10 (Test) ── Task 11 (Ship)
Task 9 (Icons)  ────────────────────────────────┘

Tasks 1, 2, 4, 5, 6, 9 can run in parallel.
Task 3 depends on Task 2.
Task 7 depends on Tasks 4, 6.
Task 8 depends on Tasks 1, 2, 3, 7.
Task 10 depends on all above.