diff --git a/packages/bruno-app/src/components/AiChatSidebar/Popout/index.js b/packages/bruno-app/src/components/AiChatSidebar/Popout/index.js
new file mode 100644
index 000000000..6b05bcb46
--- /dev/null
+++ b/packages/bruno-app/src/components/AiChatSidebar/Popout/index.js
@@ -0,0 +1,23 @@
+import React, { useCallback } from 'react';
+import { useDispatch } from 'react-redux';
+import { closeAiSidebar, dockAiChat } from 'providers/ReduxStore/slices/chat';
+import PopoutWindow from '../PopoutWindow';
+import AiChatSidebar from '../index';
+
+const AiChatPopout = ({ collection }) => {
+ const dispatch = useDispatch();
+
+ const handleClose = useCallback(({ blocked } = {}) => {
+ // Closing the OS window closes the assistant (like undocked devtools).
+ // If window.open was blocked, fall back to the docked sidebar instead.
+ dispatch(blocked ? dockAiChat() : closeAiSidebar());
+ }, [dispatch]);
+
+ return (
+
+
+
+ );
+};
+
+export default AiChatPopout;
diff --git a/packages/bruno-app/src/components/AiChatSidebar/PopoutWindow/index.js b/packages/bruno-app/src/components/AiChatSidebar/PopoutWindow/index.js
new file mode 100644
index 000000000..2bf59511a
--- /dev/null
+++ b/packages/bruno-app/src/components/AiChatSidebar/PopoutWindow/index.js
@@ -0,0 +1,128 @@
+import { useState, useEffect, useRef } from 'react';
+import { createPortal } from 'react-dom';
+import { StyleSheetManager } from 'styled-components';
+
+// Must match the frameName prefix allow-listed in bruno-electron's
+// setWindowOpenHandler, any other window.open is denied there. Each open
+// gets a unique suffix so a remount (e.g. StrictMode's dev double-effect)
+// never receives a handle to the previous, already-closing named window.
+export const AI_POPOUT_WINDOW_NAME_PREFIX = 'bruno-ai-assistant';
+let popoutSeq = 0;
+
+// Copy every stylesheet already loaded in the main window into the popout
+// document. We read cssRules instead of cloning the