Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 61 additions & 53 deletions docs/architecture.mdx

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/building.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ Set-Location services\build\bin
'{"jsonrpc":"2.0","id":1,"method":"ping"}' | .\nvpair-ui-broker.exe
```

You may see an `app:ready` notification alongside the response, and discovery may
You can see an `app:ready` notification alongside the response, and discovery can
be empty while LAN browsing starts. Set `NVPAIR_LOG_LEVEL=debug` or pass
`--log-level debug` for launch diagnostics. The accepted levels are `debug`,
`info`, `warn`, and `error`.
Expand Down Expand Up @@ -239,7 +239,7 @@ opening a pull request are in

## Cleaning Up a Build from Source

A source build has nothing to uninstall — deleting the checkout removes the
A source build has nothing to uninstall. Deleting the checkout removes the
application. What it leaves behind is the same per-user data any install creates,
so reset that the same way. Alongside the in-app
**Settings > Service > Reset app data**, a script does the same job without the
Expand All @@ -254,7 +254,7 @@ On Windows use `scripts\wipe-app-data.cmd` with the same flags. Neither script
needs Node, and both exclude engine model libraries such as `~/.ollama`,
`~/.lmstudio/models`, and `~/.llamacpp` by design, so a reset does not cost you
re-downloading models.
Start with `--dry-run`; it prints the exact paths and deletes nothing.
Start with `--dry-run`. It prints the exact paths and deletes nothing.

If the machine belongs to a cluster, leave the cluster as well, or the other
nodes keep listing it as a member. Refer to
Expand Down
8 changes: 4 additions & 4 deletions docs/developing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ cryptography in TypeScript, the change belongs in a Go service instead.

### `desktop/`

| Path | What it owns |
| Path | What it Owns |
| --- | --- |
| `src/ui/` | The React renderer: components, stores, and the renderer-side API |
| `src/ui/stores/` | One store per domain — nodes, engines, models, workloads, errors, and metrics |
| `src/ui/stores/` | One store for each domain: nodes, engines, models, workloads, errors, and metrics |
| `src/ui/api/pair-api.ts` | The renderer's view of the service surface |
| `src/preload/` | The typed bridge exposing `window.pairApi` and `window.windowApi` |
| `src/electron/` | Main process: broker supervision, service bridge, and interprocess communication (IPC) |
Expand All @@ -54,10 +54,10 @@ The files you touch most often:
| `src/shared/types/ws-channels.ts` | Every logical service channel: `WsInvokeChannelMap` for requests, `WsPushChannelMap` for pushes |
| `src/shared/types/ipc-channels.ts` | `IpcChannelMap`, the contract for Electron-native IPC |
| `src/electron/service-bridge/empty-handlers.ts` | `handleServiceBridgeInvoke`, the single dispatch every service call goes through |
| `src/electron/service-bridge/modular-state.ts` | `ModularBridgeState` — backend notifications become renderer push events here |
| `src/electron/service-bridge/modular-state.ts` | `ModularBridgeState`, where backend notifications become renderer push events |
| `src/electron/service-bridge/modular-supervisor.ts` | The broker process and its JSON-RPC link |
| `src/shared/constants/modular-binaries.ts` | The canonical inventory of shipped binaries and who launches them |
| `src/shared/constants/modular-runtime.ts` | Backend-coupled constants — the only place a port or path literal belongs |
| `src/shared/constants/modular-runtime.ts` | Backend-coupled constants and the only place a port or path literal belongs |

### `services/`

Expand Down
23 changes: 12 additions & 11 deletions docs/engine-lifecycle.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ An **engine** is the local inference runtime Personal AI Router (PAIR) uses to
run models. Today that means Ollama, LM Studio, or llama.cpp on a given machine.
PAIR can install and run those engines for you, or work with a supported
existing Ollama or LM Studio installation. This page explains what you can
expect when you install, start, stop, update, or remove an engine.
expect when you install, start, stop, or remove an engine, and how to move one
to a newer release.

For first-time setup, refer to [Getting started](getting-started.mdx). To change
an engine's ports or launch command, refer to
Expand Down Expand Up @@ -83,18 +84,18 @@ When you install an engine, consider the following:
because upstream builds it without Metal. The engine download, roughly
0.3–0.7 GiB for the CUDA archives and about 11 MiB on macOS, happens on
demand and is not part of the PAIR installer. Package choice is not
driver-aware; llama.cpp retains CPU fallback when GPU acceleration is
driver-aware. llama.cpp retains CPU fallback when GPU acceleration is
unavailable.

PAIR-managed llama.cpp models sleep after five minutes without inference work.
This releases model and KV-cache memory, and the next request wakes the model
automatically. The llama.cpp worker remains running and may retain some GPU
automatically. The llama.cpp worker remains running and can retain some GPU
memory.

To download models:

1. Use **Add model**.
2. Use **Load** when the engine requires an explicit load.
1. Select **Add model**.
2. Select **Load** when the engine requires an explicit load.

![The Install engines dialog with Ollama downloading, reporting progress as it installs.](assets/onboarding/engine-lifecycle/01-engine-installing.png)

Expand Down Expand Up @@ -127,31 +128,31 @@ an engine PAIR installed. Use it when you no longer want PAIR to own that engine
on the machine.

Uninstalling an engine does **not** remove its models. Downloaded model files stay
on disk in the engine's own storage — `~/.ollama`, `~/.llamacpp`, or
`~/.lmstudio/models` — so uninstalling and reinstalling does not cost you
on disk in the engine's own storage (`~/.ollama`, `~/.llamacpp`, or
`~/.lmstudio/models`), so uninstalling and reinstalling does not cost you
re-downloading them. The same is true of removing PAIR itself, or of resetting
its data. Both remove the engines PAIR installed as far as they can, and never
your models: a reset stops and tells you if an engine cannot be removed, while
your models. A reset stops and tells you if an engine cannot be removed, while
uninstalling PAIR leaves that engine in place and finishes. To reclaim that
space, use **Delete** on individual models, or remove the engine's storage
directory yourself.

PAIR keeps the model folder at the engine's default location. If you moved LM
Studio's models folder somewhere else inside `~/.lmstudio`, removing an LM
Studio that PAIR installed — by uninstalling it, or by removing PAIR's data —
Studio that PAIR installed (by uninstalling it, or by removing PAIR's data)
deletes that folder with the rest of `~/.lmstudio`. A models folder outside
`~/.lmstudio`, or one linked back to `~/.lmstudio/models`, is kept.

PAIR also leaves alone any engine you installed yourself. **Uninstall** acts only
on a copy PAIR installed; remove the others with the engine's own uninstaller.
on a copy PAIR installed. Remove the others with the engine's own uninstaller.

Port changes for an NVPAIR-installed engine also live in **Engine settings**.
Prefer the controls in PAIR over editing the engine's own config when PAIR is
managing it. If PAIR **adopted** an engine that was already running, meaning it
did not start the process, what it can do depends on how that engine is
controlled:

- **Ollama** is managed as a process, so PAIR will not move an adopted one. It
- **Ollama** is managed as a process, so PAIR does not move an adopted one. It
refuses the port change rather than killing something it did not start. Stop
the engine in its own application first if you want PAIR to manage it fully.
- **LM Studio** publishes an official stop command, so PAIR can stop an adopted
Expand Down
78 changes: 40 additions & 38 deletions docs/engine-settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,33 @@ SPDX-License-Identifier: Apache-2.0
# Engine Settings in NVIDIA Personal AI Router

Open a device's Ollama, LM Studio, or llama.cpp row and expand **Settings**.
Edit the server port, proxy port and engine arguments, then select the green
**Apply** button. A paired device that supports settings can be edited from
another device in the cluster.
Edit the server port, proxy port, and engine arguments, then select **Apply**.
A paired device that supports settings can be edited from another device in the
cluster.

PAIR fixes the executable, lifecycle commands and loopback address. Unsupported
PAIR fixes the executable, lifecycle commands, and loopback address. Unsupported
vendor options can fail at startup.

For installing, starting and updating engines, refer to
For installing, starting, and uninstalling engines, refer to
[Managing engines](engine-lifecycle.mdx).

## Argument notation
## Argument Notation

The text contains engine arguments and optional leading environment assignments.
PAIR supplies the executable and startup subcommand. Leave the text empty to use
managed defaults. Tokens are passed directly to the engine, using the same
notation on every operating system.

- Spaces, tabs and line breaks separate unquoted tokens.
- Spaces, tabs, and line breaks separate unquoted tokens.
- Single quotes enclose literal text. Double quotes enclose literal text with
two escapes, `\"` and `\\`; any other backslash stays literal, so a Windows
two escapes, `\"` and `\\`. Any other backslash stays literal, so a Windows
path such as `C:\new\tools` needs no doubling.
- A quoted and an unquoted part can form one token, as in `--name="two words"`.
An empty quoted string is an empty argument.
- Nothing is expanded: `$HOME`, `%USERPROFILE%`, `{port}` and `~` are literal,
and there are no comments, pipelines, redirects or command substitution.
Unquoted `|`, `&`, `;`, `<`, `>`, a backtick or `$(` is rejected — quote them
when the engine really wants that character.
- Nothing is expanded: `$HOME`, `%USERPROFILE%`, `{port}`, and `~` are literal,
and there are no comments, pipelines, redirects, or command substitution.
Unquoted `|`, `&`, `;`, `<`, `>`, a backtick, or `$(` is rejected. Quote them
when the engine needs that character.
- At most 16 KiB and 256 tokens, valid UTF-8.

