# @kindgi/secrets-dotenv

> Dev-mode `SecretBinding` over the project's own env files (`.env`, then `.env.local`, or `dev.envFiles`) — the same files, parsed the same way, as the app beside the pack — and Kindgi's own `.kindgi/secrets.env`, read last and written, plus the one definition of which env files belong to a pack environment. `KINDGI_*` names are runtime config, never secrets. Not for production — no encryption, no audit, no versioning.

`npm install @kindgi/secrets-dotenv` · [source](https://github.com/kindgi/kindgi-sdk/tree/@kindgi/sdk@0.1.9/packages/secrets-dotenv)

The dev-mode `SecretBinding` — secrets for `kindgi dev`, straight from the project's env files — plus the one definition of which env files belong to a pack environment.

Not for production: plaintext on disk, no audit events, no versioning. Deployed environments use a durable, encrypted `SecretBinding` or an external secrets provider.

## Which files

| Environment            | Files read (lowest precedence first)                                                          | Writes go to                                                                 |
| ---------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `local` (`kindgi dev`) | `.env`, `.env.local` — or `dev.envFiles` from `kindgi.config.ts` — then `.kindgi/secrets.env` | `.kindgi/secrets.env` (with `appEnvFile`: the app's last file, `.env.local`) |
| anything else          | `.env.<envName>`                                                                              | the same file                                                                |

Paths are relative to the pack root. For `local` these are the same files, parsed the same way (`@kindgi/dotenv-file`: dotenv grammar, `${VAR}` expansion), as the application beside the pack — Kindgi embedded in a Next.js app sees exactly what `next dev` sees. A key already in the app's `.env` is available to the pack without copying it anywhere. Kindgi's own file comes last, so it wins, and it's where a secret is written: a file the app doesn't load (a framework loads `.env.local` into every route). `copyToKindgiFile` gives Kindgi its own copy of names the app's files hold, and never edits them.

```ts excerpt
import { readPackEnv, resolvePackEnvFiles } from '@kindgi/secrets-dotenv';

resolvePackEnvFiles({ packDir, envName: 'local' });
// → { read: ['<pack>/.env', '<pack>/.env.local', '<pack>/.kindgi/secrets.env'],
//     write: '<pack>/.kindgi/secrets.env', app: [...the first two], appWrite: '<pack>/.env.local', … }

const env = await readPackEnv({ packDir, envName: 'local', env: process.env });
env.values; // merged + expanded; env.origin says which file supplied each name
```

## Runtime config vs. the pack's secrets

One file can hold both. The `KINDGI_` prefix is the line (`isRuntimeKey`, `runtimeValues`, `packValues`):

- `KINDGI_*` — Kindgi's own runtime config (`KINDGI_DATABASE_URL`, …). Never visible through the binding, never written by it.
- everything else — the pack's. An app's own `DATABASE_URL` is just a name the pack could reference; it never configures Kindgi.

## The binding

```ts excerpt
import { createDotenvSecretBinding } from '@kindgi/secrets-dotenv';

const binding = createDotenvSecretBinding({
  packDir,
  localEnvFiles: ['.env', '.env.local'], // optional — dev.envFiles
  env: process.env, // optional — fallback for ${VAR} no file defines
});
```

- **Reads** (`list`, `get`, `resolve`, `getVersion`, `listVersions`): the merged, expanded view without `KINDGI_*`. Versions are synthetic (`versionId: 1`).
- **`set`**: `setKey` on the write target — one line changes, every other byte stays; atomic write, mode 0600. `create-new` reports `already-exists` if ANY of the files defines the name. Refuses `KINDGI_*`, the reserved `kindgi.` prefix, non-POSIX names, and values no dotenv quoting can hold.
- **`rotate` / `revoke`**: unsupported — the error names the files to edit.
- **Scope-blind**: dotenv files are flat; `Scope` is ignored.
- **`${VAR}`**: resolved across the files; `env` only fills names no file defines and never overrides a file's value. Nothing reads `process.env` unless you pass it.
