LPM CLI

Secrets vault

Store environment secrets locally, sync encrypted copies, and share them with your organization.

Secrets vault keeps environment values outside your repository. Use lpm env to store values locally or sync an encrypted copy.

You can also share values with an organization or send them to a deployment platform.

There is no lpm vault command. The vault is the protected storage model. lpm env is the supported command surface.

How the secrets vault works

The vault separates project configuration from secret values:

lpm.json         → vault ID, environment names, and validation schema
Local vault      → secret values used by lpm dev and lpm run
LPM.dev Registry → encrypted cloud copy and access metadata
Platform         → values sent directly from LPM CLI

Commit lpm.json to the repository. Do not commit secret values, plaintext exports, or local vault files.

Choose a workflow

GoalPlan or scopeMain commands
Keep secrets on one machineAll planslpm env set, lpm env list
Store an encrypted personal cloud copyPro personal accountlpm env push, lpm env pull
Share secrets with a teamActive Organization planlpm env share --org <slug>
Give an approved CI job one environmentPro personal accountlpm env oidc allow, lpm env pull --oidc
Send values to a deployment platformPro or active Organization scopelpm env connect, lpm env push --to <platform>

Local storage does not require a paid plan. Cloud features require the applicable personal or Organization plan.

Project identity in lpm.json

A command that creates a vault adds a vault ID to lpm.json. For example, lpm env set creates the ID on first use.

lpm.json
{
  "$schema": "https://cli.lpm.dev/schemas/lpm.json",
  "vault": "7f3a1e2c-5b9d-4a8f-b6c1-9b1d2e3f4a5b"
}

The vault ID is an opaque project identifier. It is not a secret and does not grant access to stored values.

Commit this ID with the project. A renamed or moved project keeps the same vault because the ID does not depend on its path.

If you remove the vault field, the next vault-creation command makes a new ID. This action does not delete the previous local or cloud vault.

Cloud sync writes CLI-owned metadata below vaultSync. Its authority checkpoints bind each Registry and immutable user or organization identity to the highest accepted revision. Separate version and timestamp fields are non-authoritative summaries.

Do not edit or remove vaultSync manually. Removing its authority checkpoints resets local rollback and account-binding protection for this checkout.

Project configuration can also define environments and a validation schema:

lpm.json
{
  "environments": {
    "staging": { "file": ".env.staging" },
    "production": { "file": ".env.production" }
  },
  "envSchema": {
    "vars": {
      "DATABASE_URL": { "required": true, "format": "url", "secret": true }
    }
  }
}

The configuration describes environments and validation rules. It does not contain the secret values.

Store secrets locally

Store values in the default environment:

lpm env set DATABASE_URL=postgres://localhost/app
lpm env set API_KEY=...
lpm env list

Store values in a named environment:

lpm env set --env=staging API_URL=https://staging.example.com
lpm env set --env=production API_URL=https://api.example.com
lpm env list --env=staging

Without --env, local commands use the default environment.

Run a script with one environment:

lpm dev --env=staging
lpm run start --env=production

LPM CLI masks values in normal list and get output. Use --reveal only in a private terminal.

Local storage by platform

PlatformStorage
macOSThe system Keychain stores each project vault.
LinuxAn encrypted file stores the vault. The operating-system credential store protects its data key when available.
WindowsAn encrypted file stores the vault. Credential Manager protects its data key when available.

Linux and Windows store encrypted vault files below ~/.lpm/vaults/.

If the operating-system credential store is unavailable before first use, LPM CLI can use its protected file fallback.

After LPM CLI moves the key into the credential store, an unavailable store stops vault access. LPM CLI does not silently use weaker storage.

Import and export values

Import an existing dotenv file:

lpm env import --env=production .env.production

Export an environment:

lpm env export --env=production .env.production.backup

CAUTION: An exported dotenv file contains plaintext secret values. Store it securely and make sure that Git ignores it.

Sync a personal vault

A Pro personal account can store an encrypted cloud copy on the LPM.dev Registry.

lpm env diff
lpm env push
lpm env pull
lpm env log

lpm env push encrypts the complete local env project before upload. The LPM.dev Registry stores ciphertext and wrapped key data.

The LPM.dev Registry cannot decrypt values during normal cloud sync. The key that decrypts the payload stays with the local client.

lpm env push replaces the personal cloud vault with the local state. The interactive command asks for approval before upload.

lpm env pull replaces all local environments with the cloud state. The interactive command asks for approval before replacement.

Use --yes for an approved non-interactive operation:

lpm env push --yes
lpm env pull --yes

Each successful push advances the cloud version. If the known version is old, LPM CLI returns a conflict instead of silently overwriting newer data.

Share secrets with an organization

An active Organization plan can store one encrypted copy for the organization. Each approved member receives access through their sharing key.

Share the current env project:

lpm env share --org acme

Pull the organization copy:

lpm env pull --org acme

An organization pull merges remote keys into the matching local environments. A remote value replaces the local value for the same key.

Organization sharing has version-conflict protection. lpm env share --force does not overwrite an existing organization vault.

