diff --git a/Data/Agent/borealis-agent.py b/Data/Agent/borealis-agent.py
index e6e92cd..2ff9193 100644
--- a/Data/Agent/borealis-agent.py
+++ b/Data/Agent/borealis-agent.py
@@ -8,31 +8,28 @@ import threading
 import socketio
 from io import BytesIO
 import socket
+import os
 
 from PyQt5 import QtCore, QtGui, QtWidgets
 from PIL import ImageGrab
 
 # ---------------- Configuration ----------------
-SERVER_URL = "http://localhost:5000"  # WebSocket-enabled Internal URL
-#SERVER_URL = "https://borealis.bunny-lab.io"  # WebSocket-enabled Public URL"
+SERVER_URL = os.environ.get("SERVER_URL", "http://localhost:5000")
 
 HOSTNAME = socket.gethostname().lower()
 RANDOM_SUFFIX = uuid.uuid4().hex[:8]
 AGENT_ID = f"{HOSTNAME}-agent-{RANDOM_SUFFIX}"
 
-# ---------------- State ----------------
+# ---------------- App State ----------------
 app_instance = None
-region_widget = None
-current_interval = 1000
-config_ready = threading.Event()
-overlay_visible = True
+overlay_widgets = {}
+region_launchers = {}
+running_roles = {}
+running_threads = {}
 
-LAST_CONFIG = {}
-
-# WebSocket client setup
+# ---------------- Socket Setup ----------------
 sio = socketio.Client()
 
-# ---------------- WebSocket Handlers ----------------
 @sio.event
 def connect():
     print(f"[WebSocket] Agent ID: {AGENT_ID} connected to Borealis.")
@@ -45,30 +42,18 @@ def disconnect():
 
 @sio.on('agent_config')
 def on_agent_config(config):
-    global current_interval, overlay_visible, LAST_CONFIG
+    print("[PROVISIONED] Received new configuration from Borealis.")
 
-    if config != LAST_CONFIG:
-        print("[PROVISIONED] Received new configuration from Borealis.")
-        x = config.get("x", 100)
-        y = config.get("y", 100)
-        w = config.get("w", 300)
-        h = config.get("h", 200)
-        current_interval = config.get("interval", 1000)
-        overlay_visible = config.get("visible", True)
+    roles = config.get("roles", [])
+    stop_all_roles()
+    for role in roles:
+        start_role_thread(role)
 
-        if not region_widget:
-            region_launcher.trigger.emit(x, y, w, h)
-        else:
-            region_widget.setGeometry(x, y, w, h)
-            region_widget.setVisible(overlay_visible)
-
-        LAST_CONFIG = config
-        config_ready.set()
-
-# ---------------- Region Overlay ----------------
+# ---------------- Overlay Class ----------------
 class ScreenshotRegion(QtWidgets.QWidget):
-    def __init__(self, x=100, y=100, w=300, h=200):
+    def __init__(self, node_id, x=100, y=100, w=300, h=200):
         super().__init__()
+        self.node_id = node_id
         self.setGeometry(x, y, w, h)
         self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
         self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
@@ -78,7 +63,7 @@ class ScreenshotRegion(QtWidgets.QWidget):
         self.setVisible(True)
 
         self.label = QtWidgets.QLabel(self)
-        self.label.setText(AGENT_ID)
+        self.label.setText(f"{node_id[:8]}")
         self.label.setStyleSheet("color: lime; background: transparent; font-size: 10px;")
         self.label.move(8, 4)
 
@@ -87,7 +72,6 @@ class ScreenshotRegion(QtWidgets.QWidget):
     def paintEvent(self, event):
         painter = QtGui.QPainter(self)
         painter.setRenderHint(QtGui.QPainter.Antialiasing)
-
         painter.setBrush(QtCore.Qt.transparent)
         painter.setPen(QtGui.QPen(QtGui.QColor(0, 255, 0), 2))
         painter.drawRect(self.rect())
@@ -102,8 +86,8 @@ class ScreenshotRegion(QtWidgets.QWidget):
 
     def mousePressEvent(self, event):
         if event.button() == QtCore.Qt.LeftButton:
-            if (event.pos().x() > self.width() - self.resize_handle_size and
-                event.pos().y() > self.height() - self.resize_handle_size):
+            if event.pos().x() > self.width() - self.resize_handle_size and \
+               event.pos().y() > self.height() - self.resize_handle_size:
                 self.resizing = True
             else:
                 self.drag_offset = event.globalPos() - self.frameGeometry().topLeft()
@@ -124,58 +108,91 @@ class ScreenshotRegion(QtWidgets.QWidget):
         geo = self.geometry()
         return geo.x(), geo.y(), geo.width(), geo.height()
 
