diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 866e93f..dd8fde7 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.4.3"
+ ".": "1.5.0"
}
diff --git a/README.md b/README.md
index 71a1d42..bddd271 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,14 @@ Mason is a desktop application that leverages Databricks Unity AI Gateway and Un
+## Agentic Workflow Designer
+
+Build multi-model agentic pipelines on a drag-and-drop canvas. Each **cell** picks a model, a subset of your connected tools, and a prompt; wire cells together with **flow** edges to pipe one cell's output into the next, or **feedback** edges to create bounded revision loops where a reviewer routes work back until it passes. Mix providers freely — a Fable cell can feed an Opus cell whose work a Sonnet cell validates — all through the same governed gateway.
+
+
+
+
+
## Installation
### macOS (Apple Silicon) — one-line install
diff --git a/css/app.css b/css/app.css
index f4b07f2..02c4989 100644
--- a/css/app.css
+++ b/css/app.css
@@ -1066,3 +1066,380 @@
/* Notes block in update modal */
body.dark #updateNotes { background: rgba(255,255,255,0.05); }
+
+ /* ============================================================
+ Workflow Designer
+ ============================================================ */
+
+ .sidebar-designer-btn {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 10px;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ background: none;
+ color: inherit;
+ font-size: 0.82rem;
+ cursor: pointer;
+ width: 100%;
+ transition: background 0.2s, border-color 0.2s;
+ }
+ .sidebar-designer-btn:hover { background: rgba(0,0,0,0.04); border-color: #aaa; }
+ .sidebar-designer-btn.active { border-color: #ff3621; color: #ff3621; }
+ body.dark .sidebar-designer-btn { border-color: #444; }
+ body.dark .sidebar-designer-btn:hover { background: rgba(255,255,255,0.04); border-color: #666; }
+ body.dark .sidebar-designer-btn.active { border-color: #ff3621; color: #ff6a5b; }
+
+ .designer-view {
+ display: none;
+ flex: 1;
+ flex-direction: column;
+ width: 100%;
+ min-height: 0;
+ position: relative;
+ }
+ .designer-view.visible { display: flex; }
+
+ .designer-toolbar {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 14px;
+ border-bottom: 1px solid #e8e8e8;
+ flex-wrap: wrap;
+ }
+ body.dark .designer-toolbar { border-color: #2a2a2a; }
+ .designer-toolbar select,
+ .wf-name-input {
+ padding: 6px 10px;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ font-size: 0.82rem;
+ background: #fff;
+ color: #333;
+ outline: none;
+ }
+ .wf-name-input { flex: 0 1 220px; font-weight: 600; }
+ .wf-name-input:focus { border-color: #007aff; }
+ body.dark .designer-toolbar select,
+ body.dark .wf-name-input { background: #222; border-color: #3a3a3a; color: #ccc; }
+
+ .wf-btn {
+ padding: 6px 12px;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ background: none;
+ color: inherit;
+ font-size: 0.82rem;
+ cursor: pointer;
+ transition: background 0.2s, border-color 0.2s;
+ white-space: nowrap;
+ }
+ .wf-btn:hover { background: rgba(0,0,0,0.04); border-color: #aaa; }
+ body.dark .wf-btn { border-color: #444; }
+ body.dark .wf-btn:hover { background: rgba(255,255,255,0.05); }
+ .wf-btn.primary { background: #ff3621; border-color: #ff3621; color: #fff; font-weight: 600; }
+ .wf-btn.primary:hover { background: #e62f1c; }
+ .wf-btn.primary.running { background: #555; border-color: #555; }
+ .wf-btn.danger:hover { border-color: #c00; color: #c00; }
+ .wf-btn.dirty::after { content: " •"; color: #ff3621; }
+
+ .wf-status { font-size: 0.78rem; opacity: 0.6; margin-left: auto; max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+ .wf-status.error { color: #c00; opacity: 1; }
+ body.dark .wf-status.error { color: #ff6a5b; }
+
+ .designer-canvas-wrap {
+ flex: 1;
+ position: relative;
+ overflow: hidden;
+ min-height: 0;
+ cursor: grab;
+ background-color: #fafafa;
+ background-image: radial-gradient(circle, rgba(0,0,0,0.13) 1px, transparent 1px);
+ background-size: 22px 22px;
+ }
+ .designer-canvas-wrap:active { cursor: grabbing; }
+ body.dark .designer-canvas-wrap {
+ background-color: #161616;
+ background-image: radial-gradient(circle, rgba(255,255,255,0.09) 1px, transparent 1px);
+ }
+ .designer-canvas {
+ position: absolute;
+ top: 0; left: 0;
+ width: 0; height: 0;
+ transform-origin: 0 0;
+ }
+ .designer-edges {
+ position: absolute;
+ left: -10000px;
+ top: -10000px;
+ width: 20000px;
+ height: 20000px;
+ overflow: visible;
+ pointer-events: none;
+ }
+ .wf-edge {
+ fill: none;
+ stroke: #9aa3ad;
+ stroke-width: 2;
+ pointer-events: none;
+ }
+ .wf-edge.selected { stroke: #007aff; stroke-width: 3; }
+ .wf-edge-feedback { stroke: #ff3621; stroke-dasharray: 7 5; }
+ .wf-edge-feedback.selected { stroke: #ff3621; stroke-width: 3.5; }
+ .wf-edge-ghost { stroke: #007aff; stroke-dasharray: 4 4; opacity: 0.7; }
+ .wf-edge-hit {
+ fill: none;
+ stroke: transparent;
+ stroke-width: 16;
+ pointer-events: stroke;
+ cursor: pointer;
+ }
+ .wf-edge-label {
+ font-size: 12px;
+ fill: #667;
+ text-anchor: middle;
+ pointer-events: none;
+ font-family: -apple-system, BlinkMacSystemFont, sans-serif;
+ }
+ body.dark .wf-edge-label { fill: #99a; }
+ body.dark .wf-edge { stroke: #5a626c; }
+
+ .wf-edge-label-input {
+ position: absolute;
+ transform: translate(-50%, -50%);
+ z-index: 30;
+ padding: 4px 8px;
+ border: 1px solid #007aff;
+ border-radius: 6px;
+ font-size: 0.78rem;
+ background: #fff;
+ color: #333;
+ outline: none;
+ width: 170px;
+ }
+ body.dark .wf-edge-label-input { background: #2a2a2a; color: #ddd; }
+
+ .wf-cell {
+ position: absolute;
+ width: 240px;
+ background: #fff;
+ border: 1.5px solid #d4d8dd;
+ border-radius: 12px;
+ box-shadow: 0 2px 10px rgba(0,0,0,0.07);
+ padding: 8px 10px 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ cursor: default;
+ box-sizing: border-box;
+ }
+ .wf-cell.selected { border-color: #007aff; box-shadow: 0 3px 14px rgba(0,122,255,0.22); }
+ body.dark .wf-cell { background: #242424; border-color: #3c4046; }
+ body.dark .wf-cell.selected { border-color: #4a9bff; }
+
+ .wf-cell-header {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ cursor: move;
+ margin: -8px -10px 0;
+ padding: 8px 10px 2px;
+ }
+ .wf-cell-name {
+ flex: 1;
+ min-width: 0;
+ border: none;
+ background: none;
+ font-weight: 700;
+ font-size: 0.86rem;
+ color: inherit;
+ outline: none;
+ cursor: text;
+ }
+ .wf-cell-delete {
+ border: none;
+ background: none;
+ color: inherit;
+ opacity: 0.4;
+ font-size: 1rem;
+ cursor: pointer;
+ padding: 0 2px;
+ }
+ .wf-cell-delete:hover { opacity: 1; color: #c00; }
+
+ .wf-cell-model {
+ width: 100%;
+ padding: 4px 6px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 0.76rem;
+ background: #fff;
+ color: #333;
+ outline: none;
+ }
+ body.dark .wf-cell-model { background: #1d1d1d; border-color: #3a3a3a; color: #ccc; }
+
+ .wf-cell-toolsrow { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
+ .wf-cell-tools-btn {
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ background: none;
+ color: inherit;
+ font-size: 0.72rem;
+ padding: 3px 8px;
+ cursor: pointer;
+ }
+ .wf-cell-tools-btn:hover { border-color: #aaa; background: rgba(0,0,0,0.03); }
+ body.dark .wf-cell-tools-btn { border-color: #3a3a3a; }
+
+ .wf-cell-status {
+ font-size: 0.7rem;
+ padding: 2px 8px;
+ border-radius: 999px;
+ background: rgba(0,0,0,0.06);
+ opacity: 0.75;
+ }
+ body.dark .wf-cell-status { background: rgba(255,255,255,0.08); }
+ .wf-status-running { background: #ff3621 !important; color: #fff; opacity: 1; animation: wfPulse 1.2s ease-in-out infinite; }
+ .wf-status-queued { background: rgba(255,54,33,0.15) !important; color: #ff3621; opacity: 1; }
+ .wf-status-done { background: #1d9b4e !important; color: #fff; opacity: 1; }
+ .wf-status-failed { background: #c00 !important; color: #fff; opacity: 1; }
+ .wf-status-skipped { opacity: 0.4; }
+ @keyframes wfPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
+
+ .wf-cell-prompt {
+ width: 100%;
+ resize: vertical;
+ min-height: 54px;
+ max-height: 220px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 0.76rem;
+ font-family: inherit;
+ padding: 6px 8px;
+ background: #fff;
+ color: #333;
+ outline: none;
+ box-sizing: border-box;
+ }
+ .wf-cell-prompt:focus { border-color: #007aff; }
+ body.dark .wf-cell-prompt { background: #1d1d1d; border-color: #3a3a3a; color: #ccc; }
+
+ .wf-port {
+ position: absolute;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ background: #fff;
+ border: 2.5px solid #9aa3ad;
+ z-index: 2;
+ }
+ body.dark .wf-port { background: #242424; }
+ .wf-port-in { left: -8px; top: 50%; transform: translateY(-50%); }
+ .wf-port-out { right: -8px; top: 50%; transform: translateY(-50%); cursor: crosshair; }
+ .wf-port-out:hover { border-color: #007aff; background: #007aff; }
+ .wf-port-feedback {
+ left: 50%; top: -8px; transform: translateX(-50%);
+ border-style: dashed;
+ border-color: #ff3621;
+ }
+
+ .designer-drawer {
+ border-top: 1px solid #e8e8e8;
+ height: 240px;
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ background: #fff;
+ }
+ body.dark .designer-drawer { border-color: #2a2a2a; background: #1c1c1c; }
+ .designer-drawer.collapsed { height: 38px; }
+ .designer-drawer.collapsed .designer-drawer-body { display: none; }
+ .designer-drawer-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 6px 14px;
+ font-size: 0.82rem;
+ font-weight: 600;
+ flex-shrink: 0;
+ }
+ .designer-drawer-header .wf-cell-status { margin-left: 8px; }
+ .designer-drawer-body {
+ flex: 1;
+ overflow-y: auto;
+ padding: 4px 16px 14px;
+ font-size: 0.84rem;
+ }
+ .wf-drawer-hint { opacity: 0.5; font-size: 0.8rem; padding: 8px 0; }
+ .wf-tr { margin: 6px 0; }
+ .wf-tr-tool-call, .wf-tr-tool-result, .wf-tr-info {
+ font-family: ui-monospace, Menlo, monospace;
+ font-size: 0.74rem;
+ color: #3568a8;
+ background: rgba(0,122,255,0.07);
+ border-radius: 6px;
+ padding: 4px 8px;
+ white-space: pre-wrap;
+ word-break: break-word;
+ }
+ body.dark .wf-tr-tool-call, body.dark .wf-tr-tool-result, body.dark .wf-tr-info { color: #7fb0e8; }
+ .wf-tr-error { color: #c00; font-size: 0.78rem; }
+ body.dark .wf-tr-error { color: #ff6a5b; }
+ .wf-tr-verdict {
+ border-left: 3px solid #ff3621;
+ padding: 4px 10px;
+ font-size: 0.8rem;
+ font-weight: 600;
+ background: rgba(255,54,33,0.06);
+ border-radius: 0 6px 6px 0;
+ white-space: pre-wrap;
+ }
+ .wf-tr-output { border-top: 1px dashed #ddd; padding-top: 8px; }
+ body.dark .wf-tr-output { border-color: #3a3a3a; }
+
+ .wf-tools-group {
+ font-size: 0.72rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+ opacity: 0.5;
+ margin: 12px 0 4px;
+ }
+ .wf-tools-row {
+ display: flex;
+ align-items: baseline;
+ gap: 8px;
+ padding: 3px 2px;
+ font-size: 0.8rem;
+ cursor: pointer;
+ border-radius: 6px;
+ }
+ .wf-tools-row:hover { background: rgba(0,0,0,0.03); }
+ body.dark .wf-tools-row:hover { background: rgba(255,255,255,0.04); }
+ .wf-tools-name { font-family: ui-monospace, Menlo, monospace; font-size: 0.74rem; }
+ .wf-tools-desc { opacity: 0.45; font-size: 0.72rem; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+
+ /* Per-cell feedback loop cap */
+ .wf-cell-loopcap {
+ display: flex;
+ align-items: center;
+ gap: 3px;
+ font-size: 0.74rem;
+ opacity: 0.75;
+ cursor: help;
+ }
+ .wf-cell-loopcap input {
+ width: 34px;
+ padding: 2px 4px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ font-size: 0.72rem;
+ background: #fff;
+ color: #333;
+ outline: none;
+ text-align: center;
+ }
+ body.dark .wf-cell-loopcap input { background: #1d1d1d; border-color: #3a3a3a; color: #ccc; }
diff --git a/docs/designer.png b/docs/designer.png
new file mode 100644
index 0000000..0768dca
Binary files /dev/null and b/docs/designer.png differ
diff --git a/docs/specs/agentic-workflow-designer.md b/docs/specs/agentic-workflow-designer.md
new file mode 100644
index 0000000..5b31884
--- /dev/null
+++ b/docs/specs/agentic-workflow-designer.md
@@ -0,0 +1,460 @@
+# Engineering Specification — Agentic Workflow Designer
+
+**Status:** Draft for review
+**Author:** Mason core
+**Target:** Mason v1.5.x (phased; see Rollout)
+**Last updated:** 2026-06-11
+
+---
+
+## 1. Summary
+
+Add a visual, node-based **Workflow Designer** to Mason — a drag-and-drop canvas (in the spirit of n8n / ComfyUI) where users compose multi-model agentic pipelines out of **Cells**. Each Cell selects a model, a subset of available tools (built-in + MCP + UC MCP), and a prompt. Cells are wired together with edges: an edge from Cell A to Cell B means *A runs first, and A's output is injected into B's context*. Edges can also express **feedback loops** (B sends results back to A for revision) and **review gates** (a cell decides whether the workflow ends or routes work back for another pass).
+
+The designer is opened from a new button in the sidebar, directly **above the Profile section**. It replaces the chat pane with a full-pane canvas view, following the same view-swapping pattern as Dashboards/Settings/Onboarding.
+
+Everything executes through the existing Databricks AI Gateway plumbing — per-model format routing, OAuth, streaming, MCP tool dispatch, Anthropic prompt caching — none of which changes. The workflow engine is a thin orchestrator that runs the existing per-turn agent loop once per cell, in graph order.
+
+### Motivating user story (acceptance scenario)
+
+> I click **Workflow Designer**. A designer pane opens in the chat window. I create a cell, select **Fable 5**, pick a couple of MCP tools, and write a prompt with the high-level goals and specs of the project. I create a second cell with **Opus 4.8**, a different toolset, and an additional prompt. I drag a line from the Fable cell to the Opus cell — meaning the Fable cell runs first and its output feeds the Opus cell. I create a third cell named **"unit tests"** with a Sonnet model. The Fable cell feeds its unit-test specs to the unit-tests cell via a second line, and the unit-tests cell *also* receives a line from the Opus cell (two inputs) so it can run Opus's work against the spec sheet. The unit-tests cell has a **feedback** line back to the Opus cell: it reports which tests passed and what gaps remain, and Opus iterates until they're closed. When the unit-tests cell deems the work complete, it hands off to the Fable cell for **final review**. Fable either ends the session or passes the work back to Opus for another round.
+
+Section 12 walks this scenario through the spec end-to-end as the primary acceptance test.
+
+---
+
+## 2. Current-state evaluation (what we're building on)
+
+A short audit of the parts of Mason this feature touches, and the constraints they impose.
+
+### 2.1 Architecture facts that shape this design
+
+| Fact | Where | Consequence for the designer |
+|---|---|---|
+| Renderer is **script-mode TypeScript** — no bundler, no imports; modules share one global scope and load via `
+
+
+