Desktop companion
On this page
Run from sourceBuild and install locallyUse itConnect an application on another computerManage an outbound SSH tunnelManual SSH recipesHost lifecycle and private stateCheck and recover a saved hostVerification and previewThe local companion manages providers, Usagestat usage snapshots, application connections and local/remote hosts. The first preview is Linux x64. It uses the same SDK provider component and backend contracts as TypeScript, Python, Go and Rust applications.
The desktop is packaged with the 0.2.0 previews and RC. Its Linux archive and checksums are listed on the corresponding GitHub prerelease; the npm package is the SDK/host CLI, not a desktop installer. There is no automatic updater yet.
Run from source
From the SDK repository root:
npm ci
npm run build
npm ci --install-links --prefix apps/desktop
npm run prepare:runtime --prefix apps/desktop
npm start --prefix apps/desktopPreparation downloads Electron 44.4.5 and the official Node 24.21.0 Linux x64
runtime, with the Node archive checked against its pinned SHA256. The packaged
app includes both runtimes and does not require a system Node installation.
Native provider CLIs and Usagestat remain separately installed dependencies.
The --install-links option installs a copy of the local SDK dependency for
packaging, instead of a link back into the source checkout.
Build and install locally
npm run package:linux --prefix apps/desktop
node apps/desktop/scripts/install-local.mjs apps/desktop/release/linux-unpackedLaunch AgenticDriver from the application menu. The installer uses
~/.local/share/agenticdriver/desktop and the user application-menu directory
(or XDG_DATA_HOME), retains previous preview versions, and does not install a
system service. The archive is
apps/desktop/release/AgenticDriver-0.2.0-rc.2-linux-x64.tar.gz.
Extract it and launch agenticdriver-desktop for portable use. No sudo or
--no-sandbox option is needed on the qualified Fedora desktop. Distribution
policies for user namespaces still apply; do not disable the renderer sandbox.
Re-run the build/install commands to update a source preview. To remove it,
close the app and remove the generated dev.agenticdriver.desktop launcher and
its agenticdriver/desktop installation directory. Keep its private app-data
profile if you want to preserve saved settings and connections. Removal does not
revoke grants on remote hosts; revoke those there first when appropriate.
Use it
- The app starts a separate empty local host with a stable loopback endpoint. Add a provider in Providers, using an existing official native session, owned Codex device sign-in, a write-only API key or an explicitly selected compatible gateway.
- In Connections, name the application, review its provider access and lifetime, choose where its backend will connect, then create a one-use invitation. Paste it into the application's AgenticDriver connection settings. Grant provider management only when that application should administer the host.
- Hosts can start/stop the desktop's host or pair with another host using
its invitation. A management grant enables remote provider editing. Local
invitations refer to this computer; remote access needs reachable HTTPS or
an existing secure tunnel. The app does not establish a NAT relay or open
firewall ports. Private CAs must be trusted by the bundled Node process
(for example through explicitly configured
NODE_EXTRA_CA_CERTS). - Usage reads the existing Usagestat service, initially
http://127.0.0.1:6736. Change its URL and optional write-only service token in that screen. The supported native endpoints areGET /v1/providersandGET /v1/usage; quota progress, resets and costs come from the backend's metric records. Source, stale data and missing measurements remain visible.
Usagestat's existing ingestion setup continues to own SDK-run storage and account/subject bindings; selecting a read endpoint here does not enable run capture or create bindings. See the SDK Usagestat guide. The app does not create a second accounting database or infer that a provider quota belongs to a particular SDK account. Presentation names/colors reuse Usagestat metadata where the configured provider ID matches; unbundled icons use the SDK's fallback mark.
Models reported by an account stay visible. Catalog discovery, host permissions,
application enablement and live qualification remain separate. No inference is
performed by onboarding or metadata refresh. Preview 0.1.0-alpha.2 adds Codex
device sign-in on qualified Linux x64 hosts, with a separate private account
profile and explicit confirmation after native verification. Other native
providers use existing sessions. No provider/account/model fallback is added.
Connect an application on another computer
The Connection route in Connections determines the address inside the
invitation. The destination preview does not contact that address, move operator
credentials or issue access. Creating an invitation does not prove the route is
reachable. These route controls and the recovery controls below require desktop
version 0.2.0-alpha.4 or later.
- On this computer uses the desktop's private loopback host. Choose this when the application backend runs on the same computer, not merely when its browser is open here.
- Another computer · HTTPS uses the reachable base URL of a TLS host or reverse proxy that routes to this selected host. Include any proxy path prefix. The SDK requires HTTPS without embedded credentials, query strings or fragments, and the connecting backend verifies the certificate. Configure the proxy separately; changing this field does not bind a new listener or open a firewall port.
- Another computer · SSH tunnel generates an invitation for a loopback port beside the application backend. Choose a free unprivileged port, then expand SSH setup instructions. Start one of the two displayed commands using your existing SSH access. A forward tunnel runs on the application machine and connects to the driver machine; a reverse tunnel runs on the driver machine and connects to the application server. Keep the chosen SSH session running.
Manage an outbound SSH tunnel
Desktop 0.2.0-alpha.5 or later adds SSH tunnels in Connections when This computer is selected. Earlier downloads retain their manual SSH recipes.
- Expand Add an SSH tunnel. Name it, enter an existing SSH alias or
user@hostname, and choose an unused application-server port such as17433. Saving the route does not contact the server. - Choose Start tunnel. The desktop uses
/usr/bin/sshand your existing native SSH configuration, keys or agent. Set up and verify that destination in a terminal first; password prompts and unknown/changed host keys are rejected. Use an SSH alias for IPv6, custom SSH ports or jump-host settings. - Choose Use for invitation, review the application name, provider access and lifetime, then create its invitation. The address is loopback on the selected application server. Pair from the backend there, not from a browser or a different container's network namespace.
Running means OpenSSH accepted the requested forwarding, not that the application has paired or a provider has passed inference. Stopped and Failed routes cannot create managed-tunnel invitations. Failures explain whether host trust, native sign-in, forwarding or reachability needs attention. Use Start tunnel to reconnect explicitly. The saved port stays the same; there is no automatic retry, port change, alternate server or transport fallback. Use Edit on a stopped route to correct its name, destination or port. A changed server or port requires a new invitation at that address in the application.
Stopping the tunnel or closing its local host ends only its owned SSH session. The desktop asks before interrupting active paired requests. A separate worker supervises OpenSSH and closes it if the owning desktop worker disconnects. Saved tunnels remain stopped when the desktop next opens. Existing application grants survive a tunnel restart and still expire or revoke on the SDK host; Remove forgets the route, not those grants. Revocation blocks new authorized requests and does not cancel an already-running request.
This is an optional outbound OpenSSH integration, with no hosted relay service.
It needs no inbound laptop listener beyond the existing private SDK host and no
new firewall rule on that laptop. The selected SSH server is a trusted transport
endpoint: SSH encryption ends there, and its administrators can observe traffic
on its loopback interface. Provider API keys and native login files stay on the
execution computer; scoped application bearer credentials travel inside SSH.
The SSH server must permit remote forwarding and honor the requested
127.0.0.1 bind (for example, GatewayPorts no). A server configured to override
bind addresses can widen the listener; the desktop does not change that policy.
Each tunnel owns a private control socket. The initial SSH connection clears
ambient port forwards; a separate multiplexing request adds exactly the chosen
route. Agent/X11 forwarding, LocalCommand, RemoteCommand, password prompting,
background persistence and host-key updates are disabled. User-owned SSH
configuration remains trusted native configuration, including any Match exec,
proxy or jump commands it deliberately contains. The desktop accepts no shell
command, key contents or SSH password through its renderer or the remote SDK API.
Provider-key environment variables and Node preload settings are not passed to
SSH. See OpenSSH options and
configuration.
Managed tunnels are qualified on Linux only. CLI users and other platforms can keep using the manual recipes below; direct local and verified HTTPS connections remain independent of SSH.
Manual SSH recipes
For example, if this desktop listens on 127.0.0.1:7433 and the application-side
port is 17433, choose one direction:
# On the application backend machine:
ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:17433:127.0.0.1:7433 USER@DRIVER_HOST
# Or on the driver machine, connecting outward to the application server:
ssh -N -o ExitOnForwardFailure=yes -R 127.0.0.1:17433:127.0.0.1:7433 USER@APP_SERVERReplace the uppercase destination with your existing SSH account and hostname;
use the actual port shown by the desktop. The invitation then targets
http://127.0.0.1:17433/ on the application machine. Both recipes request a
loopback-only listener and stop when initial forwarding setup fails. The SSH
server must permit forwarding and honor the bind address; a successfully started
tunnel still does not prove that its ultimate target is reachable.
See the OpenSSH forwarding options.
The manual route displays these commands without running them. AgenticDriver does not manage SSH keys, change server policy or provide a hosted relay. A containerized application has its own network namespace; place the tunnel beside its backend rather than assuming container loopback reaches the host OS. For remote hosts already saved in the desktop, use their saved address or an explicitly supplied HTTPS address; generate SSH recipes on the computer that owns the local host.
After establishing the route, create the invitation and paste it into the application's connection settings. Provider keys and native sessions remain on the execution host. Existing TypeScript, Python, Go and Rust invitation APIs consume this same address-and-one-use-code format without an API migration.
Host lifecycle and private state
The app stores its own driver subdirectory under Electron's userData directory.
settings.json contains the selected host and stable local port. local/config.json
is the SDK-managed provider configuration; operator, provider and paired-client
credentials are separate private files. connections/<id>/profile.json uses the
normal SDK connection-profile contract. It never adopts or changes an existing
LitAgent, synthetic-validation or CLI host.
AGENTICDRIVER_DESKTOP_DATA=/private/directory selects a separate desktop profile
for development or testing. One desktop process owns a profile. A stale lock is
recovered only after its process no longer exists. An occupied saved host port
fails instead of attaching to another service or silently changing the endpoint.
Closing the app stops its local host. It asks before interrupting active paired requests. Connection activity is process-local HTTP observation, including metadata requests; it is not persistent online presence or usage accounting. Static credentials are outside the pairing list. Refreshing metadata does not cancel runs. Remote host removal forgets this app's saved credential without stopping that host.
Check and recover a saved host
In Hosts, pasting an invitation first shows its destination. This preview only parses the invitation; it does not contact the host or exchange the code. Check that the address is reachable from this computer before choosing Connect host. A loopback address reaches this computer, including an existing local tunnel; it does not identify the remote machine automatically.
Check connection reads the host's authenticated protocol endpoint. It reports the last check time, protocol version and whether the credential grants provider management. It performs no model calls and does not certify provider credentials or model availability. Status is a dated observation, not continuous presence. Expired, revoked, unreadable, unreachable, incompatible and untrusted-certificate connections show their next recovery step. TLS verification stays enabled.
Expand Connection settings to rename a host or Reconnect this host with a fresh invitation for the same address. Reconnection preserves the saved host ID, name and provider preferences. A different destination must be added as another host. A successful exchange writes a new private profile and atomically switches the saved host to it; a failed exchange leaves the previous profile unchanged. Old profiles remain private for clients already using them. Their grants still expire normally or can be revoked explicitly by the host operator. Reconnecting does not revoke grants or cancel active requests.
If the exchange succeeds but settings cannot be saved, the app retains both
profiles and reports the uncertain state. Reconcile the newly issued grant on the
host before creating another invitation; the app never repeats an exchange
automatically. The active private profile filename is recorded in settings.json
and is not exposed to the renderer. Removing the saved host removes these local
copies without revoking the host-side grants.
The renderer is sandboxed, has context isolation and no Node integration. A narrow, validated IPC interface reaches a separate Node worker; long-lived credentials stay there. The renderer loads only packaged assets through a restricted local protocol, and new windows/navigation are denied except selected documentation links and the exact official Codex device page opened by the user. This is local transport access control; applications retain their existing authentication stack.
Verification and preview
The desktop starts an empty actual local host. Add a real provider through the provider panel or pair with an existing host. Account status and usage come from those real connections. A connection check is distinct from a completed model run.
npm run preview --prefix apps/desktop opens a separate development profile with
the actual controller and SDK. It does not seed providers, usage or connections.
The former --fixtures mode and embedded simulated renderer smoke harness were
removed. Pure IPC/security and packaging checks remain in npm test --prefix apps/desktop.
Use real connection checks for provider acceptance.