Skip to content

Deploy the client

Install the client on every machine that runs an agent. The client is the decision point in the agent’s execution path: installing it connects every agent already present on the machine, and from then on each covered action is decided on the machine, before it runs, even when the console is unreachable.

Before you start, check these items:

#ItemWhere it comes fromBlocks
1The organization exists, and the people running the pilot can sign inConfigure the organizationEvery route
2One API key per rollout wave, held in your secret storeYour account’s API Keys pageThe managed routes only
3At least one agent installed on the target machine and signed in to its own accountThe agent’s own installerEvery route
4Egress approved, with streamed model responses exempt from buffering and inspectionNetwork requirementsEvery route
5The proxy scheme in force on the target subnet: direct, Basic, Negotiate, PAC, or TLS inspection with its root certificateThe team that manages your proxyThe managed routes

An agent that is absent when the install runs is not connected. Install the agents first, or run the install again afterwards; running it again is idempotent, so a repeat is never destructive.

Four routes reach the same end state. Pick by where the credential comes from and how many machines the route must reach, not by operating system. Most estates use two: the developer path for the pilot, and one managed route for the rest.

RouteBest forReachCredential
Developer pathWave 1: a pilot team enrolling itselfAbout ten machinesBrowser sign-in
Endpoint management script, user contextEstates already managed by Intune or JamfThe full estateWave key from the secret store
Configuration management or a pipeline stepLinux fleets and mixed estates with existing automation, such as AnsibleThe full estateWave key from a vault lookup
Container imageBuild machines and continuous integration runnersOne enrollment per jobRuntime secret, mounted per job

Three commands install the client. Which one you run depends on what the machine already has, not on the size of the estate:

MachineCommand
macOS or Linux, no runtime requiredThe install.sh script, below
Windows, no runtime requiredThe install.ps1 script, below
Any machine that already has Node.jsnpx @openlatch/client init. Node.js is what npx needs; the client is a native binary and needs no runtime
Install routesFour install routes, one end state: an enrolled machine with every agent wired.Developer pathEnrolled machine, agents wiredEndpoint management scriptConfiguration managementContainer image
Figure 1. Four install routes, one end state: an enrolled machine with every agent wired.

One command enrolls a machine. The install scripts carry the client, so the machine needs no runtime of its own. Run the line for the platform in front of you.

On macOS and Linux:

Terminal window
curl -LsSf https://openlatch.ai/install.sh | sh

On Windows:

Terminal window
powershell -ExecutionPolicy Bypass -c "irm https://openlatch.ai/install.ps1 | iex"

On a machine that already has Node.js:

Terminal window
npx @openlatch/client init

All three reach the same end state, so a team that already runs one of them keeps it. The scripts install the client under the user’s own home directory, add that directory to the PATH, and say that the current shell will not see it until it is restarted. They then run openlatch init by its full path, so the enrollment finishes in the same run. Where your estate does not reach the public package registry, OPENLATCH_NPM_REGISTRY points both the script and the client at your mirror.

StepWhat happensExpected
Check the route outThe egress check runs first, so a blocked route fails before anything on the machine changes. Nothing is left half-installedThe route out is reported, with the source that set it
Connect each agentEvery agent installed on the machine is connected, through that agent’s own configuration convention. Existing content in those files is preservedOne line per agent found, and an explicit line where none was found
AuthenticateThe order is OPENLATCH_API_KEY from the environment, then a credential already in the operating system’s credential store, then browser sign-in. A network error keeps a stored credential; only a rejection triggers a new sign-inThe account and organization printed back, or a browser window on an interactive terminal
Ask about product telemetryTelemetry is opt-out, and the choice is offered before any agent configuration is written. It carries command names, durations and error information, never contentA single prompt, and the choice in the closing report
Start with the user’s sessionThe client registers with the operating system’s own service manager, at user scope. A failure here is not fatal, because a headless session and a restricted scheduler are both survivableThe report states that the client will start again after a logout or a reboot
Prove it, then reportThe install confirms that the client is running, that each connected agent answers, and that the console can be reachedA closing report naming anything that needs attention, with the remedy beside it
Terminal window
openlatch status
openlatch doctor

A machine is installed when openlatch doctor reports no problem and the machine appears in the console’s agent record with its agents and an owner. Verify and roll out covers that check machine by machine and across a wave.

Every outbound call the client makes travels one egress route. Loopback traffic on the machine never travels it. The route is resolved setting by setting, so a flag can pin the proxy URL while the certificate bundle comes from elsewhere.

