Getting started
Varlatch is self-hosted. One person on your team runs an installation, and
everyone else connects to it with the CLI and a passkey. This page takes you
from nothing to varlatch run:
- Get the CLI, on the installation’s host and on every developer’s machine.
- Run an installation, once per team.
- Set up a project, once per repository.
- Invite your team, and join as a teammate.
- Connect CI and other machines.
Already invited to an installation? Get the CLI, then go to Join a project.
Using a coding agent? It can do most of this for you, from installing the
CLI to moving your .env files in: Set up with a coding agent.
What you need
Section titled “What you need”- For the installation: a Linux host, amd64 or arm64, with Docker and Docker Compose 2.24 or newer, and a way for people to reach it: a domain name pointing at the host, a Tailscale network, or your own reverse proxy. Run an installation explains the choice, and Host requirements lists memory, disk, and ports.
- For each person: Node.js 22, 24 or 26 with its current security fixes for the CLI (Node.js version), and a browser that supports passkeys. Varlatch has no passwords: you sign in with a passkey kept on your device, in a password manager, or on a security key.
Get the CLI
Section titled “Get the CLI”The CLI is one file, varlatch-cli-<version>.cjs, attached to every
release. It needs only Node.js: Node.js version. Use
the version your installation runs: the CLI and the installation are
released together.
V=0.21.0 # the release your installation runscurl -fLO https://github.com/varlatch/varlatch/releases/download/v$V/varlatch-cli-$V.cjscurl -fLO https://github.com/varlatch/varlatch/releases/download/v$V/SHA256SUMSsha256sum --ignore-missing -c SHA256SUMSReleases after 0.15.0 also sign SHA256SUMS: check that signature
first, as Verifying a release describes.
On macOS, check the file with
grep " varlatch-cli-$V.cjs\$" SHA256SUMS | shasum -a 256 -c -.
Then put it on your PATH as varlatch:
-
On your own machine, a directory you own, so that
varlatch self-updatecan replace it withoutsudo:Terminal window mkdir -p ~/.local/bininstall -m 755 varlatch-cli-$V.cjs ~/.local/bin/varlatchvarlatch --version -
On the installation’s host, root-owned, as the backup runbook’s Install the operator CLI describes. Replace it after every upgrade.
-
On Windows, a directory you own, with a small
varlatch.cmdthat starts it: On Windows below.
varlatch self-update installs a newer release the same way: it checks the
file against SHA256SUMS, and the signature when the release is signed and
cosign is installed.
Node.js version
Section titled “Node.js version”The CLI runs on Node.js 22, 24 or 26, from a release with that line’s security fixes: at least 22.23.4 on 22, 24.22.1 on 24, or 26.12.1 on 26. These are the Node.js security releases of 21 October 2026, which fixed, among others, a flaw in decompressing Brotli data received over the network (CVE-2026-111497).
On an older release, on a line that no longer receives security fixes
(such as 20, 23 or 25), or on a prerelease (a nightly or release candidate,
whose fixes its version cannot show), every command first prints one
warning on stderr, and otherwise works as before: its output and exit
status do not change. Only varlatch agents hook, which a coding agent’s
guardrail calls on every tool call, stays quiet. Update Node.js to clear
the warning. If your Node.js carries those fixes
under an older version number, as a distribution’s backport can, set
VARLATCH_NODE_CHECK=off to hide the warning.
On Windows
Section titled “On Windows”Install a current Node.js LTS release (Node.js version), for example with winget:
winget install OpenJS.NodeJS.LTSIn a new PowerShell window, so that it finds node, download the CLI and
SHA256SUMS, and check the file against its line in SHA256SUMS:
$V = "0.21.0" # the release your installation runscurl.exe -fLO "https://github.com/varlatch/varlatch/releases/download/v$V/varlatch-cli-$V.cjs"curl.exe -fLO "https://github.com/varlatch/varlatch/releases/download/v$V/SHA256SUMS"$Line = Get-Content SHA256SUMS | Where-Object { $_ -like "* varlatch-cli-$V.cjs" }$Hash = (Get-FileHash -Algorithm SHA256 "varlatch-cli-$V.cjs").Hashif ($Line -and $Hash -eq ($Line -split " ")[0]) { "OK" } else { "MISMATCH: do not install this file" }It must print OK. Releases after 0.15.0 also sign SHA256SUMS: check
that signature first, as Verifying a release
describes.
Then install it as %LOCALAPPDATA%\Programs\Varlatch\varlatch.cjs, with a
varlatch.cmd next to it that runs it with Node.js, and add that directory
to your user PATH:
$Dir = "$env:LOCALAPPDATA\Programs\Varlatch"New-Item -ItemType Directory -Force -Path $Dir | Out-NullCopy-Item "varlatch-cli-$V.cjs" "$Dir\varlatch.cjs"Set-Content -Path "$Dir\varlatch.cmd" -Value '@node "%~dp0varlatch.cjs" %*' -Encoding Ascii$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")if (-not $UserPath) { $UserPath = $Dir } elseif (($UserPath -split ";") -notcontains $Dir) { $UserPath = "$UserPath;$Dir" }[Environment]::SetEnvironmentVariable("Path", $UserPath, "User")$env:Path = "$env:Path;$Dir"varlatch --versionNew terminals find varlatch on their own; the second-to-last line makes
this one find it too. varlatch self-update replaces varlatch.cjs in
place, without administrator rights, because the directory is yours.
Varlatch for Windows, the tray
app, installs the CLI the same way.
Run an installation
Section titled “Run an installation”Skip this if someone already runs one for you.
On the host, download the deployment bundle of the same release, check it, and unpack it where the installation will live:
curl -fLO https://github.com/varlatch/varlatch/releases/download/v$V/varlatch-compose-$V.tar.gzsha256sum --ignore-missing -c SHA256SUMStar -xzf varlatch-compose-$V.tar.gzcd varlatch-$Vvarlatch setupRun it as a user who can use Docker. varlatch setup first asks how people
will reach Varlatch:
| Choice | Address | You need |
|---|---|---|
| public | https://vault.example.com, with a certificate a bundled Caddy obtains |
the name resolving to this host in public DNS, and ports 80 and 443 reachable from the internet |
| tailnet | https://<machine>.<tailnet>.ts.net, for members of your tailnet only |
a Tailscale auth key, and MagicDNS and HTTPS certificates enabled in the Tailscale admin console |
| external | whatever your reverse proxy serves; also for a LAN-only installation | a proxy forwarding to 127.0.0.1:8787, WebSocket upgrades included |
Choose carefully: the address is where passkeys are registered, so changing it later means everyone registers their passkey again.
Then setup does the rest, and tells you what it is doing:
- It generates every key and password the installation needs, as files in
./secrets, and starts the services. - It prints a one-time link. Open it and create the first administrator’s passkey. Setup waits until you have.
- It walks you through keeping the two recovery keys off this host: the Root KEK, which every stored value depends on, and the backup key. Without a copy of the Root KEK, a backup cannot be restored. Do not skip this.
- It finishes with
varlatch doctor, a read-only health check you can run on the host at any time.
If setup stops halfway, for a failed download, a reboot, or a cancelled passkey prompt, run it again: it continues where it stopped and never replaces a key it already made.
Next, schedule backups: Backup and recovery covers where they go and how to test a restore. The deployment guide covers every setup option, running on Coolify, and upgrades.
Set up a project
Section titled “Set up a project”Varlatch keeps configuration in organizations, which contain
projects, which contain environments such as development and
production. A project usually matches one repository. Its contract
lists the items the application needs, with a type for each and whether it
is a Secret, and Varlatch checks every environment against it.
Sign in from your machine. The CLI opens your browser, or prints the address to open, and you sign in with your passkey:
varlatch login --server https://vault.example.comCreate an organization and a project, either in the dashboard, which walks you through the same steps, or with the CLI:
varlatch org create acme "Acme" --server https://vault.example.comvarlatch project create api --org acme --server https://vault.example.comA project created with the CLI takes its contract from the repository.
Pass --managed to project create to edit the contract in the dashboard
instead.
Then, in the repository:
varlatch init --org acme --project api --server https://vault.example.comvarlatch env-create development --tier developmentvarlatch env-create production --tier productionvarlatch init writes varlatch.toml, which names the server, organization,
project, and default environment (development). It holds no credentials:
commit it, so everyone working on the repository uses the same project. It
also writes the files coding agents read, described in
Coding agents; --no-agent-files skips them.
Move an existing .env file in
Section titled “Move an existing .env file in”If the project already has a .env file, import it. The CLI reads the file
itself, so values never appear on the command line or in its output:
varlatch import .env --dry-run # the plan: names, types, Secrets; stores nothingvarlatch import .env --contract --delete-source # store the values, then delete the filevarlatch contract activate <revision> # the revision import printed--contract adds the items the contract does not have yet, each as a
Secret unless you name it with --plain <NAME>. The values go to the
default environment; fill another one the same way, for example with
varlatch import .env.production -e production.
Importing has the details.
Or start from a contract
Section titled “Or start from a contract”Describe the items in a .env.schema file in the repository:
# @required# @type=urlDATABASE_URL=
# @publicPORT=8080Then push and activate it, and set the values:
varlatch contract push --schema .env.schemavarlatch contract activate <revision> # the revision push printedvarlatch values set DATABASE_URL # a hidden prompt asks for the valueItems are Secrets unless marked @public.
The .env.schema format lists everything a
contract can say.
Run your application
Section titled “Run your application”varlatch validate # does the environment satisfy the contract?varlatch run -- npm run dev # the default environmentvarlatch run -e production -- node server.jsvarlatch run gives the values to your command as environment variables.
No file of secrets is written to disk. To go further:
varlatch types --out src/config.ts(orapp/varlatch_config.py) generates typed access to the configuration: Type generation.varlatch scan --install-hookadds a pre-commit hook that stops you from committing one of your Secrets: Secret scanning.
Invite your team
Section titled “Invite your team”Invite each person from the dashboard (Access, then Members), or from the repository with the CLI:
varlatch invite "Ada Lovelace" # a membervarlatch invite "Grace Hopper" --role admin # an organization adminEach invitation is a one-time link: send it to that person. No email is involved. Opening it creates their account and passkey.
Access is denied unless something allows it. A member can read and change development environments, read staging environments, and see only the names of production items. An admin can do everything in the organization. For anything else, such as a member who deploys to production, add a grant in the dashboard under Access.
When someone leaves the team, an admin removes them from the dashboard (Access, then Members, then the person’s menu), or with the CLI:
varlatch member remove "Ada Lovelace" --confirm "Ada Lovelace"varlatch member role "Grace Hopper" member # admin to member, or back with adminvarlatch member leave --confirm acme # leave an organization yourselfFrom their next request they reach nothing in the organization: the Grants given to them directly are revoked, and they leave every group and team. Their sign-in itself is not affected. What they set up, such as integrations, Connections, webhooks and machine credentials they were shown, keeps working: removal lists it for you to review. The last admin of an organization cannot be removed or leave.
Then see what they received, from the dashboard (Former members, then What they received) or the CLI:
varlatch member exposure "Ada Lovelace" # --json for one record per lineThe report lists each version of each value they received, how, and whether Varlatch still serves it, with what they could reach when they were removed and what they set up. Rotate what is still served, at the provider too: a new value in Varlatch does not revoke the old one there. Then mark each version as revoked at the provider; the report never does that on its own. It needs permission to read the audit log, and never shows a value.
Join a project
Section titled “Join a project”When you have been invited:
-
Open the link you were sent and create your passkey.
-
In your copy of the repository, which already has
varlatch.toml:Terminal window varlatch login --server https://vault.example.comvarlatch run -- npm run dev
On a machine without a browser, such as a server over SSH or a container, sign in with a code instead, approving it with your passkey on any other device:
varlatch login --server https://vault.example.com --start # prints an address and a codevarlatch login --server https://vault.example.com --wait # after you approved itvarlatch status shows where you are signed in and when the credential
expires.
Your passkeys
Section titled “Your passkeys”Your passkeys are listed in the dashboard under your account, then Security. Keep at least two, for example a laptop and a security key, so losing one device never locks you out.
Each passkey is either trusted or unconfirmed:
- Trusted: a passkey you created from a link: setting up the
installation, an invitation, or a link from whoever runs the server
(
varlatch admin reenroll, oradmin recoverfor an Installation Admin). Passkeys that existed before Varlatch began recording this are trusted too. - Unconfirmed: a passkey you added in the dashboard while signed in. To make it trusted, choose Confirm with another passkey and use one of your trusted passkeys with its PIN, fingerprint or face.
Why the difference: someone who stole your signed-in browser session could add a passkey of their own. They cannot confirm it without one of your trusted passkeys.
Signing in and approving a CLI sign-in work with any of your passkeys, and you can remove any of them, as before. What only a trusted passkey can do is approve a change that needs your approval, such as turning an organization’s security control down or off (Security controls and approvals). Once security controls can be enforced, an organization will also be able to require a sign-in with a trusted passkey that verified you.
If none of your passkeys is trusted, you cannot confirm one yourself: ask
whoever runs the server for a link (varlatch admin reenroll --identity <your identity id>). The passkey you create with it is trusted.
Organization admins can see on the organization’s Security page whether every admin has a trusted passkey, along with the security controls and what each would do (The Security page).
Connect CI and other machines
Section titled “Connect CI and other machines”Machines never use a person’s passkey. Create a machine identity in the dashboard, under Access, then Machines, and grant it the environments it needs: like a person, it starts with no access.
-
CI that issues OIDC tokens, such as GitHub Actions, needs no stored secret at all. Give a
ciidentity an OIDC binding: the token issuer (filled in for GitHub Actions), an audience you choose, and the subject your jobs’ tokens carry, such asrepo:acme/api:*. In the job, get the CLI as above, then sign in and run; on GitHub Actions, the job needs theid-token: writepermission:Terminal window varlatch login --server https://vault.example.com --oidc --org acme --audience <audience>varlatch run -e production -- ./deploy.shOn another CI system, pass its token with
--oidc-token. -
Servers and other workloads use a credential shown once when you create the identity. Store it where the machine keeps its secrets, and sign in with
varlatch login --server <url> --token-stdin < credential-file.Programs on one host can share an identity and its grants, each with a credential of its own that you revoke on its own. Issue another one in the machine’s Credentials panel in the dashboard, or with the CLI, which writes the token only to a new file that only you can read, never to its output:
Terminal window varlatch credential issue <identity-id> --name "backup job" --out backup-job.tokenvarlatch credential list <identity-id> # every credential, by namevarlatch credential revoke <identity-id> <credential-id>To find credentials that may no longer be needed, run
varlatch security report(--jsonfor the whole document). It lists the organization’s machine credentials that were never used, have not been used for 30 days, or never expire, each with its identity and when it was last used. It only reports: nothing is revoked or retired for you. It needsidentity.manage, ascredential listdoes. Short-lived credentials from OIDC sign-ins and agent-safe runs expire within an hour and are left out.To replace a credential, issue the new one, move the program to it, then revoke the old one.
A credential issued with an expiry (
--ttl) warns ahead: in its last 7 days, however long it was issued for, the machine’s Credentials panel marks it, every API response to it carries aVarlatch-Credential-Expiresheader, and the CLI, given it inVARLATCH_TOKEN, prints a warning on stderr (never on stdout). Credential expiry warnings has the details.A program can ask Varlatch which identity its credential belongs to:
GET /v1/meanswers with the identity, its organization, and the credential’s own name, and needs no grant. On the command line,varlatch whoamiprints the same for the credential the CLI would use (VARLATCH_TOKEN, else the stored one). A program that relies on the answer should use another way only when the server lacks theidentity.whoamicapability. A refused credential, a server error, or an identity it does not expect (another organization, a name outside its convention: identities can be renamed) is an error to report. Each call spends a use of a use-limited credential, so ask once and keep the answer.
To see what a machine can reach, open it in Access, then Machines, or ask the CLI:
varlatch identity reach deployer # an identity ID or name; --json for the whole documentIt lists the machine’s state and, per project and environment, what its
grants allow. Reading values where a tailnet requirement applies shows the
requirement as a condition, such as
needs tailnet example.ts.net: tag:prod: a request must come from a
device that meets it. The list checks no device and never shows a value.
It needs permission to read identities and policy.
Varlatch can also push an environment’s values to GitHub Actions, Coolify, or Convex, for platforms that keep their own copy: add an integration on the environment’s Integrations tab. Integrations lists the credential each platform needs and where to find every field.
With coding agents
Section titled “With coding agents”Varlatch lets a coding agent use a credential without being able to read it.
varlatch init already wrote the instructions agents read. Then:
- Coding agents: the skill, guardrails, and the agents Varlatch was evaluated with.
- Assisted mode: an agent driving the CLI with your sign-in, with every Secret masked in what it sees.
- Agent-safe runs: an agent that gets placeholders instead of Secrets.
- The MCP server, for MCP hosts without a shell.
A change that needs your approval (such as turning a security control down) never goes through on an agent’s word: the agent stops and shows you an address, and you approve with your passkey. See Security controls and approvals.
Delete a project or an organization
Section titled “Delete a project or an organization”Deleting a project erases every value of its environments at once, with no undo. Deleting an organization is a request: it freezes the organization at once, and runs after a waiting period (7 days unless you choose 1 to 30) and, when the organization has more than one admin, another admin’s approval. Any admin can cancel it until then. Both are in the dashboard (a project’s menu; Settings, then Delete organization), or:
varlatch project delete api --confirm apivarlatch org delete acme --confirm acme --after 14varlatch org deletion acme # the open request, with its IDvarlatch org delete acme --approve <request-id> # another adminvarlatch org delete acme --cancel <request-id>Deletion erases data from the live database only. Backups taken before it
keep the data until their retention removes them, values pushed to
platforms stay there, and copies people revealed or downloaded stay where
they are: rotate those at their provider. A GitHub App stays installed on
GitHub until you uninstall or delete it there. After an organization is
deleted, the people who could read its audit log export it with
varlatch audit export --deleted-org <organization-id>.
Where to go next
Section titled “Where to go next”CONTEXT.md: the vocabulary, from planes and identities to grants and contracts.- Scripting: JSON output and exit statuses.
- Threat model: what Varlatch guarantees, and what it does not.
CHANGELOG.md: what each release changed, and how to upgrade.

