Windows Integration
Aartiq for Windows
Windows Integration
Implemented in src/lib/windows-integration.js. It defines twelve actions, a PowerShell and System.Speech layer for volume and voice, and a nine-method bridge. This page previously described a Windows shortcut system that does not exist. The honest version is shorter: the code is largely there, the IPC bridge is wired up and reachable, but nothing on Windows can invoke it from outside the app.
Nothing on Windows can invoke any of these actions
At startup, on Windows only, the app calls registerWindowsProtocol(), which registers aartiq:// as a protocol handler. When Windows activates that protocol it launches a second copy of the executable with the URL as an argument.
The module has a function that would handle exactly that — handleURLSchemeEvent — and handleWindowsShortcutAction, which is what it calls. Both are imported by main.js and neither is ever called. There is no second-instance handler, no requestSingleInstanceLock, and no code that reads process.argv for a URL.
So the twelve actions are reachable from inside the app, through electronAPI.windows.*, and from nowhere else. A Windows protocol activation opens a second instance of the app and the URL is discarded.
The same is true of the Linux page, and for the same reason. On macOS the open-url event does fire, which is why the deep-link reference has working entries and this one does not.
What actually works
Of the twelve actions, 4 reach a real system API and 8 end in a webContents.send on a channel that no renderer subscribes to. The channel name is the only thing that would have connected them, and it is not connected.
4 reach a system API
open-app, volume, voice and copilot. These shell out or call Electron's shell module directly rather than relying on a renderer channel, so they work even though nothing outside the app can trigger them.
8 send into nothing
chat, navigate, search, create-pdf, run-command, screenshot, schedule and ask-ai all report success. None of the eight channel names has a subscriber anywhere in the renderer.
0 reachable from Windows
All twelve, including the four that work, because the OS never delivers the URL that would call them. Fixing the channels without fixing delivery would not change what a user can do.
Actions
Transcribed from the actionHandlers table in src/lib/windows-integration.js. The reach column is derived from whether the handler sends on a channel a renderer subscribes to, which is checked by a test rather than by reading this page.
Open App
Does the workaartiq://open-appCalls shell.openPath. With appPath it opens exactly that path. With appName it guesses C:\Program Files\<name>\<name>.exe and then C:\Program Files (x86)\<name>\<name>.exe, and returns success even if neither exists. There is no args parameter.
appName, appPathSet Volume
Does the workaartiq://volumeRuns a PowerShell script that drives the CoreAudio IAudioEndpointVolume COM interface. The level is clamped to 0-100 and defaults to 50 when absent or unparseable.
level (0-100)Voice
Does the workaartiq://voicecommand=listen runs a single System.Speech recognition with a two-second silence timeout and returns whatever it heard. It is one-shot, not continuous. command=speak speaks the text parameter.
command (listen | speak), text, rate, volume, voiceCopilot
Does the workaartiq://copilotOpens the Copilot application by shell.openPath, falling back to copilot.microsoft.com in the browser. That is the whole implementation. It does not send a prompt anywhere and does not read the prompt parameter the old page documented.
(none read)AI Chat
Sends on a channel with no listeneraartiq://chatSends the message on ai:chat-message. Nothing subscribes to that channel.
messageNavigate
Sends on a channel with no listeneraartiq://navigateSends browser:navigate. Nothing subscribes to that channel.
urlSmart Search
Sends on a channel with no listeneraartiq://searchSends ai:search. Nothing subscribes to that channel.
queryCreate PDF
Sends on a channel with no listeneraartiq://create-pdfSends ai:create-pdf. Nothing subscribes to that channel, and template is forwarded without ever being interpreted.
content, title, templateRun Command
Sends on a channel with no listeneraartiq://run-commandRefuses unless confirm is exactly the string "true", then sends the command on shell:execute. Nothing subscribes to that channel, so nothing executes. Note that confirm is a required gate here, not a convenience that skips a prompt.
command, confirmScreenshot
Sends on a channel with no listeneraartiq://screenshotSends system:screenshot. Nothing subscribes to that channel. The mode and save parameters the old page documented are not read.
(none read)Schedule Task
Sends on a channel with no listeneraartiq://scheduleSends ai:schedule. Nothing subscribes to that channel. There is no action parameter; the old page listed action: pdf, search, chat, scrape, which is not read anywhere.
task, cron, modelAsk & Speak
Sends on a channel with no listeneraartiq://ask-aiSends ai:ask-speaking. Nothing subscribes to that channel.
prompt, model, speakCalling an action from inside the app
This is the only path that works today. It goes through the preload bridge, so it is subject to the same channel problem for the eight actions that only send.
// preload.js exposes the whole Windows surface under electronAPI.windows
const result = await window.electronAPI.windows.executeAction('volume', { level: 40 });
// -> { success: true, volume: 40 }
// generateUrl builds a link without opening it
const url = await window.electronAPI.windows.generateUrl('chat', { message: 'hello' });
// -> "aartiq://chat?message=hello"
// Nothing on Windows can invoke these from outside the app.
await window.electronAPI.windows.executeAction('chat', { message: 'hello' });
// -> { success: true, message: 'Message sent to AI' } …and nothing happensBridge API
The Windows handlers and the preload methods that call them agree on all nine channel names, which is unusual for this codebase — the Linux bridge does not have that property. These are the real method names.
| Channel | Arguments | Effect |
|---|---|---|
| windows:execute-action | action, params | Runs any action above |
| windows:copilot:open | (none) | Opens Copilot |
| windows:voice:listen | params | One-shot dictation |
| windows:voice:speak | text, params | Speech synthesis |
| windows:voice:get-voices | (none) | Installed SAPI voices |
| windows:generate-url | action, params | Builds an aartiq:// URL |
| windows:create-shortcut | name, action, params | Writes a .url file into userData |
| windows:get-shortcuts-list | (none) | A hardcoded list of twelve entries |
| windows:register-protocol | (none) | Registers aartiq:// for this build |
Three shortcut ids in the built-in list do not exist
windows:get-shortcuts-list returns a hardcoded array of twelve entries. Three of its ids are not keys in the actionHandlers table, so passing them straight back returns Unknown action.
Voice
There is no wake word. The previous version of this page listed twelve "Hey Aartiq" phrases and told the reader to install a PowerShell speech module; the string Hey Aartiq does not appear anywhere in this repository, and no module is installed. What exists is a single recognition attempt through .NET's System.Speech.
Recognition
One Recognize() call with a two-second silence timeout, run through PowerShell. It returns one utterance or an empty string. There is no grammar, no keyword list and no continuous mode.
Add-Type -AssemblyName System.Speech
$recognizer = New-Object System.Speech.Recognition.SpeechRecognitionEngine
$recognizer.LoadGrammar((New-Object System.Speech.Recognition.DictationGrammar))
$recognizer.InitialSilenceTimeout = [TimeSpan]::FromSeconds(2)
$recognizer.SetInputToDefaultAudioDevice()
$result = $recognizer.Recognize()
if ($result) { $result.Text } else { '' }Synthesis
SpeechSynthesizer over System.Speech. Rate, volume and voice are passed as parameters to a param block rather than interpolated into the script source, which is why arbitrary text can be spoken safely.
Add-Type -AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.Rate = $Rate
$synth.Volume = $Vol
if ($VoiceName) { $synth.SelectVoice($VoiceName) }
$synth.Speak($TextToSpeak)If the voice query fails, the module returns a hardcoded list of Microsoft David, Zira and Hortense. Those are not read from the system.
Protocol registration
The app registers aartiq:// for itself at startup, so a manual registry entry is only needed to work around that. Read the caveat above before expecting a link to do anything.
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\aartiq]
@="URL:Aartiq Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\aartiq\DefaultIcon]
@="C:\Program Files\Aartiq\aartiq.exe,0"
[HKEY_CLASSES_ROOT\aartiq\shell\open\command]
@="\"C:\Program Files\Aartiq\aartiq.exe\" \"%1\""Single backslashes in the key paths, and a single level of quoting around the executable. The previous version of this page doubled every backslash, which is only correct inside a language string literal and not in a .reg file.
Claims removed from this page
- —The source path src/lib/platform/WindowsIntegration.ts. There is no src/lib/platform directory. The module is src/lib/windows-integration.js.
- —aartiq:// as a way to reach the app from another Windows program. The scheme is registered, but the only handler is app.on('open-url'), which Electron emits on macOS only, and there is no second-instance handler or argv parsing. A Windows protocol activation starts a second process and is discarded.
- —The Power Automate section and the POST http://localhost:3000/api/commands endpoint. No such endpoint exists and port 3000 has never been a listener in this project.
- —Microsoft Copilot as a second assistant. There is no dual chat, no compare mode, no aartiq://dual-chat and no aartiq://compare. The Copilot action launches the Copilot app.
- —Ctrl+Shift+C, Ctrl+D, Ctrl+Shift+P, Ctrl+Alt+E, Ctrl+Alt+R, Ctrl+Alt+T and Ctrl+Alt+D. None of these accelerators is registered anywhere in the project.
- —The Copilot:explain, Copilot:refactor, Copilot:tests and Copilot:doc actions. None exists.
- —The "Hey Aartiq" wake word and all twelve voice phrases. There is no wake word, no hotword detection and no continuous listening in this codebase; the string does not appear.
- —Install-Module SpeechRecognition and Start-SpeechRecognition. No PowerShell module is installed or required. The app shells out to System.Speech, which is part of .NET.
- —The VoiceAttack snippet mixing PowerShell comments with a VBScript body, an undefined {Hwnd} placeholder, and a do-nothing Sleep loop.
- —The configuration keys voice.enabled, voice.wakeWord, voice.voice, voice.rate, copilot.enabled, copilot.defaultMode, automate.httpPort and automate.authToken. No configuration file reads any of them.
- —Windows 12, which does not exist as a release. The page had used it as a search example.