RankSourceUse it for
1Flags on the openlatch init commandPinning the route at enrollment time
2OPENLATCH_PROXY and its sibling variablesThe only channel allowed to carry a proxy credential
3The client’s own configuration, written at installWhat the client reads when it starts with the session, where no shell variables exist
4The standard https_proxy family of variablesAn estate that already exports them for every tool
5Operating system discoveryZero-configuration enrollment on a managed desktop
6DirectThe last resort. It can be refused, so that an unresolved route fails instead of going direct

Whatever made the install work is written into the client’s own configuration, with the source it came from. The client starts with the user’s session and inherits none of the installing shell’s variables, so a route that lived only in an environment variable would leave the machine going direct after the session ended.

Terminal window
openlatch init --proxy http://proxy.corp:8080 --ca-bundle /etc/ssl/corp-root.pem
openlatch init --proxy http://proxy.corp:8080 --proxy-auth negotiate --proxy-spn HTTP/proxy.corp

The certificate bundle is merged on top of the operating system trust store, never replacing it, and verification is never disabled. Negotiate uses the logged-on identity, with the service principal name defaulting to HTTP/ followed by the proxy host. NTLM is refused by design, so an NTLM-only estate needs a proxy-side change before enrollment.

A credential passed inside --proxy is refused, because command-line arguments are readable by every process on the host. Supply it through OPENLATCH_PROXY or answer the prompt on a terminal. Either way the password moves into the operating system credential store, never lands in a file on disk, and is masked in every log line.

A managed install runs the same script with three additions:

AdditionEffect
OPENLATCH_INSTALL_YESMakes the install unattended
OPENLATCH_NO_INITHolds back the enrollment the script would otherwise run at the end, so that your script runs openlatch init --yes itself. With --yes the enrollment never prompts: it fails and names what it needed
OPENLATCH_API_KEY in the environmentThe credential arrives from your secret store rather than through a browser

Run openlatch doctor as the last line of every script and collect its output, so that a machine that installed but is not fully connected stays visible instead of counting as done.

Endpoint management script, user context (Windows)

Section titled “Endpoint management script, user context (Windows)”
Terminal window
# Platform script, user context. Runs silently and cannot prompt.
$ErrorActionPreference = "Stop"
# The platform has no field that sets an environment variable, so the script
# fetches the wave key itself, as its first action. Replace this call with the
# one your secret store provides.
$env:OPENLATCH_API_KEY = Get-WaveKeyFromSecretStore
if (-not $env:OPENLATCH_API_KEY) {
Write-Output "the wave key could not be read from the secret store"; exit 1
}
$env:OPENLATCH_INSTALL_YES = "1"
$env:OPENLATCH_NO_INIT = "1"
powershell -ExecutionPolicy Bypass -c "irm https://openlatch.ai/install.ps1 | iex"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$openlatch = "$env:LOCALAPPDATA\openlatch\bin\openlatch.exe"
& $openlatch init --yes
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& $openlatch doctor
exit $LASTEXITCODE

$ErrorActionPreference does not stop the script when a native command fails, so the script checks $LASTEXITCODE after each one and returns it, and Intune reports the failure. Intune runs scripts silently and does not support interactive installation, which is why the install runs unattended and --yes is mandatory. The management extension fetches assignments on its own schedule, so plan a wave in days rather than minutes. A user-context script needs a signed-in user, and platform scripts do not reach devices that are only registered with Microsoft Entra ID; to reach personally registered devices, use the Win32 app route with an install behavior of User, which the no-elevation design makes possible.

No Intune setting defines an environment variable for a platform script. That is why the secret-store call is the script’s first action. Passing the key as an argument is not an option: the client refuses a credential in its own arguments.

Endpoint management script, user context (macOS)

Section titled “Endpoint management script, user context (macOS)”

Jamf passes its first custom value in parameter 4, which keeps the key out of the script body. The policy needs no packaging step of its own, because the install registers itself under the user’s home directory. Scope the policy to a user-level trigger so the enrollment runs as the developer rather than as root.

#!/bin/zsh
set -eu
# Parameter 4 carries the wave key, or replace this line with a secret-store call.
export OPENLATCH_API_KEY="${4:?wave key was not supplied}"
export OPENLATCH_INSTALL_YES=1
export OPENLATCH_NO_INIT=1
curl -LsSf https://openlatch.ai/install.sh | sh
"$HOME/.local/bin/openlatch" init --yes
"$HOME/.local/bin/openlatch" doctor

