TForge is a local‑first vault and secret management tool for application developers. It lets you:
- define environment variables and secrets per vault and per environment (
dev,staging,prod) - store them encrypted at rest on your machine
- inject them into any local command (e.g.
npm run dev,docker compose up, etc.) without ever writing a.envfile in plaintext
The project is heavily inspired by keypo-cli,
specifically the vault exec workflow in keypo-signer, and adapts similar ideas to a
cross‑platform Go + Wails desktop app.
Credits
Huge thanks to the authors ofkeypo-clifor the original design and inspiration. TForge deliberately reuses the idea of “run a command with secrets injected as environment variables, without ever touching a.envfile”.
TForge consists of three main pieces:
-
Wails Desktop App (
wails dev/wails build)- UI to create vaults, group keys, manage per‑environment values (
dev,staging,prod) - state is kept in memory via
internal/vault.Service - changes are persisted in encrypted form via
internal/storage+internal/secure
- UI to create vaults, group keys, manage per‑environment values (
-
Local Agent / Daemon (
cmd/tforge-agent)- small HTTP server bound to
127.0.0.1:5959 - loads the same encrypted vault file as the GUI and exposes a minimal RPC API:
GET /healthGET /env?vault=<nameOrID>&env=<dev|staging|prod>
- returns a JSON map
{ "env": { KEY: VALUE, ... } }for the requested vault and environment
- small HTTP server bound to
-
CLI Runner (
cmd/tforge)- command‑line front‑end that talks to the agent and starts arbitrary processes with injected env vars
- two main modes:
- exec mode: start a process with env from a vault
- export mode: print
KEY=VALUElines for integration with other tooling
The storage format is local‑only, there is no cloud backend.
Status / Security disclaimer
TForge is currently a personal proof‑of‑concept and not a production‑ready tool. The security model and implementation have not been professionally reviewed or audited. Do not use it to store highly sensitive secrets in environments with strict security or compliance requirements.
Persistent state lives under the OS config directory, e.g. on Windows:
ConfigDir()→%APPDATA%\TForge- vault data file:
vaults.bin
The code paths are:
-
internal/storage/vault_store.goConfigDir()– base config pathLoadVaults()/SaveVaults()– read/write encrypted blob
-
internal/secure/protector.go+ platform‑specific defaults ininternal/secure/protector_default*.goProtectoris the abstraction used by the app and agent- on Windows,
NewDefaultProtectoruses aDPAPIProtector(Windows DPAPI, bound to the current user account) and falls back toSoftwareProtectoronly if DPAPI is not available - on macOS/Linux,
NewDefaultProtectorfirst tries a keyring‑backedKeyringProtector(Keychain / Secret Service via the OS keyring) and falls back toSoftwareProtectorwith a local AES‑256 key stored in the config directory if the keyring is not available Seal()/Unseal()encrypt/decrypt the JSON‑encoded vault list
The Wails app and the tforge-agent both use the same storage layer and call
NewDefaultProtector, so they always see the same encrypted vault state for
the current user.
-
DPAPIProtector (Windows)
- Uses the Windows Data Protection API (DPAPI) and is bound to the current user profile.
- Encrypted vault data can only be decrypted under the same Windows account.
- This avoids having to manage a separate key file, but you still need to protect your Windows account (login password, disk encryption, etc.).
-
KeyringProtector (macOS / Linux)
- Uses the OS keyring (e.g. Keychain on macOS, Secret Service/gnome‑keyring on Linux) to store a randomly generated AES‑256 key.
- Requires a working desktop keyring; on minimal/headless Linux systems without a keyring
implementation, the keyring lookup will fail and TForge falls back to
SoftwareProtector. - When the keyring is available, the raw AES key is never stored in plaintext on disk.
-
SoftwareProtector (all platforms, fallback)
- Stores a random AES‑256 key in
master.keyunder the config directory and uses it to encryptvaults.bin. - This is the simplest and most portable option, but you are responsible for backing up
master.keyif you want to move vaults between machines, and you must protect access to the config directory itself.
- Stores a random AES‑256 key in
Migration note
Older versions used onlySoftwareProtectorwith a localmaster.keyfile. Current builds on Windows use DPAPI by default; existing installations should migrate their vaults before dropping legacy artefacts or switching machines.
The core data model (internal/vault/vault.go):
-
VaultID,Name, optionalIcon,DescriptionEntries []Entry
-
EntryKey– final environment variable name (e.g.POSTGRES_HOST)ValueDev,ValueStage,ValueProd– per‑environment valuesType–"env","secret","note"(UI uses this to style entries)GroupPrefix– optional grouping prefix (e.g.POSTGRES_) for nicer UI
The Wails frontend allows:
- grouping keys via
GroupPrefix(e.g.POSTGRES_→POSTGRES_HOST,POSTGRES_USER, …) - editing values for
dev,staging,prod - bulk adding keys within a group
- duplicating
devvalues intostagingorprodvia the custom context menu
Located in cmd/tforge-agent/main.go.
Responsibilities:
- initialize
secure.Protectorandvault.Service - load
vaults.binon startup viastorage.LoadVaults - serve a tiny HTTP API on
127.0.0.1:5959:
GET /health
-> 200 OK, body: "ok"
GET /env?vault=<nameOrID>&env=<dev|staging|prod>
-> 200 OK, JSON: { "env": { KEY: VALUE, ... } }
-> 404 if vault not found
POST /lock
-> 200 OK, body: "locked"
POST /unlock
-> 200 OK, body: "unlocked"
GET /status
-> 200 OK, JSON: { "locked": true|false, "timeoutSeconds": <int> }
POST /reload
-> 200 OK, body: "reloaded"POST /reloadre-readsvaults.binand updates the in-memory vault list. The CLI calls this automatically after--create-vaultso a running agent sees the new vault without restart. You can also call it manually after editing vaults on disk.
Lock semantics:
- When the agent is locked,
/envrefuses to return any environment data and instead responds with423 Lockedand a short error message ("agent is locked; env access disabled"). - Lock/unlock is intentionally simple and local-only in this first iteration; there is no authentication yet. Future versions may add proper session-based security and re-auth flows.
Inactivity timeout:
-
The agent supports an optional inactivity timeout that will re-lock the agent after a period without activity.
-
It is configured via the
--lock-timeoutflag, for example:tforge-agent --lock-timeout=15m
-
Any request to
/health,/env,/lock,/unlockor/reloadcounts as activity and resets the timer. -
If
--lock-timeoutis not set or is0, the inactivity timeout is disabled and the agent will not auto-lock.
In practice:
- The lock state only affects API access – it does not change how
vaults.binis encrypted at rest; that is entirely handled by the configuredProtector. - On a shared machine, always combine TForge with OS‑level protections (user accounts, full disk encryption, screen lock) and do not rely on the lock feature as the only security layer.
Vault lookup:
- matches either by
Vault.IDorVault.Name
Env mapping (when unlocked):
- picks
ValueDev/ValueStage/ValueProdbased onenvquery parameter - skips empty values
- currently does not filter by
Entry.Type(can be refined later)
The agent is designed to be simple and local‑only. There is no authentication yet
because the process is expected to run under the current user and only listen on
127.0.0.1. A future enhancement is to add an explicit unlock / re‑auth flow.
Located in cmd/tforge/main.go.
# default env = dev
tforge @MyVault npm run dev
# explicit env selection
tforge --env dev @MyVault npm run dev
tforge --env staging @MyVault npm run dev
tforge --env prod @MyVault npm run dev
# export mode (no process, just KEY=VALUE to stdout)
tforge --env dev --export @MyVault
# import mode (create a new vault from an env-style file)
tforge --create-vault MyVault --file path/to/.env --type secrets --duplicate-to prodRules:
- positional order:
- first non‑flag argument: vault reference (
@NameorID) - everything after that: command to run (optionally with a
--separator)
- first non‑flag argument: vault reference (
- CLI calls the agent at
http://127.0.0.1:5959/env?...and merges returned env vars into the child process’sEnv.
Import mode:
tforge --create-vault <Name> --file <path>creates a new vault directly in the local storage, importing keys from an env-style file (KEY=VALUE,#comments supported).- If the agent is running, the CLI triggers a reload so the new vault is visible immediately; otherwise restart the agent to see it.
- Values are imported into the
devenvironment by default; use--duplicate-to stagingor--duplicate-to prodto copy the same values into another environment. --typecontrols the entry type (secrets– default,env, ornote).
Example:
# in one terminal
tforge-agent
# in another
cd my-project
tforge --env dev @MyVault npm run devNo .env file is created on disk; the secrets live only in memory and in the
environment of the child process.
cd tforge
wails dev # live reloading UI + Go
wails build # build production bundle# from repo root
go run ./cmd/tforge-agent
go run ./cmd/tforge --env dev @MyVault npm run devYou can also use the helper script install-tforge-tools.ps1 (Windows/PowerShell)
to build tforge and tforge-agent into a ~/.tforge/bin directory, add
it to your PATH and (on Windows) set up auto‑start for the agent.
Requirements:
- Go installed and on
PATH - PowerShell (default on Windows 10+)
Steps:
-
Open a PowerShell window in the project root (
tforge). -
Run the install script:
./install-tforge-tools.ps1
- Default install path is
~\.tforge\bin. - This directory is added to your user
PATHsotforgeandtforge-agentare available in new terminals.
- Default install path is
-
Agent auto‑start:
- The script creates a shortcut
tforge-agent.lnkin your user Startup folder. - This makes
tforge-agent.exestart automatically in the background when you sign in to Windows. - In normal use you do not need to start the agent manually.
- The script creates a shortcut
-
Optional: disable auto‑start
- Open
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup - Delete the
tforge-agent.lnkshortcut.
- Open
After that you can run, from any project directory:
tforge --env dev @MyVault npm run devTForge is intended to work on modern Linux distributions and recent macOS versions with:
- a recent Go toolchain,
- systemd user services on Linux (for convenient autostart),
- or LaunchAgents on macOS,
- and a desktop keyring implementation (for the keyring‑backed protector).
You can install the CLI and agent into a user bin directory and set up
autostart for tforge-agent with a single command:
curl -fsSL https://raw.githubusercontent.com/MrPresidentWhite/tforge/main/install-tforge-tools.sh | bashYou can also override the install directory (for example ~/.tforge/bin):
curl -fsSL https://raw.githubusercontent.com/MrPresidentWhite/tforge/main/install-tforge-tools.sh | bash -s -- "$HOME/.tforge/bin"The script will:
- build
tforgeandtforge-agent, - place them into the chosen directory,
- ensure that directory is on your
PATH(by updating~/.profileif needed), - and, depending on the platform:
- on Linux, if
systemd --useris available, create and enable atforge-agent.serviceuser unit that starts the agent automatically on login, - on macOS, create a
~/Library/LaunchAgents/dev.tforge.agent.plistLaunchAgent that runstforge-agenton login and keeps it alive.
- on Linux, if
From the repo root:
go build ./cmd/tforge-agent
go build ./cmd/tforgePlace the resulting binaries somewhere on your PATH, for example ~/.local/bin.
Create a user service unit at ~/.config/systemd/user/tforge-agent.service:
[Unit]
Description=TForge local vault agent
[Service]
ExecStart=%h/.local/bin/tforge-agent
Restart=on-failure
[Install]
WantedBy=default.targetReload and enable the service:
systemctl --user daemon-reload
systemctl --user enable --now tforge-agent.serviceThis starts tforge-agent automatically for your user session on login. You can
inspect the status and logs via:
systemctl --user status tforge-agent.service
journalctl --user -u tforge-agent.servicev1 – Core security & platform support
-
OS‑backedProtectoron Windows (DPAPI) -
OS‑backedProtectoron macOS/Linux (Keychain / Secret Service) - improved agent security and unlock flows (session timeouts, re‑auth, optional PIN / biometrics)
- first‑class Linux support (packaging, autostart, desktop integration)
- clear headless/CI story for using vaults in build pipelines
v2 – Developer experience & integrations
- more granular export modes (e.g. filter by group or type)
- vault templates/presets for common stacks (e.g. Postgres + Redis + Next.js)
- deeper tooling integration (Docker Compose, kubectl, Terraform, IDE extensions)
- local audit / activity log for vault usage (without logging secret values)
Later – Advanced features
- vault sync across multiple TPM‑capable machines (secure, hardware‑backed)
- encrypted backup/export and restore flow for vaults (disaster recovery)
- optional
.envgeneration for CI/CD only (not for local dev)
Contributions, feedback and ideas are very welcome.
- Issues: Open issues for bugs, feature requests or questions.
- Pull requests: Prefer small, focused PRs with a short description of the motivation and main changes.
- Discussion: For larger changes, open an issue first to discuss the design before you start implementing.
When using AI assistants or agents (for example to generate code or refactors),
please keep them aligned with the project-specific guidance in AGENTS.md and
the Cursor rule .cursor/rules/ai-contributor.mdc (commit behaviour, security
considerations and co-author attribution).
This project is licensed under the MIT License. See LICENSE for details.