404
+This page is redacted.
+Nothing lives at this address. The value is not hidden, it just does not exist.
+diff --git a/site/404.html b/site/404.html new file mode 100644 index 0000000..52ff1a1 --- /dev/null +++ b/site/404.html @@ -0,0 +1,26 @@ + + +
+ + +404
+Nothing lives at this address. The value is not hidden, it just does not exist.
+OpenCode plugin
+.env files.envsitter-guard stops coding agents from reading or editing secret env files, then gives them fifteen envsitter tools that work with keys, fingerprints, and booleans instead of values.
+$ opencode plugin add envsitter-guard@latest
+
+ Install
+OpenCode 2 loads the plugin through setup() and OpenCode 1 through server(), both from the same default export. Restart OpenCode 1 after changing config; OpenCode 2 reloads watched config on its own.
{
+ "$schema": "https://opencode.ai/config.json",
+ "plugins": ["envsitter-guard@latest"]
+}
+ {
+ "$schema": "https://opencode.ai/config.json",
+ "plugin": ["envsitter-guard@latest"]
+}
+ Prefer a local file? Re-export the package from .opencode/plugins/envsitter-guard.ts (OpenCode 2) or .opencode/plugin/ (OpenCode 1). The README has the snippet.
Blocking
+Protected files are .env, .env.<anything>, <name>.env, <name>.env.<anything>, and .envsitter/pepper. Blocked calls fail with a message that points the agent to envsitter_help.
read, edit, write, grep on a file, MCP filesystem tools.patch and apply_patch calls that add, update, move, or delete a protected file.cat .env, source .env, echo X >> .env, or node --env-file=.env.grep matches inside protected files are removed from the output.[envsitter: KEY redacted] in every other tool's output, so grep -r, cat *, and log files do not hand them to the model.read, edit, and shell checks on protected files are denied, including calls made from Code Mode..env.example, .env.sample, .env.template, .env.dist, and .env.default(s).npx envsitter keys --file .env are allowed because the CLI never prints values.Tools
+Agents call them by name. Mutations and file operations are dry runs unless the agent passes write: true, and output is limited to keys, booleans, line numbers, and plans.
envsitter_keysenvsitter_fingerprintenvsitter_scanList keys, fingerprint one value, or detect JWT, URL, and base64 shapes.
+envsitter_matchenvsitter_match_by_keyBoolean checks with every envsitter operator, for one key, many keys, or all keys.
+envsitter_addenvsitter_setenvsitter_unsetenvsitter_deleteAdd, update, empty, or remove keys without the agent ever reading the file.
+envsitter_validateenvsitter_copyenvsitter_formatenvsitter_reorderenvsitter_annotateValidate syntax, copy keys between files, sort them, or add comments.
+envsitter_helpA built-in guide the agent can read when a call is blocked.
+Compatibility
+Before every release, an end-to-end check runs the real OpenCode 1 and OpenCode 2 CLIs against a scripted model and confirms each blocking scenario holds.
+| OpenCode | Minimum | Verified | Entry point |
|---|---|---|---|
| 2.x | 2.0.32 | 2.0.32, 2.1.0 | setup(ctx) |
| 1.x | 1.18.29 | 1.18.31, 1.19.3 | server() |
grep -r TOKEN . or cat *, are not blocked; their output is scrubbed instead. Encoded or transformed values (base64, split strings) and values that do not look secret get through.Built on envsitter
+Every guard tool is backed by the envsitter library and CLI, which you can use directly in scripts, CI, and your own agent integrations.
+Open source library and CLI
+.env secrets without ever seeing them.envsitter lists keys, fingerprints values with HMAC-SHA-256, and answers yes or no questions about them. Values stay in memory, so they never reach your terminal, your logs, or an AI agent's context.
+$ npm install envsitter
+
+ Keys are readable. Values never leave memory.
+Match operators
+Every operator evaluates the value in-process and returns only true or false. Equality is checked by comparing HMAC digests, never the raw strings.
existsThe key is present in the source.
is_emptyThe value is exactly the empty string.
is_equalneeds a candidateDeterministic match against a candidate you supply, compared in constant time.
partial_match_prefixneeds a candidateThe value starts with the candidate.
partial_match_suffixneeds a candidateThe value ends with the candidate.
partial_match_regexneeds a candidateThe value matches a regex such as /^sk-/.
is_numberThe value parses as a finite number.
is_booleanThe value is true or false, ignoring case and surrounding spaces.
is_stringThe value is neither a number nor a boolean.
One rule everywhere
+The same guarantee holds whether you run a command, call the library, or let an AI coding agent work in your project.
+Inspect, validate, copy, and edit env files from your shell with JSON output and useful exit codes.
+ Command reference + + + +A typed TypeScript API for keys, fingerprints, matchers, scans, and file operations inside your own tools.
+ Library usage + + + +A plugin that blocks AI agents from reading or editing secret env files and hands them envsitter tools instead.
+ Guard for agents + +CLI
+Output contains keys, booleans, lengths, fingerprints, and line numbers. Commands that change files are dry runs until you pass --write.
$ npx envsitter keys --file .env
+
+ Exit codes: 0 success or match, 1 no match, 2 usage or runtime error.
| Command | What it does |
|---|---|
keys | List the keys in an env file |
fingerprint | Deterministic HMAC fingerprint of one key |
match | Match a candidate or operator against one, many, or all keys |
match-by-key | Bulk match a different candidate per key |
scan | Detect value shapes: JWT, URL, base64 |
redact | Replace secret values in text read from stdin |
validate | Check dotenv syntax with line and column |
copy | Copy keys between env files, with rename and conflict policy |
format, reorder | Sort and organize keys, by section or globally |
annotate | Add a comment above a key |
add | Add a new key, failing if it already exists |
set | Create or update a key |
unset | Set a key to an empty value |
delete | Remove one or more keys |
Library
+Build envsitter into release scripts, audits, or your own agent tools. Nothing in the API returns a plaintext value.
+Path helpers such as isSensitiveEnvFile tell your tooling which files hold real secrets and which are committed templates like .env.example.
import { EnvSitter, setEnvFileKey } from 'envsitter';
+
+const es = EnvSitter.fromDotenvFile('.env');
+
+await es.listKeys(); // ['API_TOKEN', 'PORT', ...]
+await es.matchCandidate('API_TOKEN', candidate); // true or false
+await es.matchKey('PORT', { op: 'is_number' }); // true
+await es.fingerprintKey('API_TOKEN'); // hmac-sha256 digest + length
+
+// Dry run unless write: true. Returns a plan, never the value.
+await setEnvFileKey({ file: '.env', key: 'API_TOKEN', value: next, write: true });
+ Security model
+Values are read in-process for comparisons, but the library never returns them and the CLI never prints them.
+Fingerprints are HMAC-SHA-256 with a local pepper, not raw hashes that are easy to dictionary-guess. The pepper comes from ENVSITTER_PEPPER or a .envsitter/pepper file created with mode 0600.
is_equal hashes the candidate and the stored value with the same pepper and compares the digests in constant time.
Pass candidates and new values with --candidate-stdin or --value-stdin so secrets stay out of your shell history.
Not a secret manager: envsitter does not encrypt, sync, or relocate values. It works on your env sources in place.
+For AI coding agents
+envsitter-guard is an OpenCode plugin for OpenCode 1 and 2. It blocks agents from reading or editing secret env files and gives them fifteen envsitter tools that never return values.
+