Configuration management or a pipeline step

Section titled “Configuration management or a pipeline step”
- name: Install the OpenLatch client
ansible.builtin.shell: curl -LsSf https://openlatch.ai/install.sh | sh
args:
creates: "{{ ansible_env.HOME }}/.local/bin/openlatch"
environment:
OPENLATCH_INSTALL_YES: "1"
OPENLATCH_NO_INIT: "1"
- name: Enroll the machine
ansible.builtin.command: "{{ ansible_env.HOME }}/.local/bin/openlatch init --yes"
environment:
# Or a vault lookup, so the value never lands in the play or in a fact.
OPENLATCH_API_KEY: "{{ lookup('env', 'OPENLATCH_API_KEY') }}"
- name: Report what the machine looks like
ansible.builtin.command: "{{ ansible_env.HOME }}/.local/bin/openlatch doctor"
changed_when: false

Run the enrollment against a sample of the wave before the full run, and read the report task’s output on those machines. A proxy scheme the install cannot discover shows up there rather than on every machine at once.

Container image and continuous integration

Section titled “Container image and continuous integration”
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
ENV OPENLATCH_INSTALL_YES=1 \
OPENLATCH_NO_INIT=1 \
OPENLATCH_NO_MODIFY_PATH=1 \
OPENLATCH_INSTALL_DIR=/usr/local/bin
RUN curl -LsSf https://openlatch.ai/install.sh | sh
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
entrypoint.sh
#!/bin/sh
set -eu
: "${OPENLATCH_API_KEY:?the runtime secret was not mounted}"
openlatch init --yes --no-persistence
exec "$@"
- name: Enroll the runner
env:
OPENLATCH_API_KEY: ${{ secrets.OPENLATCH_API_KEY }}
OPENLATCH_INSTALL_YES: "1"
OPENLATCH_NO_INIT: "1"
run: |
curl -LsSf https://openlatch.ai/install.sh | sh
"$HOME/.local/bin/openlatch" init --yes --no-persistence
"$HOME/.local/bin/openlatch" status

The base image carries nothing for the client: the script brings the client with it. The credential is mounted at run time, so no image layer holds it. OPENLATCH_NO_MODIFY_PATH stops the install writing a PATH line into a shell profile no interactive shell will read, and OPENLATCH_INSTALL_DIR puts the client where the image’s PATH already looks. --no-persistence skips the service manager, because a container has no user session to start into. Product telemetry is off in continuous integration without configuration. Ephemeral runners enroll on every job, and because a repeat install is safe, a retried job is safe.

The client installs and runs at user scope. No administrator rights are required, nothing is written to a system directory, and no service is registered at machine scope.

ItemDetail
One installed unitThe OpenLatch client, installed once per machine that runs an agent
Where it landsThe scripts put the client in ~/.local/bin on macOS and Linux, and %LOCALAPPDATA%\openlatch\bin on Windows, then add that directory to the PATH. OPENLATCH_INSTALL_DIR moves it. This is deliberately not the state directory below
FilesThe client keeps its configuration and local records in one directory: ~/.openlatch on macOS and Linux, %APPDATA%\openlatch on Windows. OPENLATCH_DIR moves it. Anything sensitive inside it is readable by its owner only
Agent configurationEach connected agent’s own configuration file gains an entry pointing at the client. Existing content is preserved, and what was there before is recorded so it can be restored
StartupThe client starts with the user’s session, under the operating system’s own service manager
CredentialsThe API key, and any proxy credential, live in the operating system credential store
Network postureListens only on the loopback interface. No inbound port is opened

openlatch uninstall disconnects every agent it finds on the machine, stops the client, and restores what it changed in each agent’s configuration. openlatch uninstall --purge also deletes the state directory and the stored credential. A purge is not a removal of the installed files: they sit outside the state directory, so a purge leaves them, along with the PATH line the script added. Operate covers removal in full.

  • Four install routes reach one end state. Pick by where the credential comes from and how many machines the route must reach, not by operating system.
  • The install scripts enroll a machine on macOS, Windows and Linux with no runtime required; npx @openlatch/client init reaches the same end state where Node.js is present. Either way the install detects the agents present and connects each one, and running it again is safe.
  • Some agents ask the developer to confirm the connection once. A machine is not finished until that has happened.
  • A machine is installed when openlatch doctor reports no problem and the machine appears in the console’s agent record with its agents and an owner.
  • One API key per wave, read from your secret store at run time, never in a script, a package or a command line.