Universal .env variable manager — read, write, encrypt, delegate across services and devices
Project description
getv — Universal .env Variable Manager
Read, write, encrypt, and delegate environment variables across services and devices.
Why getv?
Every project reinvents .env parsing. getv provides one library for:
- Reading/writing
.envfiles with comment preservation - Profile management — named configs for devices, LLM providers, databases
- Secret masking — automatic detection and masking of passwords/keys in logs
- Encryption — Fernet-based encryption of sensitive values for safe transport
- Format export — dict, JSON, shell, docker-compose, pydantic BaseSettings
- CLI — manage profiles from the command line
Install
pip install getv # core
pip install "getv[crypto]" # + encryption (Fernet)
pip install "getv[pydantic]" # + pydantic BaseSettings export
pip install "getv[all]" # everything
Quick Start
Python API
from getv import EnvStore, ProfileManager
# Single .env file
store = EnvStore("~/.myapp/.env")
store.set("DB_HOST", "localhost").set("DB_PORT", "5432").save()
print(store.get("DB_HOST")) # "localhost"
# Profile manager — multiple named configs
pm = ProfileManager("~/.fixpi")
pm.add_category("devices", required_keys=["RPI_HOST", "RPI_USER"])
pm.add_category("llm", required_keys=["LLM_MODEL"])
pm.set("devices", "rpi3", {
"RPI_HOST": "192.168.1.10",
"RPI_USER": "pi",
"RPI_PASSWORD": "secret",
"RPI_PORT": "22",
})
pm.set("llm", "groq", {
"LLM_MODEL": "groq/llama-3.3-70b-versatile",
"GROQ_API_KEY": "gsk_xxx",
})
# Merge profiles on top of base config
base = {"APP_NAME": "fixpi", "RPI_HOST": "default"}
cfg = pm.merge_profiles(base, devices="rpi3", llm="groq")
# cfg["RPI_HOST"] == "192.168.1.10" (overridden by device profile)
# cfg["LLM_MODEL"] == "groq/llama-3.3-70b-versatile"
CLI
# Set variables
getv set devices rpi3 RPI_HOST=192.168.1.10 RPI_USER=pi RPI_PASSWORD=secret
# Get a single variable
getv get devices rpi3 RPI_HOST
# → 192.168.1.10
# List all categories
getv list
# devices/ (2 profiles)
# llm/ (3 profiles)
# List profiles in a category (secrets masked)
getv list devices
# rpi3: RPI_HOST=192.168.1.10, RPI_USER=pi, RPI_PASSWORD=secr***
# Show all variables (unmasked)
getv list devices rpi3 --show-secrets
# Export to different formats
getv export devices rpi3 --format json
getv export devices rpi3 --format shell
getv export devices rpi3 --format pydantic
getv export llm groq --format docker
# Encrypt sensitive values (Fernet)
getv encrypt devices rpi3
# → Generated key: ~/.getv/.fernet.key
# → Encrypted sensitive values in devices/rpi3
# Decrypt
getv decrypt devices rpi3
# Delete a profile
getv delete devices old-rpi
Profile Directory Structure
~/.getv/ ← GETV_HOME (configurable)
├── .fernet.key ← encryption key (chmod 600)
├── devices/
│ ├── rpi3.env
│ ├── rpi4-prod.env
│ └── rpi5-kiosk.env
└── llm/
├── groq.env
├── openrouter.env
└── ollama.env
Each .env file is a standard KEY=VALUE file:
# ~/.getv/devices/rpi3.env
RPI_HOST=192.168.1.10
RPI_USER=pi
RPI_PASSWORD=secret
RPI_PORT=22
Security
Automatic Secret Detection
Keys matching these patterns are automatically masked in display/logs:
PASSWORD, PASSWD, SECRET, TOKEN, API_KEY, APIKEY,
PRIVATE_KEY, ACCESS_KEY, ACCESS_TOKEN, AUTH, CREDENTIAL
from getv.security import mask_dict, is_sensitive_key
data = {"RPI_HOST": "10.0.0.1", "RPI_PASSWORD": "secret123"}
print(mask_dict(data))
# {"RPI_HOST": "10.0.0.1", "RPI_PASSWORD": "secr***"}
Encryption for Transport
from getv.security import generate_key, encrypt_store, decrypt_store
key = generate_key()
data = {"RPI_HOST": "10.0.0.1", "RPI_PASSWORD": "secret"}
encrypted = encrypt_store(data, key, only_sensitive=True)
# {"RPI_HOST": "10.0.0.1", "RPI_PASSWORD": "ENC:gAAA..."}
original = decrypt_store(encrypted, key)
# {"RPI_HOST": "10.0.0.1", "RPI_PASSWORD": "secret"}
Format Export
| Format | Function | Output |
|---|---|---|
| dict | store.as_dict() |
{"KEY": "val"} |
| JSON | to_json(data) |
{"KEY": "val"} |
| Shell | to_shell_export(data) |
export KEY='val' |
| Docker | to_docker_env(data) |
KEY=val |
| .env | to_env_file(data) |
KEY=val |
| Pydantic | to_pydantic_settings(data) |
Python class source |
| Pydantic model | to_pydantic_model(data) |
BaseSettings instance |
Integration with fixpi
getv powers fixpi's device and LLM profile management:
from getv import ProfileManager
pm = ProfileManager("~/.fixpi")
pm.add_category("devices")
pm.add_category("llm")
# fixpi delegates all .env operations to getv
cfg = pm.merge_profiles(base_env, devices="rpi3", llm="groq")
Environment Variables
| Variable | Default | Description |
|---|---|---|
GETV_HOME |
~/.getv |
Base directory for profiles |
License
Apache License 2.0 - see LICENSE for details.
Author
Created by Tom Sapletta - tom@sapletta.com
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file getv-0.1.2.tar.gz.
File metadata
- Download URL: getv-0.1.2.tar.gz
- Upload date:
- Size: 19.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3af7042c6ffa3a1c7c6bc1668d12c6d89c8e396c0dcfe19cdd52a90688e24c0f
|
|
| MD5 |
5934e3a269c854dbfb2175d5107ce8f9
|
|
| BLAKE2b-256 |
1b7a9049ec3504b6281c0c0248c7b64dfecbd7b0c26354c81d1f31072e59331a
|
File details
Details for the file getv-0.1.2-py3-none-any.whl.
File metadata
- Download URL: getv-0.1.2-py3-none-any.whl
- Upload date:
- Size: 17.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9902f9bb3d3df274a989c61889b740863773e7aa223b5eb60c3ad22670b11169
|
|
| MD5 |
d2b6b8d011621080bda50f10ca53546c
|
|
| BLAKE2b-256 |
1f08020c7df173ca0325db2433fa8bdd08c1230ea06a4aa6784463b2c53578af
|