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
136 changes: 121 additions & 15 deletions INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,73 @@ On Linux, open the installed app with `~/.switchyard/bin/switchyard-desktop --tu
See [Desktop setup](crates/switchyard-desktop/SETUP.md) for these steps.
Uninstall keeps settings, history, and recovery copies.

The installer requires the repository's Rust toolchain. macOS uses LaunchAgents;
Linux requires a systemd user session. Windows requires MSVC build tools,
WebView2, and a Task Scheduler user session.
## Server Keys

In a server config, each LLM client and decision client names its API key
variable with `api_key_env`. A server you start from a terminal reads those
variables from your shell, as it always has. The installed server does not: on
macOS launchd starts it, on Linux systemd, and on Windows Task Scheduler. None
of them runs your shell, so the installed server never sees the variables that
`~/.zshrc` or `~/.bashrc` exports.

The installed server reads each key from the system credential store instead:
macOS Keychain, Windows Credential Manager, or the Linux Secret Service (GNOME
Keyring on Ubuntu and GNOME, KDE Wallet on Plasma). A key is saved under its
variable name, such as `NVIDIA_API_KEY`. Before each start, the installed
helper reads the keys that the config names and passes them to the server. A
saved key replaces any value the service manager passes. If a variable has no
saved key, the server does not start, and the server log names the variable.

To save, replace, or remove a key in the desktop app, open **Settings → Server
keys**. Type or paste the key, or choose **Import from shell** to read the
variable once from your login shell. From a terminal on macOS or Linux, run the
installed helper:

On Windows, run install and uninstall from the source checkout with Cargo.
The installed helper rejects changes to its own installation because Windows
locks running executables. The app's Update command uses a temporary helper
copy. The installed helper still supports `uninstall --dry-run`.
```bash
~/.switchyard/bin/switchyard-desktop-install key status --config ~/.switchyard/composite.toml
~/.switchyard/bin/switchyard-desktop-install key set NVIDIA_API_KEY # prompts without echo
~/.switchyard/bin/switchyard-desktop-install key import NVIDIA_API_KEY # reads it from your login shell
~/.switchyard/bin/switchyard-desktop-install key remove NVIDIA_API_KEY
```

On Windows, the installer puts the helper in
`%LOCALAPPDATA%\Programs\Switchyard`. There `key set` reads the key from
standard input without a prompt, and `key import` reads the variable from your
Windows environment variables. From PowerShell:

```powershell
$helper = "$env:LOCALAPPDATA\Programs\Switchyard\switchyard-desktop-install.exe"
& $helper key status --config "$env:USERPROFILE\.switchyard\composite.toml"
[Net.NetworkCredential]::new('', (Read-Host 'Key' -AsSecureString)).Password | & $helper key set NVIDIA_API_KEY
& $helper key import NVIDIA_API_KEY
& $helper key remove NVIDIA_API_KEY
```

Restart the server after you change a key. If you rename a variable in
`api_key_env`, save a key under the new name. The old key stays saved until you
remove it in Keychain Access, Credential Manager, or Seahorse.

`cargo desktop install` never saves, reads, or changes a key, even when your
terminal sets the variable. It checks the config without keys, then lists each
variable that has no saved key. On a first install, the server starts after you
save those keys in **Settings → Server keys** and restart it. In the terminal
app, press `7` to open the Settings page. There `k` lists the variables that the
config names and whether each has a saved key, `s` saves a key, and `i` imports
it from your login shell. Press `b` and then `y` to restart the server.
Uninstalling keeps the saved keys, the config, and history. Switchyard never
writes keys to app settings, service definitions, or logs. Model-list keys that
you enter in Routes are stored separately.

On macOS, Keychain ties each key to the helper that saved it. Keychain treats a
rebuilt helper as a new program, so after `cargo desktop install` macOS may ask
once per key whether to allow `switchyard-desktop-install`. Choose **Always
Allow**.

On Linux, the login keyring must be unlocked. A desktop login normally unlocks
it. When the server service starts after login, it waits up to a minute for the
keyring to unlock. Over SSH without a desktop session, or with a window manager
that does not unlock the keyring, the server does not start and its log says
the keyring is locked.

## Linux Codex Service

Expand All @@ -68,13 +127,16 @@ port while the service is stopped and receive your login and prompts.
From a checkout, preview or install the service:

```bash
make install-linux-dry-run
make install-linux
cargo desktop install --dry-run
cargo desktop install
systemctl --user status switchyard
codex -p sy
```

The installer builds and installs `~/.switchyard/bin/switchyard-server`.
The installer builds and installs `~/.switchyard/bin/switchyard-server` and
`~/.switchyard/bin/switchyard-desktop`. Run the same command to reinstall from
the current checkout; update the checkout first to install newer code.
Run `~/.switchyard/bin/switchyard-desktop --tui` to open the terminal app.
It creates `~/.switchyard/composite.toml` if missing and keeps existing edits.
It replaces `~/.config/systemd/user/switchyard.service` and restarts the service.
It writes `~/.codex/sy.config.toml`, backing up a changed profile first.
Expand All @@ -84,20 +146,61 @@ The profile format requires [Codex 0.134.0 or newer](https://developers.openai.c
Remove any old `[profiles.sy]` table from `~/.codex/config.toml` before using it.

Set `SY_HOME` or `SY_PORT` to change the server directory or port (default 4123).
`SY_HOME` must not contain whitespace, control characters, or a trailing
backslash; `SY_PORT` must contain only digits. `XDG_CONFIG_HOME` and `CODEX_HOME`
`SY_HOME` must be an absolute UTF-8 path without ASCII control characters.
`SY_PORT` must be a number from 1 to 65535. `XDG_CONFIG_HOME` and `CODEX_HOME`
set the systemd and Codex config directories.

Read server logs with `journalctl --user -u switchyard`. Routing records are
stored in `~/.switchyard/routing.jsonl`. Use `systemctl --user edit switchyard`
for service changes that survive reinstalling.

Remove the service and profile with `make uninstall-linux`. This also removes
Remove the service and profile with `cargo desktop uninstall`. This also removes
marked Codex aliases left by older installs from existing `.bashrc` and
`.zshrc` files. If upgrading an older install, uninstall first and run
`unalias codex` in any open shell. The server directory, routing records,
profile backups, and systemd drop-in files stay in place. Use the same path
overrides when installing and uninstalling.
profile backups, and systemd drop-in files stay in place. Uninstall uses the
recorded installation. Conflicting environment overrides require
`cargo desktop uninstall --settings FILE` to select it explicitly.

## Windows Desktop App

From PowerShell in the repository, run:

```powershell
cargo desktop install --dry-run
cargo desktop install
```

Windows needs the Rust MSVC toolchain, Visual Studio C++ build tools, and
[WebView2](https://v2.tauri.app/start/prerequisites/#windows).
The installer uses Task Scheduler for the current logged-in user. It installs
executables in `%LOCALAPPDATA%\Programs\Switchyard`, falling back to
`%USERPROFILE%\AppData\Local\Programs\Switchyard` when `LOCALAPPDATA` is unset.
It saves that location and adds a Start menu shortcut. Two independent tasks
start the server and desktop app after login with ordinary user privileges.
Quitting the app leaves the server running.

Run `cargo desktop install` again to build and install the current checkout.
This Cargo command waits for installation to finish. The app's source update
uses the saved checkout and runs from a temporary Rust executable so Windows
can release and replace the installed files; read `SY_HOME\logs\update.log` for
its progress and errors. The installed installer cannot install, update, or
uninstall its own installation, because Windows keeps a running program from
being replaced. Use `cargo desktop` from the source checkout instead.
The installer builds and validates before stopping the tasks. If a binary
replacement fails, it tries to restore the previous binaries. If restoration
also fails, the error names the directory containing recovery files.
Rerun installation if a later task or settings operation fails; the complete
installation is not one transaction.

Settings, server config, accounts, and routing history stay in
`%USERPROFILE%\.switchyard` unless `SY_HOME` changes the directory. Server and app
logs are in `SY_HOME\logs`. Model-list keys entered in Routes are saved in the
current user's Windows Credential Manager. Coding tools keep their own login files.

Use `cargo desktop uninstall` to stop and remove both tasks, the shortcut, and
the installed executables. Uninstall preserves settings, accounts, and history,
and makes a recovery copy of the Codex profile before removing it.

## Rust Libraries

Expand Down Expand Up @@ -128,3 +231,6 @@ uv run pytest tests/ -v

The `dev` dependency group contains testing and linting tools and is not exposed
in the published wheel metadata.

See the [desktop and terminal quickstart](crates/switchyard-desktop/README.md) for
first-run setup, reviewed settings changes, usage, recovery, and safe uninstall.
22 changes: 0 additions & 22 deletions Makefile

This file was deleted.

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ The standalone server is provided only for demos and local evaluation. It is not

[Evaluate routing locally](docs/operations/local_evaluation.md) with the standalone server and your own model pool, then [verify routing is active](docs/operations/local_evaluation.md#verify-routing-is-active).

The [desktop and terminal quickstart](crates/switchyard-desktop/README.md) covers
local installation, coding-tool connections, sessions, usage, recovery, and uninstall.

Agent-specific guides are available for [pi](docs/integrations/pi.md) and
[Oh My Pi](docs/integrations/oh_my_pi.md).

Expand Down
2 changes: 1 addition & 1 deletion crates/switchyard-desktop/src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ pub fn run(controller: Controller, settings: PathBuf) -> Result<(), String> {
_ => {}
})
.build(app)?;
// Like the menu bar app, the tray rereads usage on the settings interval.
// Like the earlier menu bar app, the tray rereads usage on the settings interval.
let handle = app.handle().clone();
std::thread::spawn(move || {
loop {
Expand Down
10 changes: 6 additions & 4 deletions crates/switchyard-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ at startup, and saved costs do not change when prices change. An unreadable or i
`--pricing-file` stops startup; the server does not use bundled rates instead.

The [pi guide](../../docs/integrations/pi.md#estimate-the-cost) explains how to supply
rates for your own models.
rates for your own models. The desktop app uses the same bundled rates by default.
For custom rates, point its `pricing_file` setting at the same TOML or JSON file as
the server's `--pricing-file`. Actual spending comes from recorded costs.

Clients can send `x-switchyard-origin: codex-cli` (or another client label) to include an
`origin` field in each routing record. Missing, empty, or non-text header values produce
Expand Down Expand Up @@ -301,7 +303,7 @@ rule to `~/.codex/rules/default.rules`. See Codex's
[Agent approvals & security](https://learn.chatgpt.com/docs/agent-approvals-security)
page.

The installer, `scripts/linux/install.sh`, does not overwrite an existing
The installer, `cargo desktop install`, does not overwrite an existing
`~/.switchyard/composite.toml`.
If you installed Switchyard before this route was added, add the
`[targets.reviewer]` and `[routes.codex_auto_review]` blocks to that file by
Expand All @@ -326,8 +328,8 @@ hand, then restart the server.
| `GET` | `/health` | Liveness |

Requests name a route by its `id`, so `POST /v1/chat/completions` with `"model": "switchyard/general"`
routes through the `[routes.general]` entry above. Any of the three request formats can address any
route, and the server translates between them.
routes through the `[routes.general]` entry above. The server translates between request formats
supported by the selected route and its forwarding clients.

Set the top-level `fallback_client` to an entry under `[llm_clients]` to proxy any otherwise
unmatched method and path through that client. The fallback client does not need a target. Requests
Expand Down
117 changes: 0 additions & 117 deletions scripts/common.sh

This file was deleted.

8 changes: 0 additions & 8 deletions scripts/linux/common.sh

This file was deleted.

Loading
Loading