-# ---------------- Screenshot Capture ----------------
-def capture_loop():
-    config_ready.wait()
-
-    while region_widget is None:
-        time.sleep(0.2)
-
-    while True:
-        if overlay_visible:
-            x, y, w, h = region_widget.get_geometry()
-            try:
-                img = ImageGrab.grab(bbox=(x, y, x + w, y + h))
-                buffer = BytesIO()
-                img.save(buffer, format="PNG")
-                encoded_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
-
-                sio.emit('screenshot', {
-                    'agent_id': AGENT_ID,
-                    'image_base64': encoded_image
-                })
-            except Exception as e:
-                print(f"[ERROR] Screenshot error: {e}")
-
-        time.sleep(current_interval / 1000)
-
-# ---------------- UI Launcher ----------------
+# ---------------- Region UI Handler ----------------
 class RegionLauncher(QtCore.QObject):
     trigger = QtCore.pyqtSignal(int, int, int, int)
 
-    def __init__(self):
+    def __init__(self, node_id):
         super().__init__()
+        self.node_id = node_id
         self.trigger.connect(self.handle)
 
     def handle(self, x, y, w, h):
-        launch_region(x, y, w, h)
+        print(f"[Overlay] Launching overlay for {self.node_id} at ({x},{y},{w},{h})")
+        if self.node_id in overlay_widgets:
+            return
+        widget = ScreenshotRegion(self.node_id, x, y, w, h)
+        overlay_widgets[self.node_id] = widget
+        widget.show()
 
-region_launcher = None
+# ---------------- Role Management ----------------
+def stop_all_roles():
+    for node_id, thread in running_threads.items():
+        if thread and thread.is_alive():
+            print(f"[Role] Terminating previous task: {node_id}")
+    running_roles.clear()
+    running_threads.clear()
 
-def launch_region(x, y, w, h):
-    global region_widget
-    if region_widget:
+def start_role_thread(role_cfg):
+    role = role_cfg.get("role")
+    node_id = role_cfg.get("node_id")
+    if not role or not node_id:
+        print("[ERROR] Invalid role configuration (missing role or node_id).")
         return
-    region_widget = ScreenshotRegion(x, y, w, h)
-    region_widget.show()
+
+    if role == "screenshot":
+        thread = threading.Thread(target=run_screenshot_loop, args=(node_id, role_cfg), daemon=True)
+    else:
+        print(f"[SKIP] Unknown role: {role}")
+        return
+
+    running_roles[node_id] = role_cfg
+    running_threads[node_id] = thread
+    thread.start()
+    print(f"[Role] Started task: {role} ({node_id})")
+
+# ---------------- Screenshot Role Loop ----------------
+def run_screenshot_loop(node_id, cfg):
+    interval = cfg.get("interval", 1000)
+    visible = cfg.get("visible", True)
+    x = cfg.get("x", 100)
+    y = cfg.get("y", 100)
+    w = cfg.get("w", 300)
+    h = cfg.get("h", 200)
+
+    if node_id not in region_launchers:
+        launcher = RegionLauncher(node_id)
+        region_launchers[node_id] = launcher
+        launcher.trigger.emit(x, y, w, h)
+
+    widget = overlay_widgets.get(node_id)
+    if widget:
+        widget.setGeometry(x, y, w, h)
+        widget.setVisible(visible)
+
+    while True:
+        try:
+            if node_id in overlay_widgets:
+                widget = overlay_widgets[node_id]
+                x, y, w, h = widget.get_geometry()
+            print(f"[Capture] Screenshot task {node_id} at ({x},{y},{w},{h})")
+            img = ImageGrab.grab(bbox=(x, y, x + w, y + h))
+            buffer = BytesIO()
+            img.save(buffer, format="PNG")
+            encoded = base64.b64encode(buffer.getvalue()).decode("utf-8")
+
+            sio.emit("agent_screenshot_task", {
+                "agent_id": AGENT_ID,
+                "node_id": node_id,
+                "image_base64": encoded
+            })
+        except Exception as e:
+            print(f"[ERROR] Screenshot task {node_id} failed: {e}")
+
+        time.sleep(interval / 1000)
 
 # ---------------- Main ----------------
 if __name__ == "__main__":
     app_instance = QtWidgets.QApplication(sys.argv)
-    region_launcher = RegionLauncher()
-
-    sio.connect(SERVER_URL, transports=['websocket'])
-
-    threading.Thread(target=capture_loop, daemon=True).start()
-
+    sio.connect(SERVER_URL, transports=["websocket"])
     sys.exit(app_instance.exec_())
diff --git a/Data/WebUI/src/App.jsx b/Data/WebUI/src/App.jsx
index 5d792b3..9d2bbac 100644
--- a/Data/WebUI/src/App.jsx
+++ b/Data/WebUI/src/App.jsx
@@ -48,6 +48,15 @@ import React, {
   } from "./Dialogs";
   import StatusBar from "./Status_Bar";
   
