diff --git a/ui/desktop/forge.config.ts b/ui/desktop/forge.config.ts
index 73e2d0745a..c7f9928ef3 100644
--- a/ui/desktop/forge.config.ts
+++ b/ui/desktop/forge.config.ts
@@ -65,7 +65,7 @@ module.exports = {
             target: 'main',
           },
           {
-            entry: 'src/preload.js',
+            entry: 'src/preload.ts',
             config: 'vite.preload.config.ts',
             target: 'preload',
           },
diff --git a/ui/desktop/src/ChatWindow.tsx b/ui/desktop/src/ChatWindow.tsx
index 3e6706326a..4820b88463 100644
--- a/ui/desktop/src/ChatWindow.tsx
+++ b/ui/desktop/src/ChatWindow.tsx
@@ -23,25 +23,6 @@ import { createSelectedModel } from './components/settings/models/utils';
 import { getDefaultModel } from './components/settings/models/hardcoded_stuff';
 import Splash from './components/Splash';
 
-declare global {
-  interface Window {
-    electron: {
-      stopPowerSaveBlocker: () => void;
-      startPowerSaveBlocker: () => void;
-      hideWindow: () => void;
-      createChatWindow: () => void;
-      getConfig: () => { GOOSE_PROVIDER: string };
-      logInfo: (message: string) => void;
-      showNotification: (opts: { title: string; body: string }) => void;
-      getBinaryPath: (binary: string) => Promise<string>;
-      app: any;
-    };
-    appConfig: {
-      get: (key: string) => any;
-    };
-  }
-}
-
 export interface Chat {
   id: number;
   title: string;
diff --git a/ui/desktop/src/LauncherWindow.tsx b/ui/desktop/src/LauncherWindow.tsx
index a4723a6532..ab1ae24503 100644
--- a/ui/desktop/src/LauncherWindow.tsx
+++ b/ui/desktop/src/LauncherWindow.tsx
@@ -1,18 +1,5 @@
 import React, { useRef, useState } from 'react';
 
-declare global {
-  interface Window {
-    electron: {
-      logInfo(msg: string): unknown;
-      on(channel: string, arg1: (event: any, message: any) => void): unknown;
-      stopPowerSaveBlocker(): unknown;
-      startPowerSaveBlocker(): unknown;
-      hideWindow: () => void;
-      createChatWindow: (query: string) => void;
-    };
-  }
-}
-
 export default function SpotlightWindow() {
   const [query, setQuery] = useState('');
   const inputRef = useRef<HTMLInputElement>(null);
diff --git a/ui/desktop/src/components/Input.tsx b/ui/desktop/src/components/Input.tsx
index adeb6764fa..24d00f7a85 100644
--- a/ui/desktop/src/components/Input.tsx
+++ b/ui/desktop/src/components/Input.tsx
@@ -10,14 +10,6 @@ interface InputProps {
   onStop?: () => void;
 }
 
-declare global {
-  interface Window {
-    electron: {
-      selectFileOrDirectory: () => Promise<string | null>;
-    };
-  }
-}
-
 export default function Input({
   handleSubmit,
   disabled = false,
diff --git a/ui/desktop/src/main.ts b/ui/desktop/src/main.ts
index 003e3f41d6..3ceaf762bf 100644
--- a/ui/desktop/src/main.ts
+++ b/ui/desktop/src/main.ts
@@ -98,7 +98,7 @@ const createLauncher = () => {
     frame: false,
     transparent: false,
     webPreferences: {
-      preload: path.join(__dirname, 'preload.js'),
+      preload: path.join(__dirname, 'preload.ts'),
       additionalArguments: [JSON.stringify(appConfig)],
       partition: 'persist:goose',
     },
diff --git a/ui/desktop/src/preload.js b/ui/desktop/src/preload.js
deleted file mode 100644
index d78ae3bb67..0000000000
--- a/ui/desktop/src/preload.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const { contextBridge, ipcRenderer } = require('electron')
-
-const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}');
-
-contextBridge.exposeInMainWorld('appConfig', {
-  get: (key) => config[key],
-  getAll: () => config,
-});
-
-contextBridge.exposeInMainWorld('electron', {
-  getConfig: () => config,
-  hideWindow: () => ipcRenderer.send('hide-window'),
-  directoryChooser: (replace) => ipcRenderer.send('directory-chooser', replace),
-  createChatWindow: (query, dir, version) => ipcRenderer.send('create-chat-window', query, dir, version),
-  logInfo: (txt) => ipcRenderer.send('logInfo', txt),
-  showNotification: (data) => ipcRenderer.send('notify', data),
-  createWingToWingWindow: (query) => ipcRenderer.send('create-wing-to-wing-window', query),
-  openInChrome: (url) => ipcRenderer.send('open-in-chrome', url),
-  fetchMetadata: (url) => ipcRenderer.invoke('fetch-metadata', url),
-  reloadApp: () => ipcRenderer.send('reload-app'),
-  checkForOllama: () => ipcRenderer.invoke('check-ollama'),
-  selectFileOrDirectory: () => ipcRenderer.invoke('select-file-or-directory'),
-  startPowerSaveBlocker: () => ipcRenderer.invoke('start-power-save-blocker'),
-  stopPowerSaveBlocker: () => ipcRenderer.invoke('stop-power-save-blocker'),
-  getBinaryPath: (binaryName) => ipcRenderer.invoke('get-binary-path', binaryName),
-  on: (channel, callback) => ipcRenderer.on(channel, callback),
-  off: (channel, callback) => ipcRenderer.off(channel, callback)
-});
diff --git a/ui/desktop/src/preload.ts b/ui/desktop/src/preload.ts
new file mode 100644
index 0000000000..51105a5788
--- /dev/null
+++ b/ui/desktop/src/preload.ts
@@ -0,0 +1,77 @@
+import Electron, { contextBridge, ipcRenderer } from 'electron';
+
+const config = JSON.parse(process.argv.find((arg) => arg.startsWith('{')) || '{}');
+
+// Define the API types in a single place
+type ElectronAPI = {
+  getConfig: () => Record<string, any>;
+  hideWindow: () => void;
+  directoryChooser: (replace: string) => void;
+  createChatWindow: (query?: string, dir?: string, version?: string) => void;
+  logInfo: (txt: string) => void;
+  showNotification: (data: any) => void;
+  createWingToWingWindow: (query: string) => void;
+  openInChrome: (url: string) => void;
+  fetchMetadata: (url: string) => Promise<any>;
+  reloadApp: () => void;
+  checkForOllama: () => Promise<boolean>;
+  selectFileOrDirectory: () => Promise<string>;
+  startPowerSaveBlocker: () => Promise<number>;
+  stopPowerSaveBlocker: () => Promise<void>;
+  getBinaryPath: (binaryName: string) => Promise<string>;
+  on: (
+    channel: string,
+    callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void
+  ) => void;
+  off: (
+    channel: string,
+    callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void
+  ) => void;
+};
+
+type AppConfigAPI = {
+  get: (key: string) => any;
+  getAll: () => Record<string, any>;
+};
+
+const electronAPI: ElectronAPI = {
+  getConfig: () => config,
+  hideWindow: () => ipcRenderer.send('hide-window'),
+  directoryChooser: (replace: string) => ipcRenderer.send('directory-chooser', replace),
+  createChatWindow: (query?: string, dir?: string, version?: string) =>
+    ipcRenderer.send('create-chat-window', query, dir, version),
+  logInfo: (txt: string) => ipcRenderer.send('logInfo', txt),
+  showNotification: (data: any) => ipcRenderer.send('notify', data),
+  createWingToWingWindow: (query: string) => ipcRenderer.send('create-wing-to-wing-window', query),
+  openInChrome: (url: string) => ipcRenderer.send('open-in-chrome', url),
+  fetchMetadata: (url: string) => ipcRenderer.invoke('fetch-metadata', url),
+  reloadApp: () => ipcRenderer.send('reload-app'),
+  checkForOllama: () => ipcRenderer.invoke('check-ollama'),
+  selectFileOrDirectory: () => ipcRenderer.invoke('select-file-or-directory'),
+  startPowerSaveBlocker: () => ipcRenderer.invoke('start-power-save-blocker'),
+  stopPowerSaveBlocker: () => ipcRenderer.invoke('stop-power-save-blocker'),
+  getBinaryPath: (binaryName: string) => ipcRenderer.invoke('get-binary-path', binaryName),
+  on: (channel: string, callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void) => {
+    ipcRenderer.on(channel, callback);
+  },
+  off: (channel: string, callback: (event: Electron.IpcRendererEvent, ...args: any[]) => void) => {
+    ipcRenderer.off(channel, callback);
+  },
+};
+
+const appConfigAPI: AppConfigAPI = {
+  get: (key: string) => config[key],
+  getAll: () => config,
+};
+
+// Expose the APIs
+contextBridge.exposeInMainWorld('electron', electronAPI);
+contextBridge.exposeInMainWorld('appConfig', appConfigAPI);
+
+// Type declaration for TypeScript
+declare global {
+  interface Window {
+    electron: ElectronAPI;
+    appConfig: AppConfigAPI;
+  }
+}
diff --git a/ui/desktop/src/types/electron.d.ts b/ui/desktop/src/types/electron.d.ts
deleted file mode 100644
index ef2a79d6f2..0000000000
--- a/ui/desktop/src/types/electron.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-interface IElectronAPI {
-  hideWindow: () => void;
-  createChatWindow: (query?: string, dir?: string, version?: string) => void;
-  getConfig: () => {
-    GOOSE_SERVER__PORT: number;
-    GOOSE_API_HOST: string;
-    apiCredsMissing: boolean;
-    secretKey: string;
-  };
-  directoryChooser: () => void;
-}
-
-declare global {
-  interface Window {
-    electron: IElectronAPI;
-  }
-}