If a conflict occurs, pull the organization copy. Then reconcile the values and repeat lpm env share --org <slug>.

If an owner or administrator deleted the remote vault, a bound checkout can recreate it:

lpm env share --org <slug> --force

The checkout must have the same organization binding and a stored revision checkpoint. The command stops unless the exact remote vault is missing.

The recreated vault starts one revision after the stored checkpoint. Other organization and Registry checkpoints do not change.

Organization members receive access to the complete env project. The vault does not support permissions for individual keys.

Each member wrap includes the recipient key version and full SHA-256 fingerprint. It also includes the organization content-key version.

The server compares these bindings with the current database state before each pull. An absent or stale binding fails closed as Needs share.

Rotate an organization content key

After you remove a member, rotate each affected organization env project:

lpm env rotate-key --org acme

An organization owner or administrator must run this command from a machine with current access.

The CLI pulls the complete remote payload and creates a fresh content key. It re-encrypts all environments without changing their values.

The server locks the current member and public-key rows before the write. It rejects a stale or incomplete recipient set.

The server replaces the ciphertext and all member wraps in one transaction. A compare-and-swap conflict leaves the previous state unchanged.

This rotation prevents a removed key from decrypting future ciphertext. It cannot erase data or content keys that a former member copied.

Rotate your sharing key

If the account sharing key is exposed, rotate it:

lpm env rotate-sharing-key

This command requires an interactive terminal. It asks you to type ROTATE, then requests a password or authenticator code.

The rotation invalidates your existing organization access entries. An owner or administrator must share each affected vault with you again.

If the command stops after the server accepts the new key, run it again. LPM CLI resumes the pending rotation.

Pair the dashboard

The LPM.dev Registry dashboard cannot read normal cloud vaults until you pair the browser with an existing CLI machine.

  1. Open the Secrets page in the dashboard.
  2. Complete the passkey, password, or authenticator prompt.
  3. Copy the six-character pairing code.
  4. Run the command on a CLI machine that already holds the vault key:
lpm env pair <CODE>

The browser and CLI exchange temporary P-256 public keys. Both clients derive an eight-digit number from the shared ECDH secret.

The number has two groups of four digits. Make sure that the terminal number equals the dashboard number.

Type y only when the numbers are equal. The Registry relays the public keys, but it cannot calculate the shared secret.

The pairing code expires after five minutes. Open a personal project to pair for personal access. Open an organization project to pair for organization access.

Personal and organization pairing are separate. Organization pairing requires the CLI machine with your registered sharing key. Both clients must use a version that supports organization pairing.

The browser stores your organization sharing key as a non-extractable key, bound to your account. It decrypts only projects shared with your current account.

Owners, administrators, and maintainers can edit values in the browser. Other members can view values. The server checks membership and subscription access again before each save.

After a member removal, an owner or administrator must run lpm env rotate --org <slug>. Browser saves remain disabled until this rotation completes.

If your sharing key changes, pair the browser again. An owner or administrator must also share the current environment key with your account.

CAUTION: Do not use --yes for a code from an untrusted source. This flag skips the browser-identity prompt.

Revoke all browser pairings:

lpm env unpair

Browser pairing sends an existing CLI key to the browser. It does not install the existing key on another CLI machine.

Add a passkey for sensitive actions

Open Dashboard > Settings > Security. In Passkeys, enter a name and select Add passkey.

The dashboard first requests your current step-up credential. Your device then requires a screen lock, fingerprint, face, or security key.

LPM stores the credential public key and signature counter. LPM does not receive your biometric data or device PIN.

After registration, the dashboard requires a passkey for browser pairing and passkey changes. Add a second passkey or use a synced password manager.

You can remove a passkey from the same settings page. Removal requires a recent, user-verified passkey assertion.

Use secrets in CI

OIDC access supports personal Pro projects and organization projects with explicit CI decryption setup. It supports GitHub Actions and GitLab.com CI.

Self-managed GitLab issuers are not supported. Organization projects require an active Organization or Enterprise plan.

First, push the personal vault. Then create a policy for the permitted workflow and environment:

lpm env push
lpm env oidc allow \
  --provider=github \
  --repo=owner/repository \
  --workflow=.github/workflows/deploy.yml \
  --branch=main \
  --env=production

The command prints a server-issued policy ID after it enables CI escrow. Store this UUID as LPM_OIDC_POLICY_ID in trusted CI configuration.

The policy ID is not a bearer credential. A valid GitHub Actions or GitLab.com identity token is still required.

LPM CLI gets the immutable numeric repository ID from the GitHub API. For a private repository, set GITHUB_TOKEN or GH_TOKEN.

You can also pass the ID directly:

lpm env oidc allow \
  --provider=github \
  --repo=owner/repository \
  --repository-id=123456789 \
  --workflow=.github/workflows/deploy.yml \
  --branch=main \
  --env=production

The policy requires the repository name and numeric ID. A renamed or transferred repository must update its policy before CI access resumes.

If an existing policy has no repository ID, OIDC pulls fail closed. Run lpm env oidc allow again to update it.

The approved workflow can pull the selected environment:

lpm env pull --oidc --env=production --output=.env

The pull requires LPM_OIDC_POLICY_ID. You can use --policy-id=<uuid> to override the environment variable.

OIDC changes the normal trust boundary. For personal projects, LPM CLI sends the wrapping key to the Registry over TLS. For organization projects, it sends only the current project content key. The Registry encrypts the key before storage.

The LPM.dev Registry can then decrypt the selected environment for an authorized CI identity. It sends the values to the job through TLS.

OIDC access requires an opt-in for each project. For organizations, an owner or admin runs lpm env oidc allow --org=<slug> --allow-server-decryption with the complete provider policy. The command authenticates and decrypts the current shared revision before transferring its content key.

The LPM.dev Registry encrypts escrow material with a versioned server key. Personal escrow is bound to the server key version, project ID, and account ID. Organization escrow binds the server key version, project ID, organization ID, and content-key version.

Organization content-key rotation or membership key invalidation clears CI escrow and revokes issued tokens. An owner or admin must enable decryption again for the current key. lpm env oidc disable --org=<slug> disables access immediately, including during a billing lapse. Re-enabling access does not restore revoked tokens.

The LPM.dev Registry can rotate this server key. The env values and OIDC policy do not change. The rotation writes an env audit entry.

An oidc allow command replaces the complete policy instead of adding one value. Before you change a policy, inspect it:

lpm env oidc list

See the lpm env OIDC guide for GitHub Actions and GitLab.com examples.

Send values to a deployment platform

LPM CLI can send local values to these platforms:

PlatformValue behavior
VercelLPM CLI can compare, push, clean, and pull readable values.
CoolifyLPM CLI can compare, push, clean, and pull readable application values.
Fly.ioSecrets are write-only. Pull reports names but cannot recover values.
RailwayLPM CLI can compare, push, clean, and pull service or shared values.
GitHub ActionsVariables are readable. Secrets are write-only.

Connect a platform, then send an environment:

lpm env connect vercel --project=<id> --linked-env=production
lpm env push --to vercel --env=production
lpm env status

Application values travel directly from LPM CLI to the platform. They do not pass through the LPM.dev Registry.

The LPM.dev Registry stores the encrypted platform credential and connection metadata. It handles the credential during connection and later retrieval.

Cloud storage and platform deployment are separate operations:

lpm env push                  # encrypted cloud copy
lpm env push --to vercel      # direct platform update

The two operations do not form one transaction. A successful operation remains successful after the other operation fails.

Security boundaries

BoundaryBehavior
Repositorylpm.json contains identifiers and rules, not secret values.
Local vaultThe operating system or an encrypted local file protects values.
Normal cloud syncThe LPM.dev Registry stores ciphertext and cannot decrypt the values.
Paired browserPersonal pairing transfers your wrapping key. Organization pairing transfers your account sharing key. Values decrypt in the browser.
OIDC escrowThe LPM.dev Registry can decrypt an approved environment for an authorized CI job.
Platform deploymentLPM CLI sends values directly to the selected platform.

Use lpm env log to read the latest audit entries for the current cloud vault:

lpm env log

The dashboard provides a longer audit view with filters.

Common recovery

A personal push reports a version conflict

Preserve each changed local environment before you pull. An export contains plaintext, so use a protected and ignored file:

lpm env export --env=staging .env.staging.local
lpm env pull

Reconcile the exported values with the pulled state. Then import the selected values and push again:

lpm env import --env=staging .env.staging.local --overwrite
lpm env push

Delete the plaintext recovery file after you make sure that the new cloud state is correct.

CAUTION: lpm env push --force bypasses version protection. Use it only after you inspect the local and cloud state.

A new CLI machine cannot decrypt a personal vault

Dashboard pairing does not transfer a vault key to another CLI machine. Use the original CLI machine to export the required environments through a trusted method.

Personal cloud sync does not currently provide a CLI-to-CLI key-transfer command.

A paired browser cannot decrypt the vault

Create a new dashboard pairing code. Run lpm env pair <CODE> on a CLI machine that holds the correct key.

An OIDC pull reports a stale escrow key

Run lpm env oidc allow again on the CLI machine that holds the current wrapping key.

An OIDC pull reports an unavailable escrow key version

The LPM.dev Registry configuration needs operator action. The pull fails and returns no secret values.

Do not replace the local wrapping key. Retry after the LPM.dev Registry restores the required server key.

Organization access stops after sharing-key rotation

Ask an organization owner or administrator to run lpm env share --org <slug> for each affected env project.

An organization member was removed

Run lpm env rotate-key --org <slug> for each affected env project. Use an owner or administrator machine with current access.

A platform update has an uncertain result

Run lpm env status. Then compare the local environment with the authoritative platform state before another mutation.

Current limits

  • Organization vaults do not support per-key permissions.
  • Organization CI decryption requires explicit owner or admin approval for the current project content key.
  • OIDC does not support self-managed GitLab.
  • Personal cloud sync does not provide CLI-to-CLI key transfer.
  • Cloud sync and platform deployment are not atomic.

See also