+  // Websocket Functionality
+  import { io } from "socket.io-client";
+  
+  if (!window.BorealisSocket) {
+    window.BorealisSocket = io(window.location.origin, {
+      transports: ["websocket"]
+    });
+  }
+
   // Global Node Update Timer Variable
   if (!window.BorealisUpdateRate) {
     window.BorealisUpdateRate = 200;
diff --git a/Data/WebUI/src/Node_Sidebar.jsx b/Data/WebUI/src/Node_Sidebar.jsx
index 794bd38..f7c5afb 100644
--- a/Data/WebUI/src/Node_Sidebar.jsx
+++ b/Data/WebUI/src/Node_Sidebar.jsx
@@ -35,7 +35,7 @@ export default function NodeSidebar({
   return (
     <div
       style={{
-        width: 320,
+        width: 300, //Width of the Node Sidebar
         backgroundColor: "#121212",
         borderRight: "1px solid #333",
         overflowY: "auto"
diff --git a/Data/WebUI/src/nodes/Agents/Node_Agent.jsx b/Data/WebUI/src/nodes/Agents/Node_Agent.jsx
new file mode 100644
index 0000000..bc5bdb4
--- /dev/null
+++ b/Data/WebUI/src/nodes/Agents/Node_Agent.jsx
@@ -0,0 +1,154 @@
+////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/nodes/Agent/Node_Agent.jsx
+
+import React, { useEffect, useState } from "react";
+import { Handle, Position, useReactFlow, useStore } from "reactflow";
+
+const BorealisAgentNode = ({ id, data }) => {
+    const { getNodes, getEdges, setNodes } = useReactFlow();
+    const [agents, setAgents] = useState([]);
+    const [selectedAgent, setSelectedAgent] = useState(data.agent_id || "");
+
+    // -------------------------------
+    // Load agent list from backend
+    // -------------------------------
+    useEffect(() => {
+        fetch("/api/agents")
+            .then(res => res.json())
+            .then(setAgents);
+
+        const interval = setInterval(() => {
+            fetch("/api/agents")
+                .then(res => res.json())
+                .then(setAgents);
+        }, 5000);
+
+        return () => clearInterval(interval);
+    }, []);
+
+    // -------------------------------
+    // Helper: Get all provisioner role nodes connected to bottom port
+    // -------------------------------
+    const getAttachedProvisioners = () => {
+        const allNodes = getNodes();
+        const allEdges = getEdges();
+        const attached = [];
+
+        for (const edge of allEdges) {
+            if (edge.source === id && edge.sourceHandle === "provisioner") {
+                const roleNode = allNodes.find(n => n.id === edge.target);
+                if (roleNode && typeof window.__BorealisInstructionNodes?.[roleNode.id] === "function") {
+                    attached.push(window.__BorealisInstructionNodes[roleNode.id]());
+                }
+            }
+        }
+
+        return attached;
+    };
+
+    // -------------------------------
+    // Provision Agent with all Roles
+    // -------------------------------
+    const handleProvision = () => {
+        if (!selectedAgent) return;
+
+        const provisionRoles = getAttachedProvisioners();
+        if (!provisionRoles.length) {
+            console.warn("No provisioner nodes connected to agent.");
+            return;
+        }
+
+        const configPayload = {
+            agent_id: selectedAgent,
+            roles: provisionRoles
+        };
+
+        fetch("/api/agent/provision", {
+            method: "POST",
+            headers: { "Content-Type": "application/json" },
+            body: JSON.stringify(configPayload)
+        })
+            .then(res => res.json())
+            .then(() => {
+                console.log(`[Provision] Agent ${selectedAgent} updated with ${provisionRoles.length} roles.`);
+            });
+    };
+
+    return (
+        <div className="borealis-node">
+            {/* This bottom port is used for bi-directional provisioning & feedback */}
+            <Handle
+                type="source"
+                position={Position.Bottom}
+                id="provisioner"
+                className="borealis-handle"
+                style={{ top: "100%", background: "#58a6ff" }}
+            />
+
+            <div className="borealis-node-header">Borealis Agent</div>
+            <div className="borealis-node-content" style={{ fontSize: "9px" }}>
+                <label>Agent:</label>
+                <select
+                    value={selectedAgent}
+                    onChange={(e) => {
+                        const newId = e.target.value;
+                        setSelectedAgent(newId);
+                        setNodes(nds =>
+                            nds.map(n =>
+                                n.id === id
+                                    ? { ...n, data: { ...n.data, agent_id: newId } }
+                                    : n
+                            )
+                        );
+                    }}
+                    style={{ width: "100%", marginBottom: "6px", fontSize: "9px" }}
+                >
+                    <option value="">-- Select --</option>
+                    {Object.entries(agents).map(([id, info]) => {
+                        const label = info.status === "provisioned" ? "(Provisioned)" : "(Idle)";
+                        return (
+                            <option key={id} value={id}>
+                                {id} {label}
+                            </option>
+                        );
+                    })}
+                </select>
+
+                <button
+                    onClick={handleProvision}
+                    style={{ width: "100%", fontSize: "9px", padding: "4px", marginTop: "4px" }}
+                >
+                    Provision Agent
+                </button>
+
+                <hr style={{ margin: "6px 0", borderColor: "#444" }} />
+
+                <div style={{ fontSize: "8px", color: "#aaa" }}>
+                    Connect <strong>Instruction Nodes</strong> below to define roles.
+                    Each instruction node will send back its results (like screenshots) and act as a separate data output.
+                </div>
+
+                <div style={{ fontSize: "8px", color: "#aaa", marginTop: "4px" }}>
+                    <strong>Supported Roles:</strong>
+                    <ul style={{ paddingLeft: "14px", marginTop: "2px", marginBottom: "0" }}>
+                        <li><code>screenshot</code>: Capture a region with interval and overlay</li>
+                        {/* Future roles will be listed here */}
+                    </ul>
+                </div>
+            </div>
+        </div>
+    );
+};
+
+export default {
+    type: "Borealis_Agent",
+    label: "Borealis Agent",
+    description: `
+Main Agent Node
+
+- Selects an available agent
+- Connect instruction nodes below to assign tasks (roles)
+- Roles include screenshots, keyboard macros, etc.
+`.trim(),
+    content: "Select and provision a Borealis Agent with task roles",
+    component: BorealisAgentNode
+};
diff --git a/Data/WebUI/src/nodes/Agents/Node_Agent_Role_Screenshot.jsx b/Data/WebUI/src/nodes/Agents/Node_Agent_Role_Screenshot.jsx
new file mode 100644
index 0000000..6e86279
--- /dev/null
+++ b/Data/WebUI/src/nodes/Agents/Node_Agent_Role_Screenshot.jsx
@@ -0,0 +1,186 @@
+////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/WebUI/src/nodes/Agent/Node_Agent_Role_Screenshot.jsx
+
+import React, { useEffect, useRef, useState } from "react";
+import { Handle, Position, useReactFlow, useStore } from "reactflow";
+import ShareIcon from "@mui/icons-material/Share";
+import IconButton from "@mui/material/IconButton";
+
+if (!window.BorealisValueBus) {
+    window.BorealisValueBus = {};
+}
+
+if (!window.BorealisUpdateRate) {
+    window.BorealisUpdateRate = 100;
+}
+
+const ScreenshotInstructionNode = ({ id, data }) => {
+    const { setNodes, getNodes } = useReactFlow();
+    const edges = useStore(state => state.edges);
+
+    const [interval, setInterval] = useState(data?.interval || 1000);
+    const [region, setRegion] = useState({
+        x: data?.x ?? 250,
+        y: data?.y ?? 100,
+        w: data?.w ?? 300,
+        h: data?.h ?? 200,
+    });
+    const [visible, setVisible] = useState(data?.visible ?? true);
+    const [alias, setAlias] = useState(data?.alias || "");
+    const [imageBase64, setImageBase64] = useState("");
+
+    const base64Ref = useRef("");
+
+    const handleCopyLiveViewLink = () => {
+        const agentEdge = edges.find(e => e.target === id && e.sourceHandle === "provisioner");
+        if (!agentEdge) {
+            alert("No upstream agent connection found.");
+            return;
+        }
+
+        const agentNode = getNodes().find(n => n.id === agentEdge.source);
+        const selectedAgentId = agentNode?.data?.agent_id;
+
+        if (!selectedAgentId) {
+            alert("Upstream agent node does not have a selected agent.");
+            return;
+        }
+
+        const liveUrl = `${window.location.origin}/api/agent/${selectedAgentId}/node/${id}/screenshot/live`;
+        navigator.clipboard.writeText(liveUrl)
+            .then(() => console.log(`[Clipboard] Copied Live View URL: ${liveUrl}`))
+            .catch(err => console.error("Clipboard copy failed:", err));
+    };
+
+    useEffect(() => {
+        const intervalId = setInterval(() => {
+            const val = base64Ref.current;
+
+            console.log(`[Screenshot Node] setInterval update. Current base64 length: ${val?.length || 0}`);
+
+            if (!val) return;
+
+            window.BorealisValueBus[id] = val;
+            setNodes(nds =>
+                nds.map(n =>
+                    n.id === id
+                        ? { ...n, data: { ...n.data, value: val } }
+                        : n
+                )
+            );
+        }, window.BorealisUpdateRate || 100);
+
+        return () => clearInterval(intervalId);
+    }, [id, setNodes]);
+
+    useEffect(() => {
+        const socket = window.BorealisSocket || null;
+        if (!socket) {
+            console.warn("[Screenshot Node] BorealisSocket not available");
+            return;
+        }
+
+        console.log(`[Screenshot Node] Listening for agent_screenshot_task with node_id: ${id}`);
+
+        const handleScreenshot = (payload) => {
+            console.log("[Screenshot Node] Received payload:", payload);
+
+            if (payload?.node_id === id && payload?.image_base64) {
+                base64Ref.current = payload.image_base64;
+                setImageBase64(payload.image_base64);
+                window.BorealisValueBus[id] = payload.image_base64;
+
+                console.log(`[Screenshot Node] Updated base64Ref and ValueBus for ${id}, length: ${payload.image_base64.length}`);
+            } else {
+                console.log(`[Screenshot Node] Ignored payload for mismatched node_id (${payload?.node_id})`);
+            }
+        };
+
+        socket.on("agent_screenshot_task", handleScreenshot);
+        return () => socket.off("agent_screenshot_task", handleScreenshot);
+    }, [id]);
+
+    window.__BorealisInstructionNodes = window.__BorealisInstructionNodes || {};
+    window.__BorealisInstructionNodes[id] = () => ({
+        node_id: id,
+        role: "screenshot",
+        interval,
+        visible,
+        alias,
+        ...region
+    });
+
+    return (
+        <div className="borealis-node" style={{ position: "relative" }}>
+            <Handle type="target" position={Position.Left} className="borealis-handle" />
+            <Handle type="source" position={Position.Right} className="borealis-handle" />
+
+            <div className="borealis-node-header">Agent Role: Screenshot</div>
+            <div className="borealis-node-content" style={{ fontSize: "9px" }}>
+                <label>Update Interval (ms):</label>
+                <input
+                    type="number"
+                    min="100"
+                    step="100"
+                    value={interval}
+                    onChange={(e) => setInterval(Number(e.target.value))}
+                    style={{ width: "100%", marginBottom: "4px" }}
+                />
+
+                <label>Region X / Y / W / H:</label>
+                <div style={{ display: "flex", gap: "4px", marginBottom: "4px" }}>
+                    <input type="number" value={region.x} onChange={(e) => setRegion({ ...region, x: Number(e.target.value) })} style={{ width: "25%" }} />
+                    <input type="number" value={region.y} onChange={(e) => setRegion({ ...region, y: Number(e.target.value) })} style={{ width: "25%" }} />
+                    <input type="number" value={region.w} onChange={(e) => setRegion({ ...region, w: Number(e.target.value) })} style={{ width: "25%" }} />
+                    <input type="number" value={region.h} onChange={(e) => setRegion({ ...region, h: Number(e.target.value) })} style={{ width: "25%" }} />
+                </div>
+
+                <div style={{ marginBottom: "4px" }}>
+                    <label>
+                        <input
+                            type="checkbox"
+                            checked={visible}
+                            onChange={() => setVisible(!visible)}
+                            style={{ marginRight: "4px" }}
+                        />
+                        Show Overlay on Agent
+                    </label>
+                </div>
+
+                <label>Overlay Label:</label>
+                <input
+                    type="text"
+                    value={alias}
+                    onChange={(e) => setAlias(e.target.value)}
+                    placeholder="Label (optional)"
+                    style={{ width: "100%", fontSize: "9px", marginBottom: "6px" }}
+                />
+
+                <div style={{ textAlign: "center", fontSize: "8px", color: "#aaa" }}>
+                    {imageBase64
+                        ? `Last image: ${Math.round(imageBase64.length / 1024)} KB`
+                        : "Awaiting Screenshot Data..."}
+                </div>
+            </div>
+
+            <div style={{ position: "absolute", top: 4, right: 4 }}>
+                <IconButton size="small" onClick={handleCopyLiveViewLink}>
+                    <ShareIcon style={{ fontSize: 14 }} />
+                </IconButton>
+            </div>
+        </div>
+    );
+};
+
+export default {
+    type: "Agent_Role_Screenshot",
+    label: "Agent Role: Screenshot",
+    description: `
+Agent Role Node: Screenshot Region
+
+- Defines a single region capture role
+- Allows custom update interval and overlay
+- Emits captured base64 PNG data from agent
+`.trim(),
+    content: "Capture screenshot region via agent",
+    component: ScreenshotInstructionNode
+};
diff --git a/Data/WebUI/src/nodes/Data Analysis/Node_OCR_Text_Extraction.jsx b/Data/WebUI/src/nodes/Data Analysis/Node_OCR_Text_Extraction.jsx
index 15a0108..f71cfc6 100644
--- a/Data/WebUI/src/nodes/Data Analysis/Node_OCR_Text_Extraction.jsx	
+++ b/Data/WebUI/src/nodes/Data Analysis/Node_OCR_Text_Extraction.jsx	
@@ -233,7 +233,7 @@ const numberInputStyle = {
 
 export default {
     type: "OCR_Text_Extraction",
-    label: "OCR-Based Text Extraction",
+    label: "OCR Text Extraction",
     description: `
 Extract text from upstream image using backend OCR engine via API.
 Includes rate limiting and sensitivity detection for smart processing.`,
diff --git a/Data/WebUI/src/nodes/Data Collection/Node_Borealis_Agent.jsx b/Data/WebUI/src/nodes/Data Collection/Node_Borealis_Agent.jsx
deleted file mode 100644
index 7f483c2..0000000
--- a/Data/WebUI/src/nodes/Data Collection/Node_Borealis_Agent.jsx	
+++ /dev/null
@@ -1,172 +0,0 @@
-////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: Node_Borealis_Agent.jsx
-
-import React, { useEffect, useState, useRef } from "react";
-import { Handle, Position, useReactFlow } from "reactflow";
-import { io } from "socket.io-client";
-
-const socket = io(window.location.origin, {
-    transports: ["websocket"]
-});
-
-const BorealisAgentNode = ({ id, data }) => {
-    const { setNodes } = useReactFlow();
-    const [agents, setAgents] = useState([]);
-    const [selectedAgent, setSelectedAgent] = useState(data.agent_id || "");
-    const [selectedType, setSelectedType] = useState(data.data_type || "screenshot");
-    const [intervalMs, setIntervalMs] = useState(data.interval || 1000);
-    const [paused, setPaused] = useState(false);
-    const [overlayVisible, setOverlayVisible] = useState(true);
-    const [imageData, setImageData] = useState("");
-    const imageRef = useRef("");
-
-    useEffect(() => {
-        fetch("/api/agents").then(res => res.json()).then(setAgents);
-        const interval = setInterval(() => {
-            fetch("/api/agents").then(res => res.json()).then(setAgents);
-        }, 5000);
-        return () => clearInterval(interval);
-    }, []);
-
-    useEffect(() => {
-        socket.on('new_screenshot', (data) => {
-            if (data.agent_id === selectedAgent) {
-                setImageData(data.image_base64);
-                imageRef.current = data.image_base64;
-            }
-        });
-
-        return () => socket.off('new_screenshot');
-    }, [selectedAgent]);
-
-    useEffect(() => {
-        const interval = setInterval(() => {
-            if (!paused && imageRef.current) {
-                window.BorealisValueBus = window.BorealisValueBus || {};
-                window.BorealisValueBus[id] = imageRef.current;
-
-                setNodes(nds => {
-                    const updated = [...nds];
-                    const node = updated.find(n => n.id === id);
-                    if (node) {
-                        node.data = {
-                            ...node.data,
-                            value: imageRef.current
-                        };
-                    }
-                    return updated;
-                });
-            }
-        }, window.BorealisUpdateRate || 100);
-
-        return () => clearInterval(interval);
-    }, [id, paused, setNodes]);
-
-    const provisionAgent = () => {
-        if (!selectedAgent) return;
-        fetch("/api/agent/provision", {
-            method: "POST",
-            headers: { "Content-Type": "application/json" },
-            body: JSON.stringify({
-                agent_id: selectedAgent,
-                x: 250,
-                y: 100,
-                w: 300,
-                h: 200,
-                interval: intervalMs,
-                visible: overlayVisible,
-                task: selectedType
-            })
-        })
-            .then(res => res.json())
-            .then(() => {
-                console.log("[DEBUG] Agent provisioned");
-            });
-    };
-
-    const toggleOverlay = () => {
-        const newVisibility = !overlayVisible;
-        setOverlayVisible(newVisibility);
-        provisionAgent();
-    };
-
-    return (
-        <div className="borealis-node">
-            <Handle type="source" position={Position.Right} className="borealis-handle" />
-            <div className="borealis-node-header">Borealis Agent</div>
-            <div className="borealis-node-content">
-                <label style={{ fontSize: "10px" }}>Agent:</label>
-                <select
-                    value={selectedAgent}
-                    onChange={(e) => setSelectedAgent(e.target.value)}
-                    style={{ width: "100%", fontSize: "9px", marginBottom: "6px" }}
-                >
-                    <option value="">-- Select --</option>
-                    {Object.entries(agents).map(([id, info]) => {
-                        const statusLabel = info.status === "provisioned"
-                            ? "(Provisioned)"
-                            : "(Not Provisioned)";
-                        return (
-                            <option key={id} value={id}>
-                                {id} {statusLabel}
-                            </option>
-                        );
-                    })}
-                </select>
-
-                <label style={{ fontSize: "10px" }}>Data Type:</label>
-                <select
-                    value={selectedType}
-                    onChange={(e) => setSelectedType(e.target.value)}
-                    style={{ width: "100%", fontSize: "9px", marginBottom: "6px" }}
-                >
-                    <option value="screenshot">Screenshot Region</option>
-                </select>
-
-                <label style={{ fontSize: "10px" }}>Update Rate (ms):</label>
-                <input
-                    type="number"
-                    min="100"
-                    step="100"
-                    value={intervalMs}
-                    onChange={(e) => setIntervalMs(Number(e.target.value))}
-                    style={{ width: "100%", fontSize: "9px", marginBottom: "6px" }}
-                />
-
-                <div style={{ marginBottom: "6px" }}>
-                    <label style={{ fontSize: "10px" }}>
-                        <input
-                            type="checkbox"
-                            checked={paused}
-                            onChange={() => setPaused(!paused)}
-                            style={{ marginRight: "4px" }}
-                        />
-                        Pause Data Collection
-                    </label>
-                </div>
-
-                <div style={{ display: "flex", gap: "4px", flexWrap: "wrap" }}>
-                    <button
-                        style={{ flex: 1, fontSize: "9px" }}
-                        onClick={provisionAgent}
-                    >
-                        (Re)Provision
-                    </button>
-                    <button
-                        style={{ flex: 1, fontSize: "9px" }}
-                        onClick={toggleOverlay}
-                    >
-                        {overlayVisible ? "Hide Overlay" : "Show Overlay"}
-                    </button>
-                </div>
-            </div>
-        </div>
-    );
-};
-
-export default {
-    type: "Borealis_Agent",
-    label: "Borealis Agent",
-    description: "Connects to and controls a Borealis Agent via WebSocket in real-time.",
-    content: "Provisions a Borealis Agent and streams collected data into the workflow graph.",
-    component: BorealisAgentNode
-};
diff --git a/Data/server.py b/Data/server.py
index 0f385e5..245061f 100644
--- a/Data/server.py
+++ b/Data/server.py
@@ -73,38 +73,36 @@ def get_agents():
 def provision_agent():
     data = request.json
     agent_id = data.get("agent_id")
-    config = {
-        "task": data.get("task", "screenshot"),
-        "x": data.get("x", 100),
-        "y": data.get("y", 100),
-        "w": data.get("w", 300),
-        "h": data.get("h", 200),
-        "interval": data.get("interval", 1000),
-        "visible": data.get("visible", True)
-    }
+    roles = data.get("roles", [])  # <- MODULAR ROLES ARRAY
+
+    if not agent_id or not isinstance(roles, list):
+        return jsonify({"error": "Missing agent_id or roles[] in provision payload."}), 400
+
+    # Save configuration
+    config = {"roles": roles}
     agent_configurations[agent_id] = config
+
+    # Update status if agent already registered
     if agent_id in registered_agents:
         registered_agents[agent_id]["status"] = "provisioned"
 
-    # NEW: Emit config update back to the agent via WebSocket
+    # Emit config to the agent
     socketio.emit("agent_config", config)
 
-    return jsonify({"status": "provisioned"})
+    return jsonify({"status": "provisioned", "roles": roles})
+
 
 
 # ----------------------------------------------
 # Canvas Image Feed Viewer for Screenshot Agents
 # ----------------------------------------------
-@app.route("/api/agent/<agent_id>/screenshot/live")
-def screenshot_viewer(agent_id):
-    if agent_configurations.get(agent_id, {}).get("task") != "screenshot":
-        return "<h1>Agent not provisioned as Screenshot Collector</h1>", 400
-
+@app.route("/api/agent/<agent_id>/node/<node_id>/screenshot/live")
+def screenshot_node_viewer(agent_id, node_id):
     return f"""
     <!DOCTYPE html>
     <html>
     <head>
-        <title>Borealis Live View - {agent_id}</title>
+        <title>Borealis Live View - {agent_id}:{node_id}</title>
         <style>
             body {{
                 margin: 0;
@@ -118,105 +116,66 @@ def screenshot_viewer(agent_id):
                 border: 1px solid #444;
                 max-width: 90vw;
                 max-height: 90vh;
-                width: auto;
-                height: auto;
                 background-color: #111;
             }}
         </style>
     </head>
     <body>
         <canvas id="viewerCanvas"></canvas>
-
         <script src="https://cdn.socket.io/4.8.1/socket.io.min.js"></script>
         <script>
             const agentId = "{agent_id}";
-            const socket = io(window.location.origin, {{ transports: ["websocket"] }});
+            const nodeId = "{node_id}";
             const canvas = document.getElementById("viewerCanvas");
             const ctx = canvas.getContext("2d");
+            const socket = io(window.location.origin, {{ transports: ["websocket"] }});
 
-            console.log("[Viewer] Canvas initialized for agent:", agentId);
-
-            socket.on("connect", () => {{
-                console.log("[WebSocket] Connected to Borealis server at", window.location.origin);
-            }});
-
-            socket.on("disconnect", () => {{
-                console.warn("[WebSocket] Disconnected from Borealis server");
-            }});
-
-            socket.on("new_screenshot", (data) => {{
-                console.log("[WebSocket] Received screenshot event");
-
-                if (!data || typeof data !== "object") {{
-                    console.error("[Viewer] Screenshot event was not an object:", data);
-                    return;
-                }}
-
-                if (data.agent_id !== agentId) {{
-                    console.log("[Viewer] Ignored screenshot from different agent:", data.agent_id);
-                    return;
-                }}
-
+            socket.on("agent_screenshot_task", (data) => {{
+                if (data.agent_id !== agentId || data.node_id !== nodeId) return;
                 const base64 = data.image_base64;
-                console.log("[Viewer] Base64 length:", base64?.length || 0);
-
-                if (!base64 || base64.length < 100) {{
-                    console.warn("[Viewer] Empty or too short base64 string.");
-                    return;
-                }}
-
-                // Peek at base64 to determine MIME type
-                let mimeType = "image/png";
-                try {{
-                    const header = atob(base64.substring(0, 32));
-                    if (header.charCodeAt(0) === 0xFF && header.charCodeAt(1) === 0xD8) {{
-                        mimeType = "image/jpeg";
-                    }}
-                }} catch (e) {{
-                    console.warn("[Viewer] Failed to decode base64 header", e);
-                }}
+                if (!base64 || base64.length < 100) return;
 
                 const img = new Image();
                 img.onload = () => {{
-                    console.log("[Viewer] Image loaded successfully:", img.width + "x" + img.height);
-
-                    console.log("[Viewer] Canvas size before:", canvas.width + "x" + canvas.height);
-
                     if (canvas.width !== img.width || canvas.height !== img.height) {{
                         canvas.width = img.width;
                         canvas.height = img.height;
-                        console.log("[Viewer] Canvas resized to match image");
                     }}
-
                     ctx.clearRect(0, 0, canvas.width, canvas.height);
                     ctx.drawImage(img, 0, 0);
-
-                    console.log("[Viewer] Image drawn on canvas");
                 }};
-                img.onerror = (err) => {{
-                    console.error("[Viewer] Failed to load image from base64. Possibly corrupted data?", err);
-                }};
-                img.src = "data:" + mimeType + ";base64," + base64;
+                img.src = "data:image/png;base64," + base64;
             }});
         </script>
     </body>
     </html>
     """
 
-@app.route("/api/agent/<agent_id>/screenshot/raw") # Fallback Non-Live Screenshot Preview Code for Legacy Purposes
-def screenshot_raw(agent_id):
-    entry = latest_images.get(agent_id)
-    if not entry:
-        return "", 204
-    try:
-        raw_img = base64.b64decode(entry["image_base64"])
-        return Response(raw_img, mimetype="image/png")
-    except Exception:
-        return "", 204
-
 # ---------------------------------------------
 # WebSocket Events
 # ---------------------------------------------
+@socketio.on("agent_screenshot_task")
+def receive_screenshot_task(data):
+    agent_id = data.get("agent_id")
+    node_id = data.get("node_id")
+    image = data.get("image_base64")
+
+    if not agent_id or not node_id or not image:
+        print("[WS] Screenshot task missing fields.")
+        return
+
+    # Optional: Store for debugging
+    latest_images[f"{agent_id}:{node_id}"] = {
+        "image_base64": image,
+        "timestamp": time.time()
+    }
+
+    emit("agent_screenshot_task", {
+        "agent_id": agent_id,
+        "node_id": node_id,
+        "image_base64": image
+    }, broadcast=True)
+
 @socketio.on('connect_agent')
 def connect_agent(data):
     agent_id = data.get("agent_id")
diff --git a/Launch-Borealis.ps1 b/Launch-Borealis.ps1
index fc5e115..da51ed3 100644
--- a/Launch-Borealis.ps1
+++ b/Launch-Borealis.ps1
@@ -102,7 +102,7 @@ switch ($choice) {
             }
             # React UI Deployment: Create default React app if no deployment folder exists
             if (-not (Test-Path $webUIDestination)) {
-                npx --yes create-react-app "$webUIDestination" --verbose | Out-Null
+                npx --yes create-react-app "$webUIDestination" | Out-Null
             }
             # Copy custom UI if it exists
             if (Test-Path $customUIPath) {