Environment assignments go first, followed by engine arguments:
Expand All @@ -42,23 +42,23 @@ OLLAMA_ORIGINS="https://example.com"
--port 1235 --bind 127.0.0.1
```

## Environment variables
## Environment Variables

Environment assignments are saved and passed literally to the engine on every
launch. PAIR does not maintain a list of supported variables or validate their
engine-specific values. Editing or removing one takes effect at the next launch.

Managed CORS settings, including LM Studio's `--cors` switch, can only be changed
on the device running the engine. A paired device can preserve an existing CORS
policy while changing other settings, but cannot enable, disable or replace it.
policy while changing other settings, but cannot enable, disable, or replace it.
Other environment assignments can also be edited from a paired device.

Origin lists need a scheme and a specific host, so bare `localhost` and `*` are
rejected, including wildcards hidden inside extra quotes. Wildcard subdomains
such as `https://*.example.com` and ports such as `http://localhost:*` are supported.
Managed llama.cpp starts with an empty origin list, so cross-origin browser
access is disabled until specific origins are added locally. List only the
origins you want to allow. This is how you give a web page access to your models:
origins you want to allow. This is how you give a web page access to your models.
PAIR's local endpoints add no permissive default of their own, so a browser
reaches a model through PAIR only where the engine would have allowed it directly.
For a request that spans the cluster, every engine that answers has to allow the
Expand All @@ -68,50 +68,52 @@ An engine does not need a CORS launch option to work with PAIR. The proxy follow
the engine's HTTP responses regardless of how its CORS policy is configured.
If the engine grants no CORS permission, PAIR does not add permission for it.

