envpkt 0.1.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +296 -107
- package/dist/cli.js +803 -198
- package/dist/index.d.ts +85 -7
- package/dist/index.js +369 -75
- package/package.json +22 -20
- package/schemas/envpkt.schema.json +46 -3
package/README.md
CHANGED
|
@@ -3,25 +3,60 @@
|
|
|
3
3
|
[](https://github.com/jordanburke/envpkt/actions/workflows/node.js.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/envpkt)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
**Credentials your agents actually understand.**
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Structured metadata for every secret — capabilities, constraints, expiration, and fleet health — so agents operate within their boundaries instead of flying blind.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Every credential in your system gets an `envpkt.toml` entry describing _what service it authenticates to_, _what it's allowed to do_, _when it expires_, and _how to rotate it_. Your agents query this metadata via MCP to understand their operating constraints. Your operators audit credential health across entire agent fleets. The secrets themselves stay where they belong — in your secrets manager, encrypted at rest, or injected at runtime — never in the agent's conversation context.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## MCP Integration
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- Get warnings before secrets expire
|
|
16
|
-
- Detect stale or orphaned credentials
|
|
17
|
-
- Understand what capabilities each secret grants
|
|
18
|
-
- Automate rotation workflows
|
|
19
|
-
- Share secret metadata across agents via a central catalog
|
|
14
|
+
envpkt ships an [MCP](https://modelcontextprotocol.io/) server that gives AI agents structured awareness of their credentials. Add it to Claude, Cursor, VS Code, or any MCP-compatible client:
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"envpkt": {
|
|
20
|
+
"command": "envpkt",
|
|
21
|
+
"args": ["mcp"]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Tools
|
|
28
|
+
|
|
29
|
+
| Tool | Description |
|
|
30
|
+
| ------------------ | ------------------------------------------------------- |
|
|
31
|
+
| `getPacketHealth` | Get overall health status with per-secret audit results |
|
|
32
|
+
| `listCapabilities` | List agent and per-secret capabilities |
|
|
33
|
+
| `getSecretMeta` | Get metadata for a specific secret by key |
|
|
34
|
+
| `checkExpiration` | Check expiration status and days remaining |
|
|
35
|
+
| `getEnvMeta` | Get metadata for environment defaults and drift status |
|
|
36
|
+
|
|
37
|
+
### Resources
|
|
38
|
+
|
|
39
|
+
| URI | Description |
|
|
40
|
+
| ----------------------- | --------------------------------- |
|
|
41
|
+
| `envpkt://health` | Current credential health summary |
|
|
42
|
+
| `envpkt://capabilities` | Agent and secret capabilities |
|
|
43
|
+
|
|
44
|
+
The MCP server exposes metadata only — it does not have access to secret values. See [Security Model](#security-model) for details.
|
|
45
|
+
|
|
46
|
+
## Security Model
|
|
47
|
+
|
|
48
|
+
envpkt operates a three-tier trust model. Each tier has different guarantees, and we're explicit about what each one protects against.
|
|
49
|
+
|
|
50
|
+
**Tier 1: MCP metadata (agent-facing)** — The MCP server never returns raw credential values. This isn't a policy choice — architecturally, the server reads `envpkt.toml` which contains metadata (service names, capabilities, expiration dates, rotation URLs) but never plaintext secrets. The agent gets structured awareness of its constraints without any secret material entering the LLM context window. Prompt injection attacks cannot leak what isn't there.
|
|
51
|
+
|
|
52
|
+
**Tier 2: Runtime injection (process-facing)** — `boot()` resolves secrets (from sealed packets, fnox, or environment variables) and injects them into `process.env` at startup, outside the LLM context. This is the same trust model as every Node.js application that reads from `.env`, except now secrets are encrypted at rest, scoped per-agent, and auditable. This is defense-in-depth against prompt injection — the most common attack vector — but it is not a hard boundary against agents with code execution capabilities.
|
|
53
|
+
|
|
54
|
+
**Tier 3: Shell-level agents** — Agents with shell access (Claude Code, Devin, etc.) can read environment variables directly. Prevention isn't possible at this tier. envpkt provides encrypted storage, scoped access, and audit trails — because when prevention isn't possible, visibility is what matters.
|
|
22
55
|
|
|
23
56
|
## Quick Start
|
|
24
57
|
|
|
58
|
+
Start where your credentials already are — environment variables — and graduate to encrypted, per-agent-scoped metadata.
|
|
59
|
+
|
|
25
60
|
```bash
|
|
26
61
|
# Install
|
|
27
62
|
npm install -g envpkt
|
|
@@ -51,7 +86,7 @@ Every project gets one `envpkt.toml` that describes its credentials. Here's a mi
|
|
|
51
86
|
|
|
52
87
|
version = 1
|
|
53
88
|
|
|
54
|
-
[
|
|
89
|
+
[secret.API_KEY]
|
|
55
90
|
service = "stripe"
|
|
56
91
|
```
|
|
57
92
|
|
|
@@ -74,7 +109,7 @@ stale_warning_days = 90
|
|
|
74
109
|
require_expiration = true
|
|
75
110
|
require_service = true
|
|
76
111
|
|
|
77
|
-
[
|
|
112
|
+
[secret.STRIPE_SECRET_KEY]
|
|
78
113
|
service = "stripe"
|
|
79
114
|
purpose = "Process customer payments and manage subscriptions"
|
|
80
115
|
capabilities = ["charges:write", "subscriptions:write"]
|
|
@@ -83,7 +118,7 @@ expires = "2027-01-15"
|
|
|
83
118
|
rotation_url = "https://dashboard.stripe.com/apikeys"
|
|
84
119
|
source = "vault"
|
|
85
120
|
|
|
86
|
-
[
|
|
121
|
+
[secret.DATABASE_URL]
|
|
87
122
|
service = "postgres"
|
|
88
123
|
purpose = "Read/write access to the billing database"
|
|
89
124
|
capabilities = ["SELECT", "INSERT", "UPDATE"]
|
|
@@ -93,13 +128,81 @@ rotation_url = "https://wiki.internal/runbooks/rotate-db-creds"
|
|
|
93
128
|
source = "vault"
|
|
94
129
|
```
|
|
95
130
|
|
|
131
|
+
For non-secret configuration defaults (runtime mode, log levels, etc.), use `[env.*]`:
|
|
132
|
+
|
|
133
|
+
```toml
|
|
134
|
+
[env.NODE_ENV]
|
|
135
|
+
value = "production"
|
|
136
|
+
purpose = "Runtime environment mode"
|
|
137
|
+
comment = "Override to 'development' for local testing"
|
|
138
|
+
|
|
139
|
+
[env.LOG_LEVEL]
|
|
140
|
+
value = "info"
|
|
141
|
+
purpose = "Application log verbosity"
|
|
142
|
+
```
|
|
143
|
+
|
|
96
144
|
See [`examples/`](./examples/) for more configurations.
|
|
97
145
|
|
|
98
|
-
##
|
|
146
|
+
## Sealed Packets
|
|
147
|
+
|
|
148
|
+
Sealed packets embed age-encrypted secret values directly in `envpkt.toml`. This makes your config fully self-contained — no external secrets backend needed at runtime.
|
|
149
|
+
|
|
150
|
+
### Setup
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Generate an age keypair
|
|
154
|
+
age-keygen -o identity.txt
|
|
155
|
+
# public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Add the public key to your config and the identity file to `.gitignore`:
|
|
159
|
+
|
|
160
|
+
```toml
|
|
161
|
+
[agent]
|
|
162
|
+
name = "my-agent"
|
|
163
|
+
recipient = "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
|
|
164
|
+
identity = "identity.txt"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The `identity` path supports `~` expansion and environment variables (`$VAR`, `${VAR}`), so you can use paths like `~/keys/identity.txt` or `$KEYS_DIR/identity.txt`. Relative paths are resolved from the config file's directory.
|
|
168
|
+
|
|
169
|
+
### Seal
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
envpkt seal
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Each secret gets an `encrypted_value` field with age-armored ciphertext. The TOML (including ciphertext) is safe to commit.
|
|
176
|
+
|
|
177
|
+
### Boot
|
|
178
|
+
|
|
179
|
+
At runtime, sealed values are automatically decrypted:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { boot } from "envpkt"
|
|
183
|
+
|
|
184
|
+
const result = boot() // decrypts sealed values, injects into process.env
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Mixed mode is supported — sealed values take priority, with fnox as fallback for keys without `encrypted_value`.
|
|
188
|
+
|
|
189
|
+
## Fleet Management
|
|
190
|
+
|
|
191
|
+
When you're running multiple agents, `envpkt fleet` scans a directory tree for `envpkt.toml` files and aggregates credential health across your entire fleet.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
envpkt fleet # Scan current directory (depth 3)
|
|
195
|
+
envpkt fleet -d /opt/agents # Scan specific directory
|
|
196
|
+
envpkt fleet --depth 5 # Increase scan depth
|
|
197
|
+
envpkt fleet --format json # JSON output
|
|
198
|
+
envpkt fleet --status critical # Filter agents by health status
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Shared Catalog
|
|
99
202
|
|
|
100
203
|
When multiple agents consume the same secrets, a **shared catalog** prevents metadata duplication. Define secret metadata once in a central file, then have each agent reference it.
|
|
101
204
|
|
|
102
|
-
|
|
205
|
+
#### Catalog file (`infra/envpkt.toml`)
|
|
103
206
|
|
|
104
207
|
```toml
|
|
105
208
|
version = 1
|
|
@@ -108,7 +211,7 @@ version = 1
|
|
|
108
211
|
stale_warning_days = 90
|
|
109
212
|
require_expiration = true
|
|
110
213
|
|
|
111
|
-
[
|
|
214
|
+
[secret.DATABASE_URL]
|
|
112
215
|
service = "postgres"
|
|
113
216
|
purpose = "Primary application database"
|
|
114
217
|
capabilities = ["SELECT", "INSERT", "UPDATE", "DELETE"]
|
|
@@ -117,14 +220,14 @@ source = "vault"
|
|
|
117
220
|
created = "2025-11-01"
|
|
118
221
|
expires = "2026-11-01"
|
|
119
222
|
|
|
120
|
-
[
|
|
223
|
+
[secret.REDIS_URL]
|
|
121
224
|
service = "redis"
|
|
122
225
|
purpose = "Caching and session storage"
|
|
123
226
|
created = "2025-11-01"
|
|
124
227
|
expires = "2026-11-01"
|
|
125
228
|
```
|
|
126
229
|
|
|
127
|
-
|
|
230
|
+
#### Agent file (`agents/pipeline/envpkt.toml`)
|
|
128
231
|
|
|
129
232
|
```toml
|
|
130
233
|
version = 1
|
|
@@ -136,11 +239,11 @@ consumer = "agent"
|
|
|
136
239
|
secrets = ["DATABASE_URL", "REDIS_URL"]
|
|
137
240
|
|
|
138
241
|
# Optional: narrow the catalog definition for this agent
|
|
139
|
-
[
|
|
242
|
+
[secret.DATABASE_URL]
|
|
140
243
|
capabilities = ["SELECT"]
|
|
141
244
|
```
|
|
142
245
|
|
|
143
|
-
|
|
246
|
+
#### Resolve to a flat config
|
|
144
247
|
|
|
145
248
|
```bash
|
|
146
249
|
envpkt resolve -c agents/pipeline/envpkt.toml
|
|
@@ -148,13 +251,32 @@ envpkt resolve -c agents/pipeline/envpkt.toml
|
|
|
148
251
|
|
|
149
252
|
This produces a self-contained config with catalog metadata merged in and agent overrides applied. The resolved output has no `catalog` reference — it's ready for deployment.
|
|
150
253
|
|
|
151
|
-
|
|
254
|
+
#### Merge rules
|
|
152
255
|
|
|
153
|
-
- Each field in the agent's `[
|
|
256
|
+
- Each field in the agent's `[secret.KEY]` override **replaces** the catalog field (shallow merge)
|
|
154
257
|
- Omitted fields keep the catalog value
|
|
155
258
|
- `agent.secrets` is the source of truth for which keys the agent needs
|
|
156
259
|
|
|
157
|
-
##
|
|
260
|
+
## How envpkt Compares
|
|
261
|
+
|
|
262
|
+
The agentic credential space is splitting into approaches. Here's where envpkt fits:
|
|
263
|
+
|
|
264
|
+
| | envpkt | agent-vault | AgentSecrets | 1Password Agentic | Infisical |
|
|
265
|
+
| --------------------------- | ----------------------------------------------------------- | --------------------------- | -------------------------- | ----------------------------- | -------------------- |
|
|
266
|
+
| **Core approach** | Metadata sidecar | Git-based secret storage | Proxy injection | Browser autofill | Secret retrieval API |
|
|
267
|
+
| **What agents see** | Structured metadata (capabilities, constraints, expiration) | Raw secret values | Nothing (proxy handles it) | Nothing (autofill handles it) | Raw secret values |
|
|
268
|
+
| **MCP server** | Yes | Yes | No | No | Yes |
|
|
269
|
+
| **Encryption at rest** | age sealed packets | Git-crypt | N/A (proxy model) | Vault encryption | Vault encryption |
|
|
270
|
+
| **Per-agent scoping** | Yes (agent.secrets, capabilities) | Yes (policies) | Yes (proxy rules) | No | Yes (policies) |
|
|
271
|
+
| **Fleet health monitoring** | Yes (fleet scan, aggregated audit) | No | No | No | No |
|
|
272
|
+
| **Credential metadata** | Rich (purpose, capabilities, rotation, lifecycle) | Minimal | Minimal | Minimal | Moderate |
|
|
273
|
+
| **Adoption path** | Scan existing env vars, add metadata incrementally | New secret storage workflow | Proxy configuration | Browser extension | API integration |
|
|
274
|
+
|
|
275
|
+
**envpkt's angle**: Competitors are fighting over how secrets move — retrieval vs. proxy vs. autofill. envpkt owns what secrets _mean_. Rate limits, expiration policies, capability scopes, rotation runbooks — structured semantics that travel with the credential. That's the layer the others don't have.
|
|
276
|
+
|
|
277
|
+
> **Note**: This comparison reflects publicly available information. Verify current feature sets before making procurement decisions.
|
|
278
|
+
|
|
279
|
+
## CLI Reference
|
|
158
280
|
|
|
159
281
|
### `envpkt init`
|
|
160
282
|
|
|
@@ -196,18 +318,6 @@ envpkt resolve -c agent.toml --dry-run # Preview without writing
|
|
|
196
318
|
|
|
197
319
|
Configs without a `catalog` field pass through unchanged.
|
|
198
320
|
|
|
199
|
-
### `envpkt fleet`
|
|
200
|
-
|
|
201
|
-
Scan a directory tree for `envpkt.toml` files and aggregate health.
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
envpkt fleet # Scan current directory (depth 3)
|
|
205
|
-
envpkt fleet -d /opt/agents # Scan specific directory
|
|
206
|
-
envpkt fleet --depth 5 # Increase scan depth
|
|
207
|
-
envpkt fleet --format json # JSON output
|
|
208
|
-
envpkt fleet --status critical # Filter agents by health status
|
|
209
|
-
```
|
|
210
|
-
|
|
211
321
|
### `envpkt inspect`
|
|
212
322
|
|
|
213
323
|
Display a structured view of an `envpkt.toml` file. Automatically resolves catalog references.
|
|
@@ -234,6 +344,26 @@ envpkt exec --strict -- ./deploy.sh # Abort if audit is not healthy
|
|
|
234
344
|
envpkt exec --profile staging -- ... # Use a specific fnox profile
|
|
235
345
|
```
|
|
236
346
|
|
|
347
|
+
### `envpkt seal`
|
|
348
|
+
|
|
349
|
+
Encrypt secret values into `envpkt.toml` using [age](https://age-encryption.org/). Sealed values are safe to commit to git — only the holder of the private key can decrypt them.
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
envpkt seal # Seal all secrets in envpkt.toml
|
|
353
|
+
envpkt seal -c path/to/envpkt.toml # Specify config path
|
|
354
|
+
envpkt seal --profile staging # Use a specific fnox profile for value resolution
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Requires `agent.recipient` (age public key) in your config. Values are resolved via cascade:
|
|
358
|
+
|
|
359
|
+
1. **fnox** (if available)
|
|
360
|
+
2. **Environment variables** (e.g. `OPENAI_API_KEY` in your shell)
|
|
361
|
+
3. **Interactive prompt** (asks you to paste each value)
|
|
362
|
+
|
|
363
|
+
After sealing, each secret gets an `encrypted_value` field. At boot time, `envpkt exec` or `boot()` automatically decrypts sealed values using the `agent.identity` file.
|
|
364
|
+
|
|
365
|
+
See [`examples/sealed-agent.toml`](./examples/sealed-agent.toml) for a complete example.
|
|
366
|
+
|
|
237
367
|
### `envpkt env scan`
|
|
238
368
|
|
|
239
369
|
Auto-discover credentials from your shell environment. Matches env vars against ~45 known services (exact name), ~13 generic suffix patterns (`*_API_KEY`, `*_SECRET`, `*_TOKEN`, etc.), and ~29 value shape patterns (`sk-*`, `ghp_*`, `AKIA*`, `postgres://`, etc.).
|
|
@@ -262,9 +392,30 @@ envpkt env check --strict # Exit non-zero on any drift
|
|
|
262
392
|
envpkt env check -c path/to/envpkt.toml # Specify config path
|
|
263
393
|
```
|
|
264
394
|
|
|
395
|
+
### `envpkt env export`
|
|
396
|
+
|
|
397
|
+
Output `export KEY='VALUE'` statements for sourcing secrets into the current shell. Secrets are resolved via sealed packets and/or fnox — the same pipeline as `envpkt exec`, but instead of spawning a subprocess, the output is designed to be `eval`'d.
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
# Source secrets into the current shell
|
|
401
|
+
eval "$(envpkt env export)"
|
|
402
|
+
|
|
403
|
+
# Use a specific fnox profile
|
|
404
|
+
eval "$(envpkt env export --profile staging)"
|
|
405
|
+
|
|
406
|
+
# Specify config path
|
|
407
|
+
eval "$(envpkt env export -c path/to/envpkt.toml)"
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Add to your shell startup (e.g. `~/.zshrc` or `~/.bashrc`) for automatic secret loading. envpkt's [config discovery chain](#config-resolution) finds your config automatically — no platform-specific shell logic needed:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
eval "$(envpkt env export 2>/dev/null)"
|
|
414
|
+
```
|
|
415
|
+
|
|
265
416
|
### `envpkt shell-hook`
|
|
266
417
|
|
|
267
|
-
Output a shell function that runs `envpkt audit --format minimal` whenever you `cd` into a directory
|
|
418
|
+
Output a shell function that runs `envpkt audit --format minimal` whenever you `cd` into a directory. envpkt's config discovery chain automatically finds config files beyond CWD (see [Config Resolution](#config-resolution)), so the hook works even in directories without a local `envpkt.toml`.
|
|
268
419
|
|
|
269
420
|
```bash
|
|
270
421
|
# Add to your .zshrc
|
|
@@ -282,85 +433,34 @@ Start the envpkt MCP server (stdio transport) for AI agent integration.
|
|
|
282
433
|
envpkt mcp
|
|
283
434
|
```
|
|
284
435
|
|
|
285
|
-
##
|
|
436
|
+
## Config Resolution
|
|
286
437
|
|
|
287
|
-
|
|
438
|
+
Commands that read `envpkt.toml` resolve the config path via a priority chain:
|
|
288
439
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Tools
|
|
301
|
-
|
|
302
|
-
| Tool | Description |
|
|
303
|
-
| ------------------ | ------------------------------------------------------- |
|
|
304
|
-
| `getPacketHealth` | Get overall health status with per-secret audit results |
|
|
305
|
-
| `listCapabilities` | List agent and per-secret capabilities |
|
|
306
|
-
| `getSecretMeta` | Get metadata for a specific secret by key |
|
|
307
|
-
| `checkExpiration` | Check expiration status and days remaining |
|
|
308
|
-
|
|
309
|
-
### Resources
|
|
310
|
-
|
|
311
|
-
| URI | Description |
|
|
312
|
-
| ----------------------- | --------------------------------- |
|
|
313
|
-
| `envpkt://health` | Current credential health summary |
|
|
314
|
-
| `envpkt://capabilities` | Agent and secret capabilities |
|
|
315
|
-
|
|
316
|
-
No secret values are ever exposed through the MCP server.
|
|
317
|
-
|
|
318
|
-
## Schema
|
|
319
|
-
|
|
320
|
-
envpkt.toml is validated against a JSON Schema. Editors with TOML + JSON Schema support will provide autocompletion and validation when the `#:schema` directive is present on line 1.
|
|
321
|
-
|
|
322
|
-
The schema is published at:
|
|
323
|
-
|
|
324
|
-
- npm: `envpkt/schema` (importable via package exports)
|
|
325
|
-
- GitHub: `schemas/envpkt.schema.json`
|
|
326
|
-
|
|
327
|
-
### Secret Metadata Fields
|
|
328
|
-
|
|
329
|
-
Each `[meta.<KEY>]` section describes a secret:
|
|
330
|
-
|
|
331
|
-
| Tier | Fields | Description |
|
|
332
|
-
| --------------- | ----------------------------------------------- | ----------------------------------------- |
|
|
333
|
-
| **Scan-first** | `service`, `expires`, `rotation_url` | Key health indicators for audit |
|
|
334
|
-
| **Context** | `purpose`, `capabilities`, `created` | Why this secret exists and what it grants |
|
|
335
|
-
| **Operational** | `rotates`, `rate_limit`, `model_hint`, `source` | Runtime and provisioning info |
|
|
336
|
-
| **Enforcement** | `required`, `tags` | Filtering, grouping, and policy |
|
|
337
|
-
|
|
338
|
-
### Agent Identity
|
|
440
|
+
1. **Explicit flag** — `-c path/to/envpkt.toml`
|
|
441
|
+
2. **Environment variable** — `ENVPKT_CONFIG`
|
|
442
|
+
3. **Discovery chain** — searches in order:
|
|
443
|
+
- `./envpkt.toml` (current working directory)
|
|
444
|
+
- Custom paths in `ENVPKT_SEARCH_PATH` (colon-separated)
|
|
445
|
+
- `~/.envpkt/envpkt.toml` (user home)
|
|
446
|
+
- Cloud storage paths (OneDrive, iCloud, Dropbox, Google Drive)
|
|
339
447
|
|
|
340
|
-
|
|
448
|
+
When a config is discovered outside CWD, envpkt prints where it loaded from to stderr:
|
|
341
449
|
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
name = "data-pipeline-agent"
|
|
345
|
-
consumer = "agent" # agent | service | developer | ci
|
|
346
|
-
description = "ETL pipeline processor"
|
|
347
|
-
capabilities = ["read-s3", "write-postgres"]
|
|
348
|
-
expires = "2027-01-01"
|
|
349
|
-
services = ["aws", "postgres"]
|
|
350
|
-
secrets = ["DATABASE_URL", "AWS_KEY"] # When using a catalog
|
|
450
|
+
```
|
|
451
|
+
envpkt: loaded /Users/you/.envpkt/envpkt.toml
|
|
351
452
|
```
|
|
352
453
|
|
|
353
|
-
###
|
|
454
|
+
### `ENVPKT_SEARCH_PATH`
|
|
354
455
|
|
|
355
|
-
|
|
456
|
+
Prepend custom search locations (colon-separated paths to `envpkt.toml` files):
|
|
356
457
|
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
stale_warning_days = 90 # Flag secrets older than N days without updates
|
|
360
|
-
require_expiration = true # Require expires on all secrets
|
|
361
|
-
require_service = true # Require service on all secrets
|
|
458
|
+
```bash
|
|
459
|
+
export ENVPKT_SEARCH_PATH="$HOME/OneDrive/.envpkt/envpkt.toml:/custom/path/envpkt.toml"
|
|
362
460
|
```
|
|
363
461
|
|
|
462
|
+
These are searched after CWD but before the built-in candidate paths. Useful for corporate OneDrive names, Google Drive with email in the path, or any non-standard location.
|
|
463
|
+
|
|
364
464
|
## Library API
|
|
365
465
|
|
|
366
466
|
envpkt is also available as a TypeScript library with a functional programming API built on [functype](https://github.com/jordanburke/functype). All functions return `Either<Error, Result>` or `Option<T>` — no thrown exceptions.
|
|
@@ -371,6 +471,7 @@ import { boot, bootSafe, loadConfig, computeAudit, scanFleet, resolveConfig } fr
|
|
|
371
471
|
// Boot API — load config, resolve catalog, audit, inject secrets
|
|
372
472
|
const result = boot({ configPath: "envpkt.toml", inject: true })
|
|
373
473
|
console.log(result.audit.status) // "healthy" | "degraded" | "critical"
|
|
474
|
+
console.log(result.configSource) // "flag" | "env" | "cwd" | "search"
|
|
374
475
|
|
|
375
476
|
// Safe variant returns Either instead of throwing
|
|
376
477
|
const safe = bootSafe({ configPath: "envpkt.toml" })
|
|
@@ -399,6 +500,21 @@ const fleet = scanFleet("/opt/agents", { maxDepth: 3 })
|
|
|
399
500
|
console.log(`${fleet.total_agents} agents, ${fleet.total_secrets} secrets`)
|
|
400
501
|
```
|
|
401
502
|
|
|
503
|
+
### Framework Integration
|
|
504
|
+
|
|
505
|
+
`boot()` runs before your agent framework initializes, making it compatible with any framework:
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
import { boot } from "envpkt"
|
|
509
|
+
|
|
510
|
+
// Resolve and inject credentials before agent startup
|
|
511
|
+
const result = boot({ configPath: "envpkt.toml", inject: true })
|
|
512
|
+
console.log(`${result.audit.status} — ${result.injected.length} secrets loaded`)
|
|
513
|
+
|
|
514
|
+
// Now start your agent framework — process.env is populated
|
|
515
|
+
// Works with LangChain, CrewAI, AutoGen, or any framework that reads from process.env
|
|
516
|
+
```
|
|
517
|
+
|
|
402
518
|
### Packet Formatting API
|
|
403
519
|
|
|
404
520
|
```typescript
|
|
@@ -460,6 +576,32 @@ matchEnvVar("OPENAI_API_KEY", "sk-test123").fold(
|
|
|
460
576
|
)
|
|
461
577
|
```
|
|
462
578
|
|
|
579
|
+
### Seal API
|
|
580
|
+
|
|
581
|
+
```typescript
|
|
582
|
+
import { ageEncrypt, ageDecrypt, sealSecrets, unsealSecrets } from "envpkt"
|
|
583
|
+
|
|
584
|
+
// Encrypt a single value
|
|
585
|
+
const encrypted = ageEncrypt("sk-my-api-key", "age1ql3z7hjy...")
|
|
586
|
+
encrypted.fold(
|
|
587
|
+
(err) => console.error("Encrypt failed:", err.message),
|
|
588
|
+
(ciphertext) => console.log(ciphertext), // -----BEGIN AGE ENCRYPTED FILE-----
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
// Decrypt a single value
|
|
592
|
+
const decrypted = ageDecrypt(ciphertext, "/path/to/identity.txt")
|
|
593
|
+
|
|
594
|
+
// Seal all secrets in a config's meta
|
|
595
|
+
const sealed = sealSecrets(config.meta, { OPENAI_API_KEY: "sk-..." }, recipientPublicKey)
|
|
596
|
+
|
|
597
|
+
// Unseal all encrypted_value entries
|
|
598
|
+
const values = unsealSecrets(config.meta, "/path/to/identity.txt")
|
|
599
|
+
values.fold(
|
|
600
|
+
(err) => console.error("Unseal failed:", err.message),
|
|
601
|
+
(secrets) => console.log(secrets), // { OPENAI_API_KEY: "sk-..." }
|
|
602
|
+
)
|
|
603
|
+
```
|
|
604
|
+
|
|
463
605
|
### Catalog Resolution API
|
|
464
606
|
|
|
465
607
|
```typescript
|
|
@@ -482,11 +624,58 @@ loadConfig(configPath).fold(
|
|
|
482
624
|
)
|
|
483
625
|
```
|
|
484
626
|
|
|
627
|
+
## Schema
|
|
628
|
+
|
|
629
|
+
envpkt.toml is validated against a JSON Schema. Editors with TOML + JSON Schema support will provide autocompletion and validation when the `#:schema` directive is present on line 1.
|
|
630
|
+
|
|
631
|
+
The schema is published at:
|
|
632
|
+
|
|
633
|
+
- npm: `envpkt/schema` (importable via package exports)
|
|
634
|
+
- GitHub: `schemas/envpkt.schema.json`
|
|
635
|
+
|
|
636
|
+
### Secret Metadata Fields
|
|
637
|
+
|
|
638
|
+
Each `[secret.<KEY>]` section describes a secret:
|
|
639
|
+
|
|
640
|
+
| Tier | Fields | Description |
|
|
641
|
+
| --------------- | ----------------------------------------------- | ------------------------------------------- |
|
|
642
|
+
| **Scan-first** | `service`, `expires`, `rotation_url` | Key health indicators for audit |
|
|
643
|
+
| **Context** | `purpose`, `comment`, `capabilities`, `created` | Why this secret exists and what it grants |
|
|
644
|
+
| **Operational** | `rotates`, `rate_limit`, `model_hint`, `source` | Runtime and provisioning info |
|
|
645
|
+
| **Sealed** | `encrypted_value` | Age-encrypted secret value (safe to commit) |
|
|
646
|
+
| **Enforcement** | `required`, `tags` | Filtering, grouping, and policy |
|
|
647
|
+
|
|
648
|
+
### Agent Identity
|
|
649
|
+
|
|
650
|
+
The optional `[agent]` section identifies the AI agent:
|
|
651
|
+
|
|
652
|
+
```toml
|
|
653
|
+
[agent]
|
|
654
|
+
name = "data-pipeline-agent"
|
|
655
|
+
consumer = "agent" # agent | service | developer | ci
|
|
656
|
+
description = "ETL pipeline processor"
|
|
657
|
+
capabilities = ["read-s3", "write-postgres"]
|
|
658
|
+
expires = "2027-01-01"
|
|
659
|
+
services = ["aws", "postgres"]
|
|
660
|
+
secrets = ["DATABASE_URL", "AWS_KEY"] # When using a catalog
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Lifecycle Policy
|
|
664
|
+
|
|
665
|
+
The optional `[lifecycle]` section configures audit behavior:
|
|
666
|
+
|
|
667
|
+
```toml
|
|
668
|
+
[lifecycle]
|
|
669
|
+
stale_warning_days = 90 # Flag secrets older than N days without updates
|
|
670
|
+
require_expiration = true # Require expires on all secrets
|
|
671
|
+
require_service = true # Require service on all secrets
|
|
672
|
+
```
|
|
673
|
+
|
|
485
674
|
## fnox Integration
|
|
486
675
|
|
|
487
676
|
envpkt integrates with [fnox](https://github.com/jordanburke/fnox) for secret resolution:
|
|
488
677
|
|
|
489
|
-
- `envpkt init --from-fnox` scaffolds `[
|
|
678
|
+
- `envpkt init --from-fnox` scaffolds `[secret.*]` entries from `fnox.toml`
|
|
490
679
|
- `envpkt audit` detects orphaned keys (in envpkt but not in fnox, or vice versa)
|
|
491
680
|
- `envpkt exec` injects fnox secrets into the subprocess environment
|
|
492
681
|
|