DesktopSecrets/tplenv

Commit the .env. Keep the secrets.

Write references like keepass(…) or awssm(…) into a .env.tpl, check it into git, and let tplenv resolve them when your process starts. The values come from KeePass, your OS credential store or your cloud vault, and an AI agent working in your repository only ever sees the references.

.env.tpl
DATABASE_URL=keepass(&personal|/Dev/postgres)••••••••••••••KeePass AWS_SECRET_ACCESS_KEY=awssm(MyApp/Prod|secret_key)••••••••••••AWS GH_TOKEN=op(Private/GitHub Token|credential)••••••••••1Password DEPLOY_TOKEN=user(Enter deploy token)••••••••typed in APP_ENV=production

This is the whole file. Nothing in it unlocks anything, so it can sit in your repository next to the code.

See it in action

From a template in git to resolved values in your process, shared across a team, with an approval dialog you can turn on for every read.

Music: “Happy Beats / Business Moves Vol. 12” by ende.app, CC BY 4.0.

How it works

Three steps, and the second one is the only command you type.

  1. Write a .env.tpl

    Replace each credential with a reference to where it lives. Plain values stay as they are. Everyone on the team uses the same file; each person's own vault supplies their credentials.

  2. Start your command through tplenv

    A background process opens the vaults the template needs. You unlock a vault once, and it stays open for the time you set in the tray settings.

    tplenv run npm start
  3. Your program starts with the variables set

    The resolved values go straight into the environment of the program you started. They are never written to a file.

Working with AI coding agents

An agent reads your repository, runs your commands and needs API keys to do it. Give it the keys it needs and nothing it can stumble on.

  1. The agent reads your project

    It opens every file it thinks is relevant, .env.tpl included. All it finds there is where a key lives, never the key.

    what the agent sees in .env.tpl
    OPENAI_API_KEY=keepass(&personal|/AI/OpenAI)
    STRIPE_KEY=awssm(Shop/Stripe|test_key)
  2. You start it with the keys it needs

    Launch the agent through tplenv run. The resolved values sit in its environment, so the agent and every command it starts can use them.

    your terminal
    tplenv run your-agent
    # inside the agent's session
    OPENAI_API_KEY=••••••••••••
  3. It asks for more, you decide

    With approvals turned on, an agent that calls getsec on its own gets nothing until you answer this dialog. It shows which program asked and for which secret. Each decision is written to audit.log. The hardened build also asks for Windows Hello or a security key.

    DesktopSecrets
    Allow secret access?
    Process:
    C:\Program Files\Git\usr\bin\bash.exe
    Secret reference:
    keepass(&cloud|/AWS/Prod/secret-key)

Where secrets can come from

Mix sources freely in one template. Each line resolves on its own.

ReferenceReads fromRuns onExample
keepassKeePass .kdbx vaults, with wildcards, attributes, aliases and chained unlockingAllkeepass(vault.kdbx|/AWS/Prod/key)
wincredWindows Credential ManagerWindowswincred(MyApp/DBPassword|username)
keychainmacOS login keychainmacOSkeychain(MyApp|alice)
awssmAWS Secrets Manager, with JSON field selectionAllawssm(MyApp/DB|password)
awspsAWS Parameter Store, SecureString includedAllawsps(/myapp/prod/api-key)
azkvAzure Key VaultAllazkv(my-vault/db-password)
gcpsmGoogle Cloud Secret ManagerAllgcpsm(my-project/api-key)
vaultHashiCorp Vault KV, with token or AppRole loginAllvault(secret/data/myapp|password)
op1Password, through the signed-in op CLIAllop(Private/GitHub Token|credential)
userA prompt window; the value is typed in and stored nowhereAlluser(Enter deploy token)

Cloud sources use their standard sign-in, such as the AWS credential chain, an Azure CLI login or gcloud credentials. Full reference syntax in the README

What you get

Nothing to leak from the disk
Backups, synced folders and a careless git add . only ever see references.
One unlock per session
Enter a master password once. The vault stays open for the time you choose, then locks again.
Approve each read if you want to
Turn on a confirmation dialog for every retrieval. The hardened build asks for Windows Hello or a security key each time.
Load into your current shell
tplenv --apply-one-liner prints the command that sets the variables in the shell you are in, for sh, PowerShell and cmd.
One secret at a time
getsec resolves a single reference, handy in scripts and CI steps.

Aliases and chained vaults

Give vault files short names, and let one vault hold the master password of another. You unlock the first; the rest follow.

aliases.yaml
personal: C:\Vaults\personal.kdbx

cloud:
  file: C:\Vaults\cloud.kdbx
  master: keepass(&personal|Cloud Master)
.env.tpl
# opens personal.kdbx first, then cloud.kdbx with the password stored there
SECRET=keepass(&cloud|/Prod/api-key)

Install

The script downloads the latest release, checks it against the published SHA256 sums and puts tplenv and getsec on your PATH.

Windows
irm https://it-atelier-gn.github.io/desktop-secrets/install.ps1 | iex
Linux
curl -fsSL https://it-atelier-gn.github.io/desktop-secrets/install.sh | bash

Read the scripts before you run them: install.ps1, install.sh. Binaries for Windows and Linux (x64), including the hardened variant, are on the releases page.

To use DesktopSecrets from Go, run go get github.com/it-atelier-gn/desktop-secrets and follow the library notes.

Built by Georg Nelles, freelance software engineer specializing in automation, modernization, and pragmatic tooling. DesktopSecrets is open-source. Your secrets stay on your machine.