hotenv caches an environment (a set of KEY=VALUE pairs) in a per-session local server and allows commands to run with that environment without reloading secrets repeatedly.
Core model:
hotenv servereads dotenv-style lines from stdin until EOF, stores them as an immutable environment snapshot, then serves it over a Unix domain socket.hotenv run -- <cmd...>fetches the cached environment from the server and executes<cmd...>locally with those variables set.hotenv dumpprints the cached environment.
There is no authentication layer beyond filesystem permissions.
Sessions are intentionally short‑lived. Users may terminate the server via normal process control (e.g. Ctrl-C or pkill hotenv).
hotenv relies entirely on Unix filesystem isolation:
- Runtime base directory is created with mode
0700. - Socket files are created inside that directory.
.hotenvis created with mode0600.
If a process can connect to the Unix socket, it is trusted.
There is:
- No token
- No per-request authentication
- No confirmation mode
- No runtime permission re-validation
The primary security measure is the idle timeout, which limits how long secrets remain available in memory.
Each session has a session_id.
Requirements:
- 32-bit random value
- 8 lowercase hexadecimal characters
- Used only to avoid filename conflicts
Example:
a3f19c2d
No cryptographic strength is required beyond collision avoidance.
hotenv serve reads dotenv-style lines from stdin until EOF.
Parsing MUST be delegated to a standard dotenv-compatible parsing library. The implementation MUST follow conventional dotenv semantics.
Example input:
# comment
API_KEY=abc123
EMPTY=
DATABASE_URL=postgres://localhost/db
General rules:
- One entry per line:
VAR=VALUE - Blank lines are ignored
- Lines starting with
#are ignored - Split on the first
= VALUEmay be empty- If a variable appears multiple times, the last occurrence wins
- Behavior otherwise follows the chosen dotenv library
If the dotenv parser reports an error:
serveMUST:- Print a clear, helpful error message to stderr.
- Include enough context to identify the problem (e.g., line number if available).
- Exit immediately.
- No socket MUST be created.
- No
.hotenvfile MUST be created.
This is considered a user input parsing error and MUST use exit code 7.
Chosen as:
$XDG_RUNTIME_DIR/hotenv/if set- Otherwise
/tmp/hotenv-<uid>/
Created with:
mode 0700
owned by current user
No runtime re-validation is required.
Per session:
<runtime_base>/<session_id>.sock
- Unix domain stream socket
- Created inside the runtime base directory
- Removed during cleanup
Created in the directory where serve is started:
<root>/.hotenv
Mode: 0600
Must be created safely (e.g., O_CREAT | O_EXCL).
Contents:
socket=<absolute path>
Example:
socket=/tmp/hotenv-1000/a3f19c2d.sock
Session artifacts include:
.hotenv- The
socket=entry inside.hotenv - Socket protocol JSON messages
If parsing of any session artifact fails (e.g., malformed .hotenv, invalid socket= entry, malformed JSON protocol):
- The command MUST:
- Print a clear error message to stderr.
- Exit with exit code 9.
- No undefined behavior is permitted.
- Unix domain stream socket at
<runtime_base>/<session_id>.sock - One request per connection:
- Client connects
- Client sends one JSON line
- Server replies with one JSON line
- Connection closes
All messages are UTF‑8 encoded JSON objects terminated by a single newline.
All requests are single-line JSON objects.
{"command":"dump"}{"command":"run","args":["cmd","arg1","arg2"]}Fields:
commandMUST be"dump"or"run".- For
"run":argsMUST be a non-empty array of strings.args[0]is the executable name.- Remaining elements are arguments.
- The server does not execute the command.
- The
argsfield exists to support server-side logging only.
Malformed JSON or invalid fields → protocol error (exit code 9 on client side).
The response format is identical for all successful requests.
{"env":{"KEY":"VALUE"}}envis the complete immutable environment snapshot.- Order of keys is unspecified.
{"error":"BAD_REQUEST","message":"..."}Error codes:
BAD_REQUESTINTERNAL
Logging is performed by the server process (hotenv serve).
By default, the server MUST log one line per successful request to stderr.
Log format (human-readable):
<timestamp> <command> <summary>
Where:
<timestamp>is local time in a human-readable format (e.g.,2026-02-14 15:04:05).<command>isrunordump.<summary>is:- For
dump:- - For
run: the value ofargs[0]only.
- For
Example:
2026-02-14 15:04:05 run python
2026-02-14 15:05:12 dump -
If hotenv serve --verbose is specified:
- For
run, the log line MUST include all arguments, space-separated, instead of onlyargs[0].
Example:
2026-02-14 15:04:05 run python script.py --debug
If hotenv serve --quiet is specified:
- No per-request logs are emitted.
- Startup errors and fatal errors MUST still be printed.
If both --quiet and --verbose are specified, this is a CLI usage error (exit code 2).
Shorthands:
-t,--timeout-f,--force-q,--quiet-v,--verbose
Behavior:
- Read environment from stdin.
- Parse via dotenv library.
- Generate
session_id. - Create socket at
<runtime_base>/<session_id>.sock. - Write
.hotenv. - Serve requests until:
- Idle timeout expires, or
- Graceful termination signal is received.
Without --force:
- Refuse to start (exit code 10).
With --force:
- Overwrite
.hotenv. - Best-effort cleanup of the old socket file.
- Walk upward to find
.hotenv. - Parse
.hotenv. - Read
socketpath. - Connect to socket.
- Send:
{"command":"run","args":["cmd","arg1","arg2"]}- Receive environment snapshot.
- Overlay returned environment onto current process environment.
- Execute
<cmd...>locally. - Exit with the child’s exit status.
Same lookup and artifact parsing as run.
Sends:
{"command":"dump"}Receives environment snapshot and prints:
KEY=VALUE
Order unspecified.
- Default: 5 minutes
- Configurable via
--timeout - Timer resets after each successful request
- When expired:
- Server exits
- Cleanup occurs
This is the primary security control limiting exposure of secrets.
Cleanup occurs on:
- Idle timeout
- Graceful signal (
SIGTERM,SIGINT)
Cleanup consists of:
- Removing the socket file
- Removing
.hotenvonly if it still points to this socket
On non-graceful termination (SIGKILL):
- No cleanup is required.
| Code | Meaning |
|---|---|
| 0 | Success |
| 2 | CLI usage error |
| 3 | No .hotenv found |
| 4 | Session unreachable |
| 7 | User input parse error (dotenv input) |
| 8 | OS operation failure |
| 9 | Session artifact parse error |
| 10 | serve refused (existing marker, no --force) |
- Exit code 7 is reserved exclusively for dotenv parsing failures during
serve. - Exit code 9 is reserved for parsing failures of session artifacts (
.hotenv, protocol JSON, etc.).
hotenv run exits with the child process’s exit code if execution occurs.