EnvDrift Agent Setup Guide¶
The EnvDrift Agent is a background daemon that automatically encrypts .env files
when they're not in active use. This guide covers installation, configuration,
and troubleshooting.
Overview¶
The agent runs silently in the background and:
- Watches directories for
.envfile modifications - Detects when files are idle (not being edited)
- Verifies files aren't open by other processes
- Encrypts using
envdrift encrypt <file>(respects yourenvdrift.toml) - Notifies you via desktop notifications (optional)
Prerequisites¶
Before installing the agent, ensure you have:
1. envdrift installed¶
2. dotenvx (used internally by envdrift)¶
Installation¶
From Binary (Recommended)¶
Download pre-built binaries from Releases:
# macOS / Linux
chmod +x envdrift-agent-*
./envdrift-agent-* install
# Windows (PowerShell as Admin)
.\envdrift-agent-windows-amd64.exe install
From Source¶
Commands¶
| Command | Description |
|---|---|
envdrift-agent install |
Install as system service (auto-starts on boot) |
envdrift-agent uninstall |
Remove from system startup |
envdrift-agent status |
Check if agent is installed and running |
envdrift-agent start |
Run in foreground (for debugging); --log-file <path> writes size-rotated logs there instead of stdout |
envdrift-agent stop |
Stop the running agent (stays installed; restarts on next boot) |
envdrift-agent config |
Show/create configuration file |
envdrift-agent version |
Print version information |
Configuration¶
The agent uses a TOML configuration file at ~/.envdrift/guardian.toml:
[guardian]
enabled = true
idle_timeout = "5m" # Encrypt after 5 minutes of no changes
patterns = [".env*"] # File patterns to watch
exclude = [".env.example", ".env.sample", ".env.keys"]
notify = true # Show desktop notifications
[directories]
watch = ["~/projects", "~/code"] # Display only — see note below
recursive = true # Watch subdirectories
[directories].watch does not select what the agent watches
The [directories].watch value is loaded into the config but is only echoed
back by envdrift-agent config — the agent never uses it to add watched
directories. To choose what gets watched, register projects with
envdrift agent register (see
Selecting which projects to watch).
Configuration Options¶
| Option | Type | Default | Description |
|---|---|---|---|
guardian.enabled |
bool | true |
Master switch for the whole agent |
guardian.idle_timeout |
duration | "5m" |
Default time to wait before encrypting |
guardian.patterns |
string[] | [".env*"] |
Default glob patterns for files to watch |
guardian.exclude |
string[] | [".env.example", ...] |
Default patterns to exclude |
guardian.notify |
bool | true |
Default for desktop notifications |
directories.watch |
string[] | ["~/projects"] |
Directories to monitor (display only — not used to select watched directories; see Selecting which projects to watch) |
directories.recursive |
bool | true |
Watch subdirectories |
The global guardian.idle_timeout, guardian.patterns, guardian.exclude
and guardian.notify values act as the defaults for every registered project.
A project's own [guardian] section (in its envdrift.toml or
pyproject.toml) overrides them per key. guardian.enabled is different: the
global value is only the agent's master on/off switch — it never opts a
project in, so each project still needs its own enabled = true (see
Selecting which projects to watch).
When a project has [guardian] enabled = true, custom
[vault.sync].mappings.env_file names are added to the effective watch patterns
automatically. This lets the agent react to files such as postgresql.env even
though the global default is .env*.
Duration Format¶
The idle_timeout accepts duration strings:
"30s"- 30 seconds"5m"- 5 minutes"1h"- 1 hour"2d"- 2 days"1h30m"- 1 hour 30 minutes (any Go duration string works)
Configs written by older agent versions stored idle_timeout as a raw
nanosecond integer; those files still load, and the agent rewrites the value
in the documented string form the next time it saves the config.
Selecting which projects to watch¶
The agent does not scan the [directories].watch paths from guardian.toml.
Instead, it watches the projects listed in the registry at
~/.envdrift/projects.json, which you populate with envdrift agent register.
Register the project you want the agent to watch (defaults to the current directory):
✓ Registered project: /Users/you/projects/my-app
⚠ Guardian is not enabled in envdrift.toml
Add this to your envdrift.toml to enable auto-encryption:
[guardian]
enabled = true
Registration alone is not enough: the agent only watches a project whose
config has the guardian turned on. The per-project default is
enabled = false, so add the [guardian] section shown above to each project
you want auto-encrypted.
The agent discovers a project's config the same way the CLI does: it walks up
from the project directory toward the filesystem root and uses the first
envdrift.toml it finds, or the first pyproject.toml containing a
[tool.envdrift] table (use [tool.envdrift.guardian] for the guardian
section there). A project registered via pyproject.toml or a parent-dir
envdrift.toml is therefore watched too.
List the registered projects at any time:
Registered Projects
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Path ┃ Registered ┃ Has Config ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ /Users/you/projects/my-app │ 2026-06-03 16:05 │ ✓ │
└─────────────────────────────┴──────────────────┴────────────┘
Registry: /Users/you/.envdrift/projects.json
Use envdrift agent unregister [PATH] to stop watching a project and
envdrift agent status to see the agent state and registered project count.
If the installed binary cannot execute (e.g. wrong architecture or a corrupt
download), both envdrift agent status and envdrift install check report it
as broken with the underlying error and suggest
envdrift install agent --force to reinstall.
Registry safety¶
The CLI guards the registry file against races and corruption:
- Concurrent registers are safe.
register/unregisterhold an exclusive lock on a sidecar~/.envdrift/projects.json.lockfile and re-read the registry under it, so parallel commands (e.g. several setup scripts at once) never overwrite each other's entries. If the lock cannot be acquired within 10 seconds the command fails with exit code 1 instead of corrupting state. - A corrupt registry is never silently wiped. If
projects.jsonis truncated or malformed, read commands (list,status) warn and treat it as empty without touching the file. The nextregistermoves the corrupt original aside toprojects.json.corrupt-<timestamp>(and tells you where) before writing a fresh registry, so prior registrations can be recovered by hand and re-registered. Anunregisternever performs this backup: a corrupt registry loads as empty, so there is nothing to remove and the file is left untouched.
How It Works¶
┌─────────────────┐
│ File System │
│ (.env files) │
└────────┬────────┘
│ fsnotify events
▼
┌─────────────────┐
│ Watcher │
│ (pattern match) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Guardian │
│ (idle tracking) │
└────────┬────────┘
│ idle_timeout expired?
▼
┌─────────────────┐
│ Lock Check │
│ (file in use?) │
└────────┬────────┘
│ not locked?
▼
┌─────────────────────┐
│ Encrypt │
│ (envdrift encrypt) │
└────────┬────────────┘
│
▼
┌─────────────────┐
│ Notify │
│ (desktop alert) │
└─────────────────┘
- Watcher - Uses
fsnotifyto detect file changes matching patterns - Guardian - Tracks last modification time, checks for idle timeout. A file counts as encrypted only when every value is ciphertext — a plaintext secret added to an already-encrypted file is re-encrypted, not dropped
- Lock Check - Verifies file isn't open by another process (
lsofon Unix,handle.exeon Windows); the agent's own watcher handles are ignored - Encrypt - Calls
envdrift encrypt <file>which respects yourenvdrift.toml - Notify - Shows desktop notification if enabled
Platform Details¶
macOS¶
- Auto-start: LaunchAgent (
~/Library/LaunchAgents/com.envdrift.guardian.plist) - Lock detection:
lsof - Logs:
~/.envdrift/logs/agent.log, size-rotated by the agent itself (5 MiB per file, 3 rotated backups:agent.log.1…agent.log.3). launchd cannot rotate itsStandardOutPathredirection, so the plist runs the agent with--log-fileand the/tmp/envdrift-agent.log//tmp/envdrift-agent.errfiles now only receive the brief startup prints and crash output. Re-runenvdrift-agent installafter upgrading to refresh an older plist.
Linux¶
- Auto-start: systemd user service (
~/.config/systemd/user/envdrift-guardian.service) - Lock detection:
lsof - Logs:
journalctl --user -u envdrift-guardian
Windows¶
- Auto-start: Task Scheduler (scheduled task
EnvDriftGuardian) - Lock detection:
handle.exe(Sysinternals) or PowerShell fallback - Logs: not captured to a file — the scheduled task runs without stdout/stderr redirection
Integration with envdrift.toml¶
The agent calls envdrift encrypt <file>, which means it respects all settings in your project's envdrift.toml:
- Partial encryption - Only secrets are encrypted
- Vault integration - Keys are pushed to vault if configured
- Ephemeral keys - Keys never touch disk if enabled
- Custom env filenames -
vault.sync.mappings.env_filenames are watched automatically when project guardian config is enabled
Troubleshooting¶
Agent not starting¶
Files not being encrypted¶
- Check patterns match: Ensure file matches
patternsin config - Check exclusions: File might be in
excludelist - Check idle timeout: File might still be within timeout
- Check lock detection: File might still be open
Registry file corrupted¶
If ~/.envdrift/projects.json becomes corrupt (truncated write, manual edit),
the agent does not crash-loop: at startup it logs the parse error,
preserves the broken file at projects.json.bak, and continues with an empty
registry; at runtime it keeps the last-good project set and logs the error.
Re-register projects (or restore the .bak) to recover:
envdrift not found¶
# Ensure envdrift is installed and in PATH
which envdrift
pip install envdrift
# Or try python module directly
python -m envdrift --version
Permission issues¶
# macOS/Linux: Check the agent can access watched directories
ls -la ~/projects
# Windows: Run as Administrator for initial install