<!-- OpenSmartRoute: Desktop app. https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/DESKTOP -->
# Desktop app

OpenSmartRoute Desktop puts your router one keystroke away in every application on your computer. Press
**Ctrl+Shift+Space** (**⌘⇧Space** on a Mac) and a small bar opens over whatever you are doing - Word, Outlook,
Slack, Teams, VS Code, Notes, a terminal, a browser. Type a request, press Enter, and the router picks the model,
answers, and tells you which model it was, what it cost and how long it took. The app also
installs the [browser extension](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/EXTENSION.md) into every browser on the machine and keeps itself up to date.

Windows, macOS and Linux. Download from the [product page](https://opensmartroute.ai/desktop) or the
[downloads page](https://opensmartroute.ai/downloads); the current build, its size and SHA-256 are listed there.

## Install

| System | File | Notes |
|---|---|---|
| Windows 10/11 (x64, ARM) | `OpenSmartRoute-<version>-win-x64.exe` / `-win-arm64.exe` | Installs for you, no administrator rights, and starts when it is done. Run as administrator and choose *Anyone who uses this computer* (or `/S /ALLUSERS`) to install for every account - see [Installing for an organisation](#installing-for-an-organisation). `-win-x64-portable.exe` runs without installing (and does not self-update) |
| Windows 10 (1809+) / 11 (x64, ARM) | `OpenSmartRoute-<version>-win-x64-native.exe` / `-win-arm64-native.exe` | The [native Windows app](#the-native-windows-app): the same bar and workspace in WPF, Mica and Acrylic on Windows 11. Installs for you, no administrator rights; `/S` silently, `/S /ALLUSERS` from an elevated prompt for every account. `-native-portable.exe` is the bare self-contained exe: put it where you like and run it |
| macOS 12+ (Apple silicon, Intel) | `OpenSmartRoute-<version>-mac-arm64.dmg` / `-mac-x64.dmg` (or `.zip`) | Drag to Applications. The app lives in the menu bar; a Dock icon appears only while the main window is open. Administrators: the `.pkg` installs to Applications for everyone, and the `.mobileconfig` grants the two privacy permissions through your MDM |
| macOS 15+ (Apple silicon, Intel) | `OpenSmartRoute-<version>-mac-universal-native.dmg` (or `.zip`) | The [native Mac app](#the-native-mac-app): the same bar and workspace as SwiftUI, one universal binary of about a megabyte, Liquid Glass on macOS 26. Drag to Applications |
| Linux | `.AppImage` (any distribution), `.deb` (Debian, Ubuntu), `.rpm` (Fedora, openSUSE) | The AppImage self-updates; `.deb` and `.rpm` update through your package manager |

The first run opens a short welcome: what the app does, **Add** the browser extension, **Sign in** to a
workspace, **Check my writing as I type** where this system can read a focused field, and **Start when I sign in**.
Every step can be done later from Settings. After that the app sits in the
system tray (Windows, Linux) or menu bar (macOS) and waits for the shortcut.

Until code signing is in place the installers are unsigned, and the first launch needs one confirmation:

- **Windows:** SmartScreen shows *Windows protected your PC*. Choose *More info*, then *Run anyway*.
- **macOS:** the app is refused with *Apple could not verify "OpenSmartRoute" is free of malware*. Open **System
  Settings > Privacy & Security**, scroll to the notice about OpenSmartRoute and choose **Open Anyway**; on macOS 14
  and earlier, Control-click the app in Applications and choose **Open**. It opens normally from then on.

Check the SHA-256 on the downloads page if you want to be sure of the file.

## The main window

Two surfaces, for two ways of working. The **main window** is the app itself - a normal, resizable window with a
taskbar entry, an application menu, a title that names the conversation in view, and a size, place and
maximised state it remembers between runs. Open it from the tray (*Open OpenSmartRoute*), by double-clicking the
tray icon, from the Dock on macOS (the icon appears while the window is open; right-click it for *Ask from Anywhere*,
*New Conversation* and *Settings…*), from the taskbar's Jump List on Windows (right-click the pinned icon: the same
three tasks), or with an `osr://open` link.

The **sidebar** on the left holds **New chat**, the five sections, and every past conversation, grouped by day
(Today, Yesterday, This week ...) with the time and how many turns each has. A search field narrows the list by
title or content. Click a conversation to carry on where it stopped; double-click it (or the pencil) to rename it
in place; the download icon exports it as a Markdown file wherever you choose (who said what, the target and the
price under each answer - written from what the window shows, nothing uploaded); the bin asks once, in place,
before removing it. Conversations live in your workspace: the same list
appears in the browser extension's side panel and on the dashboard's Memory page, a thread started there opens
here (marked *from the browser extension*), a rename or a deletion reaches every client, and a reinstall loses
nothing. A copy of the recent ones is kept on this computer too (Settings › *Keep past conversations*), so the
list is there before the workspace answers. The footer shows the workspace you are connected to and opens
Settings. **Ctrl+B** (⌘B) folds the sidebar away.

**Chat** is where the window opens.

- **The conversation** shows each answer as Markdown - code blocks carry a copy button - followed by one line with
  what the router decided: which target answered, the provider behind it, whether it fell back from another target,
  the cost, the time taken and how many prompt tokens were trimmed. **Copy**, **Regenerate** and the two rating
  buttons sit on the same row; a rating goes back to the router as feedback, which is how it learns what works for
  you.
- **The thread is the platform's.** Only your new question travels; the platform prepends the conversation so far
  (the last twelve turns verbatim, everything older as a rolling summary), so a long conversation never outgrows
  the model and never re-sends itself. When a question reads like a change of subject, a line under the answer
  says so and offers **Move to a new chat**, which lifts that exchange into a conversation of its own; when you
  return to a thread after hours, a line above it says how long ago it was and offers to start fresh instead.
- **It remembers what you tell it.** Say *my name is Priya*, *I work at Northwind*, *we use Rust*, *answer
  briefly*, *remember that the sprint ends Friday* and a small line under the answer confirms what was kept;
  later questions - in this app, the extension or the playground - get that context without repeating it. *Forget
  that I work at Northwind* removes it. Settings › *Memory* lists every remembered fact with a bin, an *Add* field
  and the switch that turns the whole thing off; nothing is ever inferred, only what you said.
- **What matters most** - *Prefer* Balanced, Cheapest, Best quality or Fastest - is in the header and applies to the
  next question.
- **Enter** (or the arrow button) sends, **Shift+Enter** adds a line. **Stop** (the same button, or **Esc**)
  interrupts an answer that is still streaming.

**Models** is the catalogue the router chooses from, so you can see the choice before you ask. Every target your
workspace can reach, with the list price per million tokens in and out, the context window, the typical reply
time, its benchmark score or quality prior, and - once you have used it - how many requests it took, how many
succeeded and what they cost. Search by name or vendor, and order by most capable, cheapest, fastest or most
used. A thinking model is marked, and so is one turned off for the workspace.

**Usage** is what your workspace counted - every client together: this app, the browser extension, the API, the
playground. Requests over the last 7, 30 or 90 days (how many answered without an error, what they cost the
providers, how many came from this app), one bar per day, the split by app and by target, and the newest requests
one by one with when, from where, what answered, the cost, the time taken, whether it went through and how you
rated it. The same figures as the workspace dashboard, read live from `GET /api/v1/usage` and `GET /api/v1/activity`;
the trace of each request stays on the dashboard.

**Writing** is the writing assistant as a page: on or off, how many checks and fixes it has done, autopilot, what
it checks, which kinds of app it watches, and every application it has met with its own switch - the same
controls as Settings › *Writing assistant* (see below), arranged so "is it watching Word?" is one glance.

**Overview** is the workspace and plan you are connected to, the requests, tokens and spend your workspace counted
over the last 30 days across every client (the same figures as *Usage*, so they do not change when this computer's
history is trimmed or cleared), how many conversations are kept here, the most recent conversations, which targets
actually answered your questions as a share of the total, and what the catalogue currently holds - the cheapest and
the fastest target your workspace can reach. Without a workspace it falls back to the answers kept on this computer
and says so.

### Menu and shortcuts

The application menu (Alt shows it on Windows and Linux; it is always in the menu bar on macOS) carries the
shortcuts a desktop app is expected to have:

| Menu | Item | Shortcut |
|---|---|---|
| File | New Conversation | Ctrl+N / ⌘N |
| File | Ask from Anywhere (the command bar's global shortcut) | Ctrl+Shift+Space / ⌘⇧Space by default |
| File | Settings… | Ctrl+, / ⌘, |
| File | Quit | Ctrl+Q / ⌘Q |
| Edit | Undo, Redo, Cut, Copy, Paste, Select All | the usual |
| Edit | Find Conversation… (focuses the sidebar search) | Ctrl+K / ⌘K |
| Edit | Focus Composer | Ctrl+L / ⌘L |
| View | Chat, Models, Usage, Writing, Overview | Ctrl+1 … 5 / ⌘1 … 5 |
| View | Toggle Sidebar | Ctrl+B / ⌘B |
| View | Appearance (Follow System, Light, Dark), zoom, full screen | |
| Help | Documentation, Open Dashboard in Browser, Copy Diagnostics, Check for Updates…, About | F1 for the documentation |

**Right-click** works the way it does in every other app. On a field it offers Undo, Redo, Cut, Copy, Paste, Paste
and Match Style, Delete and Select All, greyed when the field does not allow them; over a word the system spell
checker underlined (Windows and macOS - the app uses the checker your system already has, so nothing is downloaded
and no text leaves the computer for it) the suggestions come first, with *Add to dictionary*; on a selection in an
answer it offers Copy, *Ask about "…"* (opens the command bar with the selection as the question) and *Search the web
for "…"*; on a link, *Open link in browser* and *Copy link address*. Links never open inside the app.

The **command bar** below is the other surface: it opens over whatever you are doing, answers, and gets out of
the way.

## The command bar

- **Open** it with the shortcut from any app, from the tray menu (*Ask*), or by opening an `osr://` link. If
  another program already holds Ctrl+Shift+Space the app falls back to Ctrl+Alt+Space and says so in Settings.
  The first open shows a one-line coach mark - *two ways to ask*: type and press Enter, or select text in the app
  you are in (it is named) and press the shortcut (shown as the real keys) - and the empty bar offers five
  starters that each do a whole task: **Fix the text I copied**, **Summarise what I copied** and **Explain what I
  copied** attach whatever you copied last and send it with the right instruction (if nothing is copied the bar
  says so and how to copy), **Write an email** and **Translate something** put an opening in the field to finish.
  A signed-out bar says so up front with a **Sign in** button; a signed-in one names the workspace in the footer.
- **Type** a request. While you type, the same checks the browser extension runs happen on this computer: the
  verdict line says *Nothing flagged*, *2 personal details in your text* or *An API key is in your text*, with the
  token count and whether a quick, standard or thinking model is enough. **Redact** swaps personal details for
  placeholders such as `<EMAIL_1>` before anything is sent. *Nothing flagged* means no personal-detail patterns
  were found; names, addresses and free-text facts are not detected.
- **Choose what matters** with the four chips after *Prefer*: **Balanced** (default), **Cheapest**, **Best quality**,
  **Fastest**. They set the router's objective for the next request.
- **Your own commands** (Settings › Commands) sit next to the starters on the empty bar and next to the quick actions
  under attached text: prompts you saved once - *Reply in my tone*, *Turn into a post* - with `{{selection}}` where
  the text goes (`{{title}}` for the window's title, `{{app}}` for the app in front and `{{language}}` work too; a
  prompt that names no text gets it quoted under it). Chosen with nothing attached, a command that works on text
  takes what you copied last, like the starters do. The list is the same one the [browser extension](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/EXTENSION.md)
  offers on selected text; a command that uses the browser-only `{{page}}` or `{{url}}` stays there.
- **Enter** or the arrow button sends, **Shift+Enter** adds a line, **Esc** steps back one level at a time (stops a streaming answer,
  clears the draft, clears the thread, closes the bar). **New chat** starts a fresh thread; the bar keeps the
  thread while it is open and says *Draft kept from last time* when it comes back after you switched windows.
- **Answers render as Markdown** - headings, lists, tables and code blocks with their own *Copy* - never raw HTML.
  The status line says *Picking a model…* and then *Answering on llm-small* as soon as the router has decided -
  before the first word - while a caret follows the text as it streams; a thinking model shows *is thinking* and a
  glimpse of its reasoning until the answer proper begins. A **Stop** button sits in the status line throughout;
  what arrived stays, marked *stopped*.
- **Every answer** carries one line with the decision under it - *answered by llm-small · azure/gpt-4.1-mini ·
  $0.0004 · 780 ms* (the target, the provider and upstream model that ran it, the cost, the time; *after a
  fallback* when the first target failed, *N tokens trimmed* when the prompt was compacted) - with **Copy**,
  **Regenerate** on the last answer, **Paste into …** and thumbs up / down. Your thumbs are outcome feedback: the
  router learns from them. On the hosted platform the target is a link that opens the request's trace on the
  dashboard; every call the app makes carries a request id and a W3C `traceparent` and the workspace tenant, so
  each one is a traceable row with `app: desktop`. Answers from a self-hosted router on this machine show *$0 · on
  this machine* instead of a price.
- **History** (the clock icon, or Ctrl+H) lists past conversations saved on this computer and brings one back;
  Settings › Command bar decides how many are kept (0 keeps none) and clears them.
- **Pin** (the pin icon) keeps the bar open when another window takes focus; otherwise it steps aside on blur and
  your draft and thread are waiting when you open it again.
- The bar follows the light or dark appearance of your system, or the look you choose in Settings › Appearance.
  Every window wears the same editorial palette as the site and the browser extension: warm cream (light) or
  charcoal (dark) surfaces and one warm *clay* accent on the things you can press - the primary button, switches,
  links and focus rings. The tokens are generated at build time from the extension's `brand.ts`
  (`dist/tokens.css`), so the three products never drift apart.
- When something fails the status line says what happened in plain words and offers the one action that helps -
  *Try again* (the question goes back into the field), *Connect* (the key expired), *See plans* (the plan's monthly
  allowance is used up), *Open settings* (the platform could not be reached).

## Working inside the app in front

When the bar opens it asks the operating system which application is in front and reads the text you have
selected there (Settings › *Read what I selected when the bar opens*, on by default). The app is recognised by the
name its maker gave it - *Word*, *VS Code*, *Slack*, *Chrome* - with its own icon, and the document, page or
conversation the window title names (*Q3 plan.docx*, *Inbox - Gmail*); Store apps are named by their window, not by
the host process. The selection appears as a card - *240 chars · selected in Word · Q3 plan.docx* - with one-click
actions that fit the app: in an editor **Explain code**, **Find bugs**, **Add comments**, **Write tests**,
**Refactor**; in a mail client **Draft a reply**, **Summarise**, **More polite**; in Slack, Teams and other chat
apps **Reply** and **Recap**; in documents and notes **Rewrite**, **Fix grammar**, **Shorten**, **Summarise**,
**Expand**; everywhere else **Explain**, **Summarise**, **Rewrite**, **Fix grammar**, **Shorten**, **Translate**.
While the answer streams a greyed *Paste into Word when done* chip says
paste-back will be possible; every finished answer then offers **Paste into Word** (or whichever app it was, with
its icon), which puts the answer where your cursor was. Pasting is always an explicit click; nothing is typed into
another app on its own. If you select new text while something attached is still unused, the bar asks before
swapping it.

| Where | What happens |
|---|---|
| Word, Outlook, Notes, mail and documents | Selection read, answer pasted back at the cursor |
| Slack, Teams | A thread or message turned into a decision or action items, pasted into the composer |
| VS Code and other editors | Explain an error or a function, write the test, paste it back |
| Terminals (Windows Terminal, PowerShell, iTerm, GNOME Terminal…) | The bar never sends Ctrl+C to a terminal - it would interrupt the running program - so nothing is read there; type or paste the command output instead. Pasting back works |
| Browsers | The selection is read like any other app; on the chat sites the browser extension already sits under the composer |

*Attach the clipboard when the bar opens* (off by default) offers whatever you copied last as context, on this
computer only, until you send.

Requirements per system: Windows needs nothing. macOS asks once for the **Accessibility** permission: the welcome
window and Settings have an **Allow** button that opens System Settings › Privacy & Security › Accessibility on the
right pane and tick themselves once the permission is there. Linux on X11 needs
`xdotool`; on Wayland it needs `wl-clipboard` (to read the highlighted text - no key is sent) and `wtype` (to paste
back), and `kdotool` (KDE), `hyprctl` (Hyprland) or `swaymsg` (Sway) names the app in front - elsewhere the chip
says *selected text* and the paste button says **Paste back**. Settings names exactly what is missing; the bar
itself works everywhere.

## The writing assistant

It is off until you ask for it: the first run offers it as a step, and Settings › *Check my writing as I type, in
every app* (or the **Writing assistant** entry in the tray menu) turns
on a checker that follows you into whatever you are typing in - a mail, a chat message, a document, a form in the
browser. It watches the text control that has the keyboard focus through the operating system's accessibility
layer (UI Automation on Windows, the AX API on macOS, AT-SPI on Linux - the same way a screen reader does; no key
is ever pressed and no text is typed on its own). When you pause for a second the text is checked **on this
computer**:

- **Spelling** with the dictionary you already have - the Windows spell checker (every language installed in
  Windows, your custom words included) or the macOS spell checker; on Linux `hunspell` or `aspell` when one is
  installed. Nothing is bundled and no word list is guessed.
- **Grammar** with a deterministic rule set that a careful reader would apply without context: a doubled word,
  two spaces, a space before a comma, a missing one after a full stop, a sentence starting in lower case, a lone
  *i*, *a* / *an* (silent letters and initialisms included: *an hour*, *a user*, *an MRI*), *alot*, *could of*,
  *your welcome*, *their is*, *its a*, missing apostrophes (*dont*, *im*, *youre*), day and month names.
- **Style**, as advice only: overlong sentences, repeated punctuation.

A small badge appears at the bottom-right corner of the field - a count while there is something to fix, a tick
while the text is clean - and opens into the list: each item shows the change, other spellings the dictionary
offered, **Apply** and **Ignore** (a word you ignore is remembered). **Fix all** applies every fix at once. Each fix
replaces just its own slip, in place: the rest of the document, its formatting, your caret and the app's undo
history stay as they were (Windows selects the slip through UI Automation and pastes over the selection; Linux
writes the range through the accessibility API, no key sent; macOS walks the caret to the slip with the arrow keys -
System Events can read a selection range but not set one - selects it with Shift-Right, checks that what is selected
is the slip and writes the fix through the accessibility API; an app that lets the range be selected but not
written - Office on macOS - gets the fix pasted over that selection). A document, a note or a mail is never
rewritten whole: where none of that works the badge says the fix failed rather than flatten your formatting. In a
plain control - a chat composer, a form field, a plain-text editor - the corrected text may go in whole through the
accessibility layer when the control takes a value; elsewhere, and only when *Replace text by pasting* is on, the
app receives Select all + Paste. Your clipboard is restored afterwards either way. **Improve with AI** hands the
text to the command bar with the app's quick actions
(*Fix grammar*, *Rewrite*, *Shorten*, ...) - the only path on which the text leaves this computer, and only through
your own workspace's router; the answer's button reads **Replace in** followed by the app's name (*Replace in Word*) and puts the answer in place of the text
the assistant checked (not at the caret, as *Paste into* does for a selection).

What is never read: password and PIN fields, read-only text, address and search bars, terminals, the app's own
windows, a document longer than 20,000 characters (its length is read, not its text), and any kind of app you switch
off (Settings › *Where*: browsers, code editors, mail, chat, office, notes,
other). Code editors are off by default. Every control the system reports as text is watched - Word, PowerPoint and
Outlook documents and composers, Notes, Mail, the text fields and rich editors of Chrome, Edge, Safari and Firefox,
the composers of Teams, Slack and Discord; Chromium and Electron apps build their accessibility tree only when a
client asks, so the first check in such an app can take a moment longer. Under *Apps*, Settings lists **every application the assistant has met** -
its kind, how many checks and fixes it did there, when it last saw it - each with its own switch that wins over the
kind (so code editors can stay off while one particular editor is on, or mail can stay on while one mail client is
off); *Off for this app* on the badge writes that switch from where you are, and *follow its kind* takes it back. The
language follows the text (or the one you fix in Settings); the pause is adjustable. On Linux the field is read
through AT-SPI with the `python3-pyatspi` bindings (the package your desktop's screen reader uses; `python3-atspi`
on some distributions) and accessibility switched on for the desktop - Settings names what is missing when it
cannot read; the shortcut and the bar work regardless.

**Autopilot** (Settings › *Autopilot*, off by default) applies the sure fixes on its own once you pause, so you keep
typing and the slips just disappear: *Fix spelling automatically* takes a misspelling the dictionary corrects with
one or two letters ("teh" → "the", "ocupation" → "occupation"; a word the dictionary would swap for a different word
is left for you), *Fix spelling and grammar automatically* adds the rule set (doubled words, spacing, capitals, *a*
/ *an*, contractions). Style advice is never applied on its own. The badge then reads **N fixed** and opens to
**Undo**; a fix you take back is never applied automatically again in that field, and at most two rounds run on
one pause so a fix can uncover the next without ever looping.

## Connect your workspace

The on-device checks work without an account. To ask through your router, press **Sign in** in the welcome, the
bar or Settings › Workspace: the browser opens a sign-in page for this computer, you approve it, and the app
receives a workspace key. Settings shows the code with a **Copy** button, an *Open the page again* link in case
the tab was closed, and how long the code is still valid. From then on answers come from your workspace's own
models, prices and rules, and every request appears in your [dashboard](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/PLATFORM.md#13-dashboard) with its trace.

The app talks to OpenSmartRoute (`https://opensmartroute.ai`) unless you tell it otherwise, and telling it
otherwise takes a licence. *On-premises router or a key* (Settings › Workspace) holds the platform address, the
API style and the tenant for a router you run yourself - `osr serve` on this machine (a **Local osr serve** preset
points the app at `http://127.0.0.1:8765` in one click), a self-hosted platform, a proxy in your network - and a
field to paste a key directly instead of signing in. Any address other than OpenSmartRoute's is an **on-premises
router**, and an on-premises router needs a workspace on a Pro plan or higher: sign in to OpenSmartRoute with such
a workspace and the fold's *On-premises licence* row turns to *Licensed* on this computer; until then it reads *Pro
required* with a link to the plans, the router switch, the address and the API style refuse to change, a pasted
serve token is refused, and a router set up earlier gets no answers - the bar says why and Settings offers **Use
OpenSmartRoute** to come back. The licence is kept sealed next to the key and stays through sign-outs; a later
sign-in to OpenSmartRoute with a workspace below Pro withdraws it. An address pinned by your organisation's
[managed file](#managed-settings-for-organisations) needs no licence. A platform address that uses plain `http`
to anything but this machine gets a warning: the key would travel unencrypted. **Sign out** removes the key from
this computer. The key is stored encrypted with your account's own secret store (Windows DPAPI, the macOS Keychain,
the Linux keyring) so a copied file is worthless on another machine or account; where no keyring exists it stays
in a file readable by your user only.

## Add the extension to every browser

**Add to my browsers** (welcome, Settings › Browser extension, tray menu) finds every browser that has a profile
on this machine - Chrome, Edge, Brave, Chromium, Vivaldi, Arc, Firefox, Safari - and registers the browser
extension the way each browser allows:

| Browser | What you will see |
|---|---|
| Chrome, Edge, Brave, Chromium, Vivaldi, Arc | The next time the browser starts it asks once, *Enable OpenSmartRoute?* Accept and the extension's welcome page opens |
| Firefox | Installed silently from the signed package; on Linux the app shows the system-wide path an administrator has to write instead |
| Safari | Opens the App Store listing when there is one |

Settings lists the outcome per browser. **Remove** undoes everything the app wrote, and so does uninstalling the
app on Windows (the uninstaller takes the registrations back before it removes the files; an update leaves them in
place). For a browser whose store listing is not available, the button does everything a program is allowed to do
on a personal computer: it downloads the package, unpacks it into the app's own folder, puts that folder on the
clipboard and opens the browser on `chrome://extensions` (`edge://extensions`). Two clicks remain for you - switch
on **Developer mode**, click **Load unpacked** and paste the folder - because Chrome and Edge only install an
unlisted extension silently on a managed device (domain-joined or enrolled), where an administrator's
`ExtensionInstallForcelist` policy does it.

## Settings

Open Settings from the gear in the bar, the tray menu or `osr://settings`.

| Section | What it holds |
|---|---|
| **Workspace** | Sign in / Sign out, the connected workspace, the device code with Copy and *Open the page again*; *Price my draft while I type* - off: nothing leaves this computer until you press Enter; on: your workspace prices the draft as you type (the text is not stored); *On-premises router or a key* - the *On-premises licence* row (Licensed / Pro required / Managed), the OpenSmartRoute / Local osr serve preset, platform address, API style, tenant, a pasted key |
| **Command bar** | The shortcut (press the keys you want; a combination another app holds is refused, the old one stays and the note offers the fallback in one click; **Reset** returns to the default), **Appearance** (System / Light / Dark), *Start when I sign in*, *Keep the bar open when I switch windows*, *Read what I selected when the bar opens* (with **Allow** on macOS), *Attach the clipboard when the bar opens*, *Keep past conversations* (how many, and **Clear**) |
| **Commands** | **Answer in** - the language every answer is asked for (empty: the language of the question; it travels as a system line in front of each request) - and your own commands: name, prompt with `{{selection}}` and friends, where each appears (selected text in the extension, the extension's writing widget, the desktop bar); **New command**, **Add three examples**, edit and delete. Up to 50, kept in `settings.json` |
| **Browser extension** | Add / Remove, one line per browser with what happened |
| **Writing assistant** | *Check my writing as I type, in every app*; *Autopilot* (off, spelling, spelling and grammar); what to check (spelling, grammar, style), where (browsers, code editors, mail, chat, office, notes, other), the *Apps* list with one switch per application the assistant has met, the pause before checking, the language, *Replace text by pasting when an app cannot be edited directly*, and the words you told it to accept |
| **Updates and about** | The installed version next to *Check now*, *Download*, *Restart to update* and *What's new*; *Download updates automatically*; **Copy diagnostics**; a *Self-hosted update server* fold that shows the effective feed and warns when it is not on the platform's host |

## Updates

The app checks for a new version 30 seconds after it starts and every six hours. With *Download updates
automatically* (default) the new version downloads in the background; a notification and the first line of the
tray menu then offer **Restart to update**. Nothing restarts on its own - a downloaded update is applied when you
choose to restart or when you quit. Development builds, the Windows portable exe and `.deb` / `.rpm` installs do
not self-update; the Updates section says why. The same goes for the macOS build until it is signed with an Apple
Developer ID: macOS only lets an app replace itself with one carrying the same signature, so the Updates section
reads *not signed with an Apple Developer ID* and the downloads page is the way to a new version.

Self-hosted deployments point *Self-hosted update server* at any web folder that holds the installers and the
`latest*.yml` files the build produces (see the [deployment guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/INSTALL.md)). After an update the bar says once
*Updated to x.y.z* with a *What changed* link.

### Updating without the internet, or across a fleet

You never have to wait for the in-app update: **download the installer for the new version and run it over the
one you have**. It keeps your settings, the workspace you connected, your chat history and the browser
extensions, replaces the application, and leaves a single entry in *Apps & features* - no need to uninstall
first. This is the way to update an air-gapped machine, and the way to roll a version out with your own
deployment tooling: copy the installer and run it with `/S` (Windows), install the `.deb` / `.rpm` with your
package manager, or replace the application bundle on macOS.

### Managed settings for organisations

An administrator pins settings for every account on a machine with one JSON file the app reads and never writes:
`%ProgramData%\OpenSmartRoute\managed.json` on Windows, `/Library/Application Support/OpenSmartRoute/managed.json`
on macOS, `/etc/opensmartroute/managed.json` on Linux (or the path in `OSR_DESKTOP_MANAGED_SETTINGS`). Drop it
with Intune, Jamf, Ansible or a login script; the app re-reads it on every use, so a change lands without a
restart, and removing the file gives people their own values back. The keys it may set: `platformUrl`,
`apiPrefix`, `tenant`, `policy` (`local` / `quote`), `autoUpdate`, `updateUrl`, `logActivity`, `readSelection`,
`attachClipboard`, `commands` (a list of `{ "id", "label", "prompt", "where" }` objects that replaces the person's
own commands), `answerLanguage` and any field of `assist` (`enabled`, `autopilot`, `spelling`, `grammar`, `style`, `pauseMs`,
`apps`, `appRules`, `pasteFallback`, `ignore`, `language`). Anything else in the file is ignored. Settings shows a
pinned control greyed out with *Set by your organisation*; **Copy diagnostics** names the file and the keys it pins.

```json
{
  "platformUrl": "https://osr.example.com",
  "tenant": "acme",
  "policy": "local",
  "updateUrl": "https://files.example.com/opensmartroute/desktop",
  "assist": { "enabled": true, "autopilot": "spelling", "apps": { "editor": false } }
}
```

### Installing for an organisation

Everything above is for one person on one computer. An administrator installs once for every account and settles
the questions the first run would ask, so people open the bar and it works.

**Windows.** The installer installs for the person running it by default (no administrator prompt,
`%LocalAppData%\Programs`). Run it as administrator and choose **Anyone who uses this computer**, or install
silently with `/S /ALLUSERS`, and it goes to `Program Files` for every account, with one entry in *Apps & features*.
A `managed.json` beside the installer - or the file named by `/MANAGED=<path>` - is copied to
`%ProgramData%\OpenSmartRoute\managed.json` at the same time, so the settings above are pinned before anyone signs
in; the uninstaller removes that copy again. Updates keep the mode they find: an all-users install stays one.

```powershell
# every account on this computer, silently, with the organisation's settings beside the installer
Start-Process .\OpenSmartRoute-2.1.0-win-x64.exe -ArgumentList '/S','/ALLUSERS' -Wait
# ... or naming the settings file
Start-Process .\OpenSmartRoute-2.1.0-win-x64.exe -ArgumentList '/S','/ALLUSERS','/MANAGED=\\files\it\osr\managed.json' -Wait
# uninstall
& "$env:ProgramFiles\OpenSmartRoute\Uninstall OpenSmartRoute.exe" /S /allusers
```

Windows needs no privacy permission for the bar or the writing assistant (UI Automation is open to every program
on the desktop). Add `/EXTENSIONS=all` and the installer registers the browser extension for every account as well:
the app runs once, elevated, and makes the same registrations its **Add** button makes for one person in the
machine-wide places - the HKLM external-extension key of every Chromium browser installed on the computer (Chrome,
Edge, Brave, Vivaldi, ...; each person still sees *Enable OpenSmartRoute?* once) and Firefox's HKLM
`ExtensionSettings` policy (installed silently) - and keeps the receipts in `%ProgramData%\OpenSmartRoute\extensions.json`,
which the uninstaller reads back. A browser with no store listing yet is skipped (an unpacked folder cannot be
installed for every account). For a silent, forced install with the organisation's settings pinned, roll out the
policy files the [extension guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/EXTENSION.md#managed-by-an-organisation) generates instead; they work without the
desktop app.

```powershell
Start-Process .\OpenSmartRoute-2.1.0-win-x64.exe -ArgumentList '/S','/ALLUSERS','/EXTENSIONS=all' -Wait
```

**macOS.** Two files come with every build for administrators:

- `OpenSmartRoute-<version>-mac-arm64.pkg` / `-mac-x64.pkg` installs the app into `/Applications` for everyone
  (`sudo installer -pkg OpenSmartRoute-2.1.0-mac-arm64.pkg -target /`, or pushed by Jamf, Intune, Kandji, Mosyle).
  A `managed.json` beside the package is copied to `/Library/Application Support/OpenSmartRoute/managed.json` by
  the package's postinstall; a management server that pushes the package from a temporary folder drops the file
  itself.
- `OpenSmartRoute-<version>-mac-universal.mobileconfig` is a *Privacy Preferences Policy Control* profile that
  grants the two permissions macOS would otherwise ask each person for: **Accessibility** (read the selection and
  the field you write in, put a fix back) and **Automation towards System Events** (which app is in front, Copy and
  Paste). Nothing else is granted. macOS accepts such a profile only from a device-management server, never from a
  double-click, so upload it to your MDM as a custom configuration profile scoped to the Macs that get the app. The
  profile is bound to the build's code signature: use the one published with the build you deploy (an ad-hoc,
  unsigned build ships one profile per architecture, valid for that build alone). Without the profile every person
  allows the two prompts once, from the welcome window or Settings.

The browser extension on a fleet of Macs goes through the MDM as well: the [extension guide](https://osr-web.kindrock-caaab1a2.centralindia.azurecontainerapps.io/docs/EXTENSION.md#managed-by-an-organisation)
generates one `.mobileconfig` that installs it in Chrome, Edge and Firefox for every account and pins the
organisation's settings, alongside the app's privacy profile.

**Linux.** Install the `.deb` / `.rpm` with your package manager and drop `/etc/opensmartroute/managed.json`.

On a machine with no route to the update server the app simply carries on: the check fails quietly, Settings ›
*Updates and about* shows *Could not reach the update server*, and the next check happens on the usual schedule.
Nothing blocks the bar or the tray while updates are unreachable.

To pre-seed settings on a machine before anyone signs in, write `settings.json` into the app's data folder
(`%APPDATA%\OpenSmartRoute` on Windows, `~/Library/Application Support/OpenSmartRoute` on macOS,
`~/.config/OpenSmartRoute` on Linux) before the first start; the app keeps what it understands and fills in the
rest. A file it cannot read is kept next to the original as `settings.json.corrupt-<timestamp>` rather than
being overwritten.

## Diagnostics

Settings › Updates and about › **Copy diagnostics** puts a support bundle on the clipboard: version, install kind,
system, every setting with the key left out, what the OS bridge can do on this machine, the update state and the
last lines of `diagnostics.log` (a small rolling file in the app's folder that records warnings, blocked
navigations, crashes and what the updater did - the feed it read, the version it found, the installer it started
on *Restart to update*; it never leaves the computer). Paste it into a support ticket.

## The native Mac app

Beside the Electron build there is a native app for macOS 15 and later, written in SwiftUI: the same command bar,
main window and settings, drawn with the system's own Liquid Glass on macOS 26 (the system material on macOS 15)
and weighing about a megabyte. It talks to the same platform, keeps the same conversations and sends the same
`osr.objective`; the platform lists its traffic as the `desktop-mac` client. Download
`OpenSmartRoute-<version>-mac-universal-native.dmg` from the downloads page, drag it to Applications, and press
**⌘⇧Space**. On a Mac without a GPU the system can draw with - a virtual machine, a remote session, a build agent -
the surfaces draw flat and opaque instead of as glass (the same layout, no blur), because the material would
otherwise stop the app; `OSR_MAC_FLAT=1` forces that look anywhere.

What it does the same way:

- **The bar** over the app in front: the selection read through Accessibility when you allow it, the clipboard
  offered when you ask, the on-device verdict (tokens, an e-mail address, a card number, a secret) and **Redact**
  before anything leaves the Mac, the streamed answer with the model, confidence, cost and latency, **Paste into
  …** straight back into the field you came from, thumbs up and down, **Prefer** (Balanced, Cheapest, Best
  quality, Fastest), history, pin, Esc that steps back one level (stop, clear, close). Return sends, ⌘Return too.
- **The main window** (⌘⇧Space then the menu bar icon, or *Open OpenSmartRoute*): Overview with today's
  requests, spend and the recent request log, the workspace's conversations (open, rename, delete; the ones the
  browser extension held appear too), Models with prices and reasoning flags, Usage per client and per model,
  and a conversation view with the same streaming.
- **Sign-in** with the browser (the device code) or a pasted key; the key is sealed in your login Keychain.
  Everyone talks to the hosted platform. The **on-premises router** option (`osr serve`, a self-hosted platform,
  a company proxy) appears in Settings › Workspace only for a workspace on the Pro plan or higher - the hosted
  sign-in grants the licence - or when the organisation's managed file pins the router; a router left in the
  settings without either is put back to the hosted platform at the next launch. The rules under
  [Connect your workspace](#connect-your-workspace) apply unchanged.
- **Managed settings**: the same `/Library/Application Support/OpenSmartRoute/managed.json` the Electron app reads,
  so one MDM payload serves both apps (`platformUrl`, `apiPrefix`, `tenant`, `policy`, `logActivity`,
  `readSelection`, `attachClipboard`, `assistEnabled`, `autoUpdate`). The person's own settings live in
  `~/Library/Application Support/OpenSmartRoute/mac/settings.json`.
- **Updates**: at launch and once a day the app asks the downloads page for a newer native build (Settings › About
  › *Check for updates automatically*, off = only the button there; nothing else is ever contacted besides your
  router). A newer build shows on the island and in Settings › About with its size; **Download** fetches it and
  checks the published SHA-256, then **Install and relaunch** unpacks the zip, swaps it in for the running app and
  opens the new copy - your settings and key stay. When the app sits where your account cannot write (an
  administrator's install) the disk image is downloaded instead and opened for you to drag over the old copy. A
  preview build follows the preview channel; a release only ever moves to the next release. Nothing is installed
  without a click.
- **`osr://` links**: `osr://ask?text=…` opens the bar with the text, `&send=1` sends it at once (a Shortcut or a
  launcher can route a request without touching the bar), `osr://main`, `osr://settings`, `osr://welcome`.

### The writing assistant, natively

The assistant watches the text control that has the keyboard focus in whatever app is in front - Word,
PowerPoint, Excel, Keynote, Teams, Slack, Mail, Notes, a browser's page, VS Code, the ChatGPT or Claude desktop
app - through the accessibility layer, and once you pause it checks the text on this Mac: the system's dictionary
and grammar checker (every language macOS spells) plus the shared mechanics rules (the doubled word, *i* for
*I*, *should of*, *a honest*, the space before a comma, the sentence that starts in lower case). A small glass
badge sits beside the field with the count; hover or click it and the card lists each suggestion with **Fix**
(or a menu of guesses), **Fix all**, **Undo**, **Ignore**. Fixes are written straight into the control where the
app allows a ranged edit and pasted over the verified selection otherwise, so a document keeps its formatting.
*Autopilot* (Settings › Writing) applies the sure spelling fixes - or spelling and grammar - on its own while you
pause; style stays advice. Terminals, password fields, address and search boxes, URLs and the app's own windows
are never read; any app can be excluded from the badge's menu.

Beyond spelling, the card carries what OpenSmartRoute itself notices, each with the one button that resolves it:

- **A key or personal data about to leave.** An API key anywhere, a card number, an IBAN, an SSN or an Aadhaar
  number in any text, and - when the field is the composer of an AI assistant - e-mail addresses, phone numbers
  and IP addresses too. **Redact** swaps each for the bar's placeholder (`<EMAIL_1>`) in the field itself; Undo
  puts the data back. Nothing is redacted without a click. An address in a mail or a chat is left alone: it
  belongs there.
- **Tone and length.** Capitals and stacked exclamation marks read as shouting; a chat message past ~900
  characters, a mail past ~2,500. **Ask** opens the bar with a rewrite prompt and the text, and the answer's
  *Paste into* replaces the field.
- **A question.** A short question in a chat or a mail offers **Ask** to draft the answer.
- **In an AI assistant's composer** (ChatGPT, Claude, Perplexity, Copilot, Gemini desktop apps): the token
  estimate and the tier the request usually lands on (*a small model will do*, *a mid-tier model*, *a reasoning
  model*), with **Route it** - the prompt becomes the bar's request, OpenSmartRoute picks the model and says
  which one answered, what it cost and how long it took.

### The island

A live activity in the spirit of the iPhone's Dynamic Island continues the notch on a MacBook (a black shape at
the top edge on any other display) and folds away when nothing is happening. It shows one line while the router
thinks (*Routing…*, *Answering with claude-mid*), the decision when the answer lands (*claude-mid · 87% · 640 ms
· $0.0021*), what the assistant found in the field you are typing in (*Contains a card number · Teams*, *3 writing
suggestions · Mail*), fixes and redactions as they are written, the sign-in code to approve, an error as a
sentence. Move the pointer up to it and it opens into a card with the actions - Copy answer, Paste into the app,
Stop, Redact, Fix all, Improve, Undo - and **Ask** (the bar) and **Workspace** (the main window); with nothing
going on the card is the workspace at a glance: who is signed in, today's requests and spend, whether the
assistant is on. Settings › Command bar › *Island* turns it off. It is non-activating: the app you were in keeps
the keyboard.

What differs from the Electron app: no `.pkg` or privacy profile - the Electron app's `.mobileconfig`
does not cover this bundle. Both apps can be installed side by side; they hold different bundle identifiers
(`ai.opensmartroute.mac` here) and settings folders, and the shortcut goes to whichever registered it first, so
pick one shortcut per app in Settings.

Colours follow the system: the accent colour you chose in System Settings on every primary action, the semantic
system colours (red, orange, green, blue, purple) for spelling, grammar, success, style and privacy, `Label`
colours for text, so the app reads like the rest of the Mac in light, dark and increased-contrast appearances. The
OpenSmartRoute mark - the open ring with three routes - is the menu bar icon (a template image, so it follows the
menu bar), the bar's corner, the welcome and the island; the Dock and Finder show the brand's app icon.

The first launch is *Open Anyway* as described under [Install](#install) until a Developer ID signs the build;
the bundle is ad-hoc signed with the hardened runtime otherwise.

### Building it

Building from source needs Xcode (the Command Line Tools alone cannot build SwiftUI); Xcode 26 compiles the
Liquid Glass path, an older Xcode builds an app that draws the system material everywhere, and `OSR_MAC_XCODE=26`
picks that Xcode when several are installed. `npm run mac:bundle -- --arch universal` produces the app bundle, the
`.dmg`, the `.zip` and the SHA-256, stamped with the release version. The bundle is signed with the Developer ID
in `OSR_DESKTOP_MAC_CSC_LINK` / `OSR_DESKTOP_MAC_CSC_KEY_PASSWORD` and notarised and stapled when
`OSR_DESKTOP_APPLE_ID`, `OSR_DESKTOP_APPLE_APP_PASSWORD` and `OSR_DESKTOP_APPLE_TEAM_ID` are set (`--no-notarize`
skips that), or with `OSR_DESKTOP_MAC_SIGN_IDENTITY`, an identity already in the keychain, or ad-hoc otherwise.
The published native builds carry a `-native` marker and the downloads page labels them *native app (macOS 15+)*.

## The native Windows app

Beside the Electron build there is a native app for Windows 10 (1809) and later, written in C# on WPF and .NET 9
with the Fluent theme: the same command bar, main window, settings, welcome, writing assistant and island as the
Mac app, drawn with Windows 11's own materials - Mica behind the main window and Settings, Acrylic behind the
bar - and the system accent colour on every primary action; on Windows 10 the surfaces are the theme's solid
colours. It is one self-contained exe of about 70 MB (the runtime travels inside), talks to the same platform,
keeps the same conversations and sends the same `osr.objective`; the platform lists its traffic as the
`desktop-win` client. Download `OpenSmartRoute-<version>-win-x64-native.exe` (or `-win-arm64-native.exe` on an
ARM PC) from the downloads page and run it: the installer puts the app in `%LocalAppData%\Programs\OpenSmartRoute`
for you - no administrator prompt - with a Start-menu entry, a *Programs and Features* entry and the `osr://`
link, and offers to start it. Then press **Ctrl+Shift+Space**. Run a newer installer over it and it upgrades in
place: the running app is asked to quit, the exe is replaced, your settings and the sealed key stay. The
`-native-portable.exe` beside it is the bare exe for a USB stick or a locked-down PC. In a remote session,
without desktop composition, or with `OSR_WIN_FLAT=1`, the surfaces draw flat and opaque (the same layout, no
backdrop).

What it does the same way as the [native Mac app](#the-native-mac-app):

- **The bar** over the app in front: the selection read through UI Automation (the interface screen readers use,
  open to every program - nothing has to be granted), the clipboard offered when you ask, the on-device verdict
  and **Redact** before anything leaves the PC, the streamed answer with the model, confidence, cost and latency,
  **Paste into …** straight back into the field you came from (the app in front is brought forward and Ctrl+V
  pressed for it; the clipboard is restored a moment later), thumbs up and down, **Prefer**, history (Ctrl+H),
  pin, Esc that steps back one level. Enter sends, Shift+Enter breaks the line, Ctrl+N starts over, Ctrl+. stops.
  The bar hides from Alt+Tab and the taskbar and closes when another window takes focus unless pinned or
  *Keep the bar open* is set.
- **The main window** (double-click the notification-area icon, or *Open OpenSmartRoute*): Overview, the
  workspace's conversations (open, rename, delete), Models, Usage with a 7 / 30 / 90-day window, and the
  conversation view. Ctrl+1 / 2 / 3 switch the pages, Ctrl+R refreshes, Ctrl+, opens Settings.
- **Sign-in** with the browser or a pasted key; the key is sealed with DPAPI under your Windows account in
  `%APPDATA%\OpenSmartRoute\win` (a copied file is worthless on another machine or account). The on-premises
  router option and its licence follow the same rules; the organisation's `managed.json` lives at
  `%ProgramData%\OpenSmartRoute\managed.json`, the same file the Electron app reads.
- **The writing assistant**, through UI Automation: the focused text control in Word, Outlook, Teams, Slack,
  Notepad, a browser's page, VS Code, the ChatGPT or Claude desktop app; Windows' own spell checker (every
  language installed under Settings › Time & language, your custom words included) plus the shared rules and the
  insights - a key or personal data about to leave, tone, length, a question, the cost and tier of a prompt in an
  AI assistant's composer. Fixes are written through the control's value pattern where it allows a write, pasted
  over the verified selection otherwise. The badge is a small non-activating window beside the field.
- **The island** at the top edge of the primary display: folded to a sliver when nothing is happening, one line
  while the router thinks or when the assistant has something to say, a card with the actions when the pointer
  comes up to it.
- **`osr://` links** (`osr://ask?text=…&send=1`, `osr://main`, `osr://settings`, `osr://welcome`), registered
  for your account the first time the app runs unless another live installation already owns the scheme. A second
  copy started with a link hands it to the running one.
- **Start at login** through the account's Run key (visible in Task Manager › Startup), off by default.
- **Updates**: at launch and once a day the app asks the downloads page for a newer native build (Settings › About
  › *Check for updates automatically*; `autoUpdate` in `managed.json` pins it). A newer build shows on the island
  and in Settings › About with its size; **Download** fetches the installer and checks the published SHA-256, then
  **Install and restart** runs it silently: the app is asked to quit, the exe is replaced in place, and the app
  starts again with your settings and key. A copy installed for every account asks for an administrator's approval
  first. The portable exe is never swapped under itself: the new file is downloaded beside it and shown for you to
  replace the old one. Nothing is installed without a click.

What differs from the Electron app: no browser extension installer. Administrators install it the same way as the
Electron app - `OpenSmartRoute-<version>-win-x64-native.exe /S /ALLUSERS` from an elevated prompt puts it in
`Program Files` for every account, and a `managed.json` beside the installer (or `/MANAGED=<path>`) becomes
`%ProgramData%\OpenSmartRoute\managed.json`; `/D=<folder>` picks the folder; the uninstaller in the install folder
(also listed under *Programs and Features*) takes `/S` and removes the Start-menu entry, the `osr://` link and the
start-at-login value while they still name that install, and leaves your settings and key alone. Both Windows
apps can be installed side by side; they hold different install and settings folders and separate *Programs and
Features* entries (*OpenSmartRoute* and *OpenSmartRoute (native)*), and the shortcut goes to whichever registered
it first - the other falls back to Ctrl+Alt+Space and says so in Settings.

### Building it

Building from source needs only the .NET 9 SDK (`winget install Microsoft.DotNet.SDK.9`) and `makensis` for the
installer. `npm run win:bundle -- -Arch both` publishes a self-contained single-file build per architecture,
stamped with the release version, as an installer (`-native.exe`) and a portable exe (`-native-portable.exe`),
each with its `.sha256`. Both files are signed with Azure Trusted Signing when `OSR_DESKTOP_AZURE_SIGN_ENDPOINT`,
`OSR_DESKTOP_AZURE_SIGN_ACCOUNT` and `OSR_DESKTOP_AZURE_SIGN_PROFILE` are set (the same variables as the Electron
app), with a certificate from the account's store when `OSR_WIN_SIGN_THUMBPRINT` names one, and left unsigned
otherwise. `OpenSmartRoute.exe --quit` asks a running copy to quit (the installer uses it). The published native
builds carry a `-native` marker and the downloads page labels them *native app (Windows 10+)*.

## Code signing without buying a certificate

The installers work unsigned; what a signature buys is the absence of the SmartScreen and Gatekeeper prompts
described under [Install](#install). None of the paths below needs a traditional code-signing certificate from a
commercial CA; each one takes effect for a deployment's builds as soon as it is configured - nothing else changes.

| System | Path | What it needs | Build configuration |
|---|---|---|---|
| Windows | **Azure Trusted Signing** (Artifact Signing): Microsoft issues short-lived Public Trust certificates from an identity-validated account and signs through the service; SmartScreen treats the publisher as known from the first download. | An Azure subscription, the Basic tier of the service (a small monthly fee), and identity validation - an organisation in the United States, Canada, the European Union, the United Kingdom, Australia, New Zealand, Japan, South Korea, Singapore, Switzerland, Norway or Israel, or an individual in the United States or Canada (government ID, a few days). The build's service identity gets the *Artifact Signing Certificate Profile Signer* role. | `OSR_DESKTOP_AZURE_SIGN_ENDPOINT` (the region endpoint, e.g. `https://weu.codesigning.azure.net`), `OSR_DESKTOP_AZURE_SIGN_ACCOUNT`, `OSR_DESKTOP_AZURE_SIGN_PROFILE` (naming the certificate profile switches signing on) and `OSR_DESKTOP_AZURE_SIGN_PUBLISHER` = the certificate's subject name so the updater accepts signed updates. |
| Windows | A conventional certificate (`.pfx`) from a CA. | The certificate and its password. | `OSR_DESKTOP_WIN_CSC_LINK` (base64 of the `.pfx`), `OSR_DESKTOP_WIN_CSC_KEY_PASSWORD`. |
| macOS | Developer ID signing and notarisation. | An Apple Developer Program membership (yearly fee); there is no free notarisation. | `OSR_DESKTOP_MAC_CSC_LINK`, `OSR_DESKTOP_MAC_CSC_KEY_PASSWORD`, `OSR_DESKTOP_APPLE_ID`, `OSR_DESKTOP_APPLE_APP_PASSWORD`, `OSR_DESKTOP_APPLE_TEAM_ID`. The same five sign, notarise and staple the [native Mac app](#the-native-mac-app) and its disk image. Until then both bundles are ad-hoc signed so Gatekeeper reports them as unverified rather than damaged, and the first launch is *Open Anyway* as described above. |
| Linux | Nothing to sign for the AppImage; `.deb` / `.rpm` repositories can carry a GPG key. | - | - |

What the unsigned Windows build cannot avoid is the one *More info › Run anyway* on first launch; the SHA-256 on
the downloads page is the check that the file is the published file. The portable exe carries the
same prompt and never self-updates.

## Tray menu

The mark in the system tray or menu bar gains a dot while an answer is streaming. Its menu mirrors the app:
**Open OpenSmartRoute**, **Ask**, the connected workspace or **Sign in to a workspace**, the extension's status, **Settings**,
**Start when I sign in**, **Writing assistant** (on or off), **Dashboard**, **Help**, an update line when one is ready, **Quit**. Double-clicking the
icon opens the main window.

## Privacy

- Nothing leaves this computer until you press Enter, unless you turn on *Price my draft while I
  type*. The personal-data scan, redaction and the model-tier check run on the device.
- A request you send goes to your workspace (or, signed out, nowhere - the bar asks you to sign in). The platform
  stores the decision and its trace, not the text, unless your workspace has turned request logging on.
- The selection is read by sending Copy to the app in front and reading the clipboard, which is restored
  immediately afterwards. It is never read in a terminal.
- Settings, past conversations (`threads.json`, when history is on) and the workspace key live in the app's own
  folder - `%APPDATA%\OpenSmartRoute` on Windows,
  `~/Library/Application Support/OpenSmartRoute` on macOS, `~/.config/OpenSmartRoute` on Linux. Uninstalling
  keeps the folder so a reinstall finds your settings; delete it to remove everything.
- The renderer windows never navigate or open windows themselves: a link in an answer opens in your browser,
  anything else is dropped. No telemetry to us; diagnostics are copied by you, never uploaded.
- **Log my activity to the workspace** (Settings › Command bar, on by default) records what the app did as
  events on *your* workspace (`POST /api/v1/usage/activity`), posted every few minutes and once more when the app
  quits. The first event sends *Your desktop app is connected* to you: what the app does, that the workspace sees
  counts only, and what to do if you did not install it. An event is a kind, the kind of app that was in front (`editor.app`, `browser.app` ...), a count and a
  figure - never your question, the answer or a window title; the platform refuses a text field of any name. The
  kinds: `app.started` / `app.updated`, `bar.opened`, `context.attached`, `pii.detected`, `ask.sent`,
  `answer.received` (with the target, request id and latency), `answer.failed`, `answer.cancelled`,
  `answer.pasted`, `feedback.good` / `feedback.bad`, `session.signed_in` / `session.signed_out`,
  `extension.registered` / `extension.unpacked` per browser. The workspace's Apps page shows them as counts; the
  plan decides how long they are kept and how many a day are recorded (PLATFORM.md). Unsent events wait in
  `activity.json` and go with an uninstall.
- Every request carries an `X-OSR-App: desktop` header so the dashboard can tell the app from the extension and
  the API.

## Troubleshooting

| Symptom | What to do |
|---|---|
| The shortcut does nothing | Another app holds it. Settings › Command bar shows the active shortcut; press new keys there, use the fallback the note offers, or **Reset** |
| *Selected text is not read* | macOS: press **Allow** in Settings (opens the Accessibility pane) and the row ticks itself once granted. Linux X11: install `xdotool`; Wayland: install `wl-clipboard` and `wtype` (Settings says which is missing). Terminals are never read by design |
| The bar closes when I switch to another window | That is the default; pin it (the pin icon, or Settings › *Keep the bar open when I switch windows*). Your draft and thread are kept either way |
| *Enable OpenSmartRoute?* never appears in Chrome or Edge | Restart the browser fully (check the tray for a lingering process). Settings › Browser extension shows what was written per browser |
| The bar says *connect a workspace* | Press Connect and approve the sign-in in the browser; for an on-premises router fill in *On-premises router or a key* |
| The bar says *an on-premises router needs a Pro plan* | The settings name a router other than OpenSmartRoute and this computer holds no licence. Sign in to OpenSmartRoute with a workspace on Pro or higher (the licence is granted on that sign-in), or press **Use OpenSmartRoute** in Settings › Workspace |
| macOS keeps asking to *control System Events*, or the answer is never pasted back | Allow it once (System Settings › Privacy & Security › Automation › OpenSmartRoute › System Events). On a managed Mac ask your administrator for the privacy profile published with the build; a profile from another build or another signing identity does not apply |
| The Windows installer shows *Anyone who uses this computer* greyed out | It was started without administrator rights. Right-click › *Run as administrator*, or install for yourself only - both work the same afterwards |
| No update is offered | Portable, `.deb` and `.rpm` builds, and the macOS build while it is not Developer-ID signed, do not self-update; download the new version from the downloads page. Installed Windows builds and the AppImage: Settings › Updates › Check now |
| The Windows installer closes at once, or Windows reports *OpenSmartRoute-…-win-x64.exe has stopped working* | Installers published before the electron-builder 26 upgrade could crash while choosing the install folder (an over-read in the installer runtime); download the current installer from the downloads page |
| Chrome or Edge refuses the download - *this file isn't commonly downloaded and may be dangerous* | The browser scores installers by how many people have downloaded them, and an unsigned build of a new app scores low. Open the browser's downloads list, choose **Keep**, then **Keep anyway**; compare the SHA-256 with the downloads page before you run it |
| Windows SmartScreen or macOS Gatekeeper warns about the file | The build you have is not code-signed (a deployment signs and notarises its installers once the certificates are configured; the downloads page then drops these steps, and the manifest at `/desktop/release.json` says so under `signed`). Compare the SHA-256 with the downloads page, then allow it (*Run anyway*; on macOS *Open Anyway* under Privacy & Security) |
| macOS says *"OpenSmartRoute.app" is damaged and can't be opened* | The first macOS builds were published without any signature; download the current image again. If it persists, the quarantine flag on the old copy is to blame: in Terminal, `xattr -dr com.apple.quarantine /Applications/OpenSmartRoute.app`, then open it once from Applications |