Startup failures include a bounded excerpt of the engine’s own output. PAIR
redacts supplied values by exact match, but an engine may transform or encode
Startup failures include a bounded excerpt of the engine's own output. PAIR
redacts supplied values by exact match, but an engine can transform or encode
them. Do not put secrets in launch values.

## Ports and validation
## Ports and Validation

PAIR understands only the networking controls needed to keep engine and proxy
configuration consistent:

| Engine | Server port | Loopback bind | Browser access |
| Engine | Server Port | Loopback Bind | Browser Access |
| --- | --- | --- | --- |
| Ollama | `OLLAMA_HOST=127.0.0.1:<port>` | The host in `OLLAMA_HOST` | `OLLAMA_ORIGINS` |
| LM Studio | `--port`, `-p` | `--bind`, `LMS_SERVER_HOST` | `--cors` |
| llama.cpp | `--port` | `--host` | `--cors-origins` |

For LM Studio, `--port 1235`, `--port=1235`, `-p 1235`, `-p1235` and `-p=1235`
For LM Studio, `--port 1235`, `--port=1235`, `-p 1235`, `-p1235`, and `-p=1235`
all synchronize the same server-port field. Conflicting repetitions and invalid
ports are rejected. Write managed short options separately; bundles containing
them are ambiguous and rejected. CORS switches do not take `=true` or `=false`:
add or remove the switch locally. Origin lists are normalized before validation;
conflicting repeated lists are rejected. Other vendor options remain opaque.
llama.cpp must remain in router mode; model-selection arguments such as `-m`
ports are rejected. Write managed short options separately. Bundles containing
them are ambiguous and rejected. CORS switches do not take `=true` or `=false`.
Add or remove the switch locally. Origin lists are normalized before validation,
and conflicting repeated lists are rejected. Other vendor options remain opaque.
llama.cpp must remain in router mode. Model-selection arguments such as `-m`
or `-hf` switch it to an incompatible single-model server and fail readiness.

Changing the server-port field updates the port in the command. Editing the
command's port updates the numeric field. If both are edited before validation
finishes, the numeric field takes precedence. The server and proxy must use
different ports; a collision opens an error dialog explaining which port
different ports. A collision opens an error dialog explaining which port
collides. Invalid settings and failed saves also open an error dialog.

Apply validates the complete change. Confirmation is requested only when a running engine
needs to restart. Progress appears as a spinner inside Apply. A running engine
restarts for launch/server changes; changing only the proxy port leaves the
engine running. Stopped engines remain stopped. Saved settings survive restart.
**Apply** validates the complete change. PAIR asks for confirmation only when a
running engine needs to restart. Progress appears as a spinner inside **Apply**.
A running engine restarts for launch and server changes. Changing only the proxy
port leaves the engine running. Stopped engines remain stopped. Saved settings
survive restart.

## Concurrent edits
## Concurrent Edits

Changes from another device update a clean editor. An unfinished draft stays
intact; applying a stale draft opens an error dialog. **Reload saved settings** deliberately
discards that draft. Failed starts retain the saved settings for correction and
show one error dialog. Validation on leaving a field quietly synchronizes ports;
errors appear only when Apply is selected, without duplicate text below the command.

Offline, unpaired or older devices cannot be edited. A process started outside
PAIR may require stopping it in its own application before changing its launch.
intact, and applying a stale draft opens an error dialog. **Reload saved
settings** deliberately discards that draft. Failed starts retain the saved
settings for correction and show one error dialog. Validation on leaving a field
quietly synchronizes ports. Errors appear only when you select **Apply**, without
duplicate text below the command.

Offline, unpaired, or older devices cannot be edited. A process started outside
PAIR can require stopping it in its own application before changing its launch.
The displayed arguments describe a future PAIR launch, not an external process's
original arguments.
Loading
Loading