Environment encryption and access
Understand local secrets, encrypted cloud sync, browser pairing, team access, and CI decryption.
LPM CLI environment commands keep secret values outside your repository. Local storage, cloud sync, browser access, and CI each have a separate access boundary.
lpm.json project identity, environment names, and validation rules
.lpm/env-sync.json this checkout's sync checkpoints, never committed
Local storage secret values for lpm dev and lpm run, kept per LPM home
LPM.dev Registry encrypted cloud copy and access metadata
Paired browser local decryption and editing
Approved CI job selected values over TLS after explicit decryption setupLocal secrets work without an account. Personal cloud sync requires Pro. Organization sharing requires an active Organization or Enterprise plan.
Configure a project
Store a value, inspect its name, then run your application:
lpm env set --env=development API_TOKEN=example-token
lpm env list --env=development
lpm dev --env=developmentThe first storage command adds a vault identifier to lpm.json. Commit this identifier with the project.
{
"vault": "7f3a1e2c-5b9d-4a8f-b6c1-9b1d2e3f4a5b",
"environments": {
"development": { "file": ".env.development" },
"production": { "file": ".env.production" }
},
"envSchema": {
"vars": {
"API_TOKEN": { "required": true, "secret": true }
}
}
}The identifier grants no access by itself. Moving or renaming the project preserves its identity. Removing the field creates a new identity on the next storage operation.
environments defines files and inheritance. envSchema defines validation rules. Neither field contains the stored secret values.
LPM CLI loads local secrets for lpm dev and lpm run. An explicit --env selects the environment for that run.
Cloud operations also record authority checkpoints for this checkout in .lpm/env-sync.json. These bind the Registry, account or organization, and accepted revision. The project's .lpm/ directory ignores itself, so the file is never committed, and each clone keeps its own. Keep this CLI-owned file intact.
Removing the file resets local rollback and account-binding protection for that checkout.
Earlier releases kept the checkpoints in lpm.json > vaultSync. Unless Git has it committed, LPM CLI reads them there until the next lpm env pull or lpm env push moves them; a committed vaultSync is ignored, and the next pull or push removes it. lpm doctor warns until then. Commit lpm.json after the move. lpm publish leaves both vault and vaultSync out of a published lpm.json.
Local storage
| Platform | Protection |
|---|---|
| macOS | The system Keychain stores the project secrets. |
| Linux | An encrypted file stores values. The operating-system credential store protects its key when available. |
| Windows | An encrypted file stores values. Credential Manager protects its key when available. |
Linux and Windows store encrypted files below vaults/ in the LPM home: ~/.lpm, or the directory that LPM_HOME names. A protected file fallback supports machines without a credential store at first use.
A home other than ~/.lpm keeps its own OS credential store entries, so its local secrets are separate from those of ~/.lpm. Project env values cannot set LPM_HOME for the scripts that LPM CLI starts.
After a key moves into the credential store, an unavailable store stops access. LPM CLI does not silently switch that key to file storage.
Import or export one environment:
lpm env import --env=production .env.production
lpm env export --env=production .env.production.backupCAUTION: Exports contain plaintext secrets. LPM CLI writes an export owner-only and adds a Git ignore rule for it, and it refuses a destination that Git tracks. Keep the file out of artifacts and delete it when you no longer need it. Normal
getandlistoutput masks values.
Personal cloud sync
Sign in, then push an encrypted copy:
lpm env diff
lpm env push
lpm env pull
lpm env log
# Approved non-interactive operations
lpm env push --yes
lpm env pull --yesA push replaces the complete cloud project. A pull replaces all local environments with the cloud copy. Human output mode requests confirmation unless you pass --yes.
Three separate keys
Personal projects use three layers:
| Key | Scope and purpose |
|---|---|
| Device root key | A random local key for one Registry origin and account. It protects that device's personal project keys. |
| Project key | An independent random key for one project. It protects that project's content keys. |
| Content key | A fresh random key for each push or browser save. It encrypts the complete payload. |
Normal sync uploads ciphertext and encrypted keys. The LPM.dev Registry cannot decrypt this data without an explicit project decryption opt-in.
Key protection binds the Registry origin, account, project, and key version. Content protection also binds the payload revision.
Each device has an independent root. A new device can create new projects, but it cannot open another device's existing projects without the correct root.
Before a push replaces an existing cloud project, LPM CLI authenticates and decrypts its current revision. Signing in alone does not authorize replacement of unreadable data.
Revisions and migration
Each successful push advances the revision, even with unchanged values. A concurrent change causes a conflict.
push --force can replace a newer revision after authenticated decryption. It still requires the correct key and does not bypass account binding or rollback checks.
Current clients can read supported older personal payloads with their existing local key. The next successful push or browser save migrates them to independent project keys.
Migration uses fresh project and content keys. It clears previous CI decryption material, disables policies, and revokes issued CI credentials.
After migration, enable CI access again with the complete policy and --allow-server-decryption. Older clients cannot write the previous key format.
The CLI and browser retain project-key checkpoints to reject older key versions. Removing local state also removes its local rollback protection.
Rotate a content key
lpm env rotate-keyThis command retrieves the complete cloud payload and encrypts it with a fresh content key. It preserves remote values and project metadata.
For a migrated project, ordinary rotation preserves the project key and its CI access. To revoke personal CI decryption, use oidc disable.
Organization access
Share the current project or retrieve its organization copy:
lpm env share --org=acme
lpm env pull --org=acmeAn organization pull immediately replaces all local environments. Export local values that you need to retain before the pull.
Each approved member receives an encrypted content key through their registered sharing key. Access covers the complete project, with no per-key permissions.
The first share and changed recipient sets require a review of identities and public-key fingerprints. After review, supply the exact printed digest:
lpm env share --org=acme --accept-recipient-keys=<64-character-digest>A stale digest fails. An unchanged, trusted recipient set needs no new acceptance flag.
Organization writes reject revision conflicts. share --force only recreates an absent project already bound to this checkout. It cannot overwrite an existing project.
Rotate after a member or key change
After member removal, an owner or administrator with current access must rotate the project content key:
lpm env rotate-key --org=acmeThe command encrypts all remote environments again for the current recipients. A concurrent membership or key change causes a conflict.
Rotation prevents old keys from opening future ciphertext. It cannot erase values or keys that a former member copied.
To replace your account sharing key, use:
lpm env rotate-sharing-keyThis command requires an interactive terminal, ROTATE confirmation, and step-up authentication. Owners or administrators must then share each affected project with you again.
After an interruption, rerun the command to resume a pending rotation. See the key rotation reference.
Pair a dashboard browser
- Open a personal or organization project on the dashboard Secrets page.
- Complete the step-up authentication prompt and copy the pairing code.
- On a CLI machine with the correct key, run:
lpm env pair <CODE>- Compare the two groups of four digits in the terminal and browser.
- If the numbers match, type
y.
The code expires after five minutes. The Registry relays the exchange but cannot calculate its temporary shared secret.
Personal pairing transfers the device root for the selected Registry and account. It can also transfer the legacy key needed for older projects.
Use a current CLI and a fresh pairing code. Retired personal pairing sessions cannot authorize writes to the current format.
A paired browser can open projects protected by that root. Pairing another device replaces the browser's personal pairing. Re-pair the original device to reopen its projects.
Organization pairing is separate. It transfers your registered account sharing key and permits access only to projects shared with your account.
Owners, administrators, and maintainers can edit organization values. Other members have read access. The Registry checks current membership and key state before each save.
After a sharing-key change, pair again. After member removal, complete organization rotation before browser saves resume.
CAUTION:
--yesskips the comparison prompt. Use it only for a command copied from your trusted dashboard.
Revoke browser sessions:
lpm env unpairRevocation stops further server access through those sessions. It cannot erase plaintext or keys that a browser already copied.
Pairing transfers keys to the browser. It does not transfer them to another CLI machine.
Explicit CI decryption
OIDC supports personal Pro projects and active Organization or Enterprise projects. Supported providers are GitHub Actions and GitLab.com CI.
Personal setup requires a current cloud project and an explicit decryption opt-in:
lpm env push --yes
lpm env oidc allow \
--allow-server-decryption \
--provider=github \
--repo=owner/repository \
--workflow=.github/workflows/deploy.yml \
--branch=main \
--env=production
lpm env oidc listFor private GitHub repositories, supply GITHUB_TOKEN, GH_TOKEN, or --repository-id=<numeric-id>. The policy binds the repository name and immutable ID.
Personal activation authenticates the current encrypted revision, then sends only its project key. The device root and legacy global key stay local.
The Registry validates the captured revision and key before it commits the complete policy and encrypted escrow together. Failed activation preserves the previous state.
An organization owner or administrator adds --org=<slug> and --allow-server-decryption after a share or pull. Organization setup transfers only the current project content key.
This opt-in gives the Registry decryption capability for the complete project. Environment allowlists restrict authorized CI responses. They do not create separate encryption boundaries.
Each oidc allow replaces the complete policy. Review oidc list before changing branches, environments, workflows, or events.
Store the returned policy UUID as LPM_OIDC_POLICY_ID in trusted CI configuration. It selects the policy but grants no access without a valid CI identity token.
The approved job can retrieve its environment:
lpm env pull --oidc --env=production --output=.envSee the OIDC reference for complete GitHub Actions and GitLab.com workflows.
Disable CI access
lpm env oidc disable
lpm env oidc listPersonal disable rotates both the project and content keys through an authenticated cloud update. It preserves values, clears escrow, disables policies, and revokes issued credentials.
A conflict leaves the previous cloud state intact. Retry from a machine with current project access.
After a confirmed remote update, a local checkpoint failure produces a warning. Restore local storage or project-file access, then pull the latest revision.
Organization disable uses --org=<slug>. It clears escrow and revokes credentials without a content-key rotation, including during a billing lapse.
Organization content-key rotation or membership key invalidation also clears CI decryption access. Re-enable it explicitly after the current key is shared.
The policy list shows active and disabled policies. Re-enabling a policy never restores revoked credentials.
Deployment platforms
LPM CLI platform integrations send application values directly to Vercel, Coolify, Fly.io, Railway, or GitHub Actions.
lpm env connect vercel --project=<id> --linked-env=production
lpm env push --to vercel --env=production
lpm env statusThe LPM.dev Registry stores the encrypted platform credential and connection metadata. Application values travel directly between LPM CLI and the platform.
Cloud sync and platform updates are separate operations. If one operation fails, a successful change in the other remains committed.
Recovery
| Problem | Action |
|---|---|
| A push reports a conflict. | Export local changes to protected, ignored files. Pull the current revision, reconcile values, then push again. |
| A new CLI machine cannot decrypt a project. | Recover values from the original machine through a trusted method. There is no CLI-to-CLI key-transfer command. |
| A browser holds another device's root. | Pair again from the device that can open the project. |
| A browser reports an older project-key version. | Retrieve the latest project state. Re-pairing does not repair stale ciphertext. |
| Browser checkpoint storage is unavailable. | Restore browser storage access, then reopen the project. |
| A browser says changes were saved but the checkpoint failed. | The remote save succeeded. Restore storage access and reload the latest revision before further edits. |
| A browser save reports a conflict. | Preserve pending edits, reload the current project, then reconcile changes. |
| CI stops after personal migration or project-key rotation. | Run the complete oidc allow --allow-server-decryption command from a device with current access. |
| CI reports an unavailable server escrow-key version. | Wait for the Registry operator to restore that server key. Do not replace your local key. |
| Organization access shows Needs share. | Ask an owner or administrator to share the project with your current sharing key. |
| A platform update has an uncertain result. | Use status and compare the authoritative platform values before another update. |
See also
- lpm env — command reference and CI examples
- Local secrets — storage and application loading
- Managing secrets — practical workflows
- lpm.json — environment configuration
- Authentication — sessions and credential storage