envpkt 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Jordan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,507 @@
1
+ # envpkt
2
+
3
+ [![Node.js CI](https://github.com/jordanburke/envpkt/actions/workflows/node.js.yml/badge.svg)](https://github.com/jordanburke/envpkt/actions/workflows/node.js.yml)
4
+ [![npm version](https://img.shields.io/npm/v/envpkt.svg)](https://www.npmjs.com/package/envpkt)
5
+
6
+ Credential lifecycle and fleet management for AI agents.
7
+
8
+ **fnox handles access. envpkt handles awareness.** One file (`envpkt.toml`) answers five questions per credential: **What / Where / Why / When / How**.
9
+
10
+ ## Why envpkt?
11
+
12
+ Secrets managers store values. envpkt stores _metadata about_ those values — what service each credential authenticates to, when it expires, how to rotate it, and why it exists. This gives AI agents (and their operators) a structured way to:
13
+
14
+ - Audit credential health across a fleet of agents
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
20
+
21
+ envpkt never touches secret values. It works alongside your existing secrets manager (Vault, fnox, CI variables, etc.).
22
+
23
+ ## Quick Start
24
+
25
+ ```bash
26
+ # Install
27
+ npm install -g envpkt
28
+
29
+ # Auto-discover credentials from your shell environment
30
+ envpkt env scan
31
+
32
+ # Scaffold envpkt.toml from discovered credentials
33
+ envpkt env scan --write
34
+
35
+ # Audit credential health
36
+ envpkt audit
37
+
38
+ # Check for drift between envpkt.toml and live environment
39
+ envpkt env check
40
+
41
+ # Scan a directory tree of agents
42
+ envpkt fleet
43
+ ```
44
+
45
+ ## The envpkt.toml File
46
+
47
+ Every project gets one `envpkt.toml` that describes its credentials. Here's a minimal example:
48
+
49
+ ```toml
50
+ #:schema https://raw.githubusercontent.com/jordanburke/envpkt/main/schemas/envpkt.schema.json
51
+
52
+ version = 1
53
+
54
+ [meta.API_KEY]
55
+ service = "stripe"
56
+ ```
57
+
58
+ And a more complete one:
59
+
60
+ ```toml
61
+ #:schema https://raw.githubusercontent.com/jordanburke/envpkt/main/schemas/envpkt.schema.json
62
+
63
+ version = 1
64
+
65
+ [agent]
66
+ name = "billing-service"
67
+ consumer = "agent"
68
+ description = "Payment processing agent"
69
+ capabilities = ["charge", "refund"]
70
+ expires = "2027-01-01"
71
+
72
+ [lifecycle]
73
+ stale_warning_days = 90
74
+ require_expiration = true
75
+ require_service = true
76
+
77
+ [meta.STRIPE_SECRET_KEY]
78
+ service = "stripe"
79
+ purpose = "Process customer payments and manage subscriptions"
80
+ capabilities = ["charges:write", "subscriptions:write"]
81
+ created = "2026-01-15"
82
+ expires = "2027-01-15"
83
+ rotation_url = "https://dashboard.stripe.com/apikeys"
84
+ source = "vault"
85
+
86
+ [meta.DATABASE_URL]
87
+ service = "postgres"
88
+ purpose = "Read/write access to the billing database"
89
+ capabilities = ["SELECT", "INSERT", "UPDATE"]
90
+ created = "2026-02-01"
91
+ expires = "2026-08-01"
92
+ rotation_url = "https://wiki.internal/runbooks/rotate-db-creds"
93
+ source = "vault"
94
+ ```
95
+
96
+ See [`examples/`](./examples/) for more configurations.
97
+
98
+ ## Shared Secret Catalog
99
+
100
+ 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
+
102
+ ### Catalog file (`infra/envpkt.toml`)
103
+
104
+ ```toml
105
+ version = 1
106
+
107
+ [lifecycle]
108
+ stale_warning_days = 90
109
+ require_expiration = true
110
+
111
+ [meta.DATABASE_URL]
112
+ service = "postgres"
113
+ purpose = "Primary application database"
114
+ capabilities = ["SELECT", "INSERT", "UPDATE", "DELETE"]
115
+ rotation_url = "https://wiki.internal/runbooks/rotate-db"
116
+ source = "vault"
117
+ created = "2025-11-01"
118
+ expires = "2026-11-01"
119
+
120
+ [meta.REDIS_URL]
121
+ service = "redis"
122
+ purpose = "Caching and session storage"
123
+ created = "2025-11-01"
124
+ expires = "2026-11-01"
125
+ ```
126
+
127
+ ### Agent file (`agents/pipeline/envpkt.toml`)
128
+
129
+ ```toml
130
+ version = 1
131
+ catalog = "../../infra/envpkt.toml"
132
+
133
+ [agent]
134
+ name = "data-pipeline"
135
+ consumer = "agent"
136
+ secrets = ["DATABASE_URL", "REDIS_URL"]
137
+
138
+ # Optional: narrow the catalog definition for this agent
139
+ [meta.DATABASE_URL]
140
+ capabilities = ["SELECT"]
141
+ ```
142
+
143
+ ### Resolve to a flat config
144
+
145
+ ```bash
146
+ envpkt resolve -c agents/pipeline/envpkt.toml
147
+ ```
148
+
149
+ 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
+
151
+ ### Merge rules
152
+
153
+ - Each field in the agent's `[meta.KEY]` override **replaces** the catalog field (shallow merge)
154
+ - Omitted fields keep the catalog value
155
+ - `agent.secrets` is the source of truth for which keys the agent needs
156
+
157
+ ## CLI Commands
158
+
159
+ ### `envpkt init`
160
+
161
+ Generate an `envpkt.toml` template in the current directory.
162
+
163
+ ```bash
164
+ envpkt init # Basic template
165
+ envpkt init --from-fnox # Scaffold from fnox.toml
166
+ envpkt init --agent --name "my-agent" # Include agent identity
167
+ envpkt init --catalog "../infra/envpkt.toml" # Reference a shared catalog
168
+ envpkt init --agent --name "bot" --capabilities "read,write" --expires "2027-01-01"
169
+ ```
170
+
171
+ ### `envpkt audit`
172
+
173
+ Check credential health against lifecycle policies. Automatically resolves catalog references.
174
+
175
+ ```bash
176
+ envpkt audit # Table output
177
+ envpkt audit --format json # JSON output
178
+ envpkt audit --expiring 14 # Show secrets expiring within 14 days
179
+ envpkt audit --status expired # Filter by status
180
+ envpkt audit --strict # Exit non-zero on any non-healthy secret
181
+ envpkt audit -c path/to/envpkt.toml # Specify config path
182
+ ```
183
+
184
+ Exit codes: `0` = healthy, `1` = degraded, `2` = critical.
185
+
186
+ ### `envpkt resolve`
187
+
188
+ Resolve catalog references and output a flat, self-contained config.
189
+
190
+ ```bash
191
+ envpkt resolve -c agent.toml # Output resolved TOML to stdout
192
+ envpkt resolve -c agent.toml --format json # Output as JSON
193
+ envpkt resolve -c agent.toml -o resolved.toml # Write to file
194
+ envpkt resolve -c agent.toml --dry-run # Preview without writing
195
+ ```
196
+
197
+ Configs without a `catalog` field pass through unchanged.
198
+
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
+ ### `envpkt inspect`
212
+
213
+ Display a structured view of an `envpkt.toml` file. Automatically resolves catalog references.
214
+
215
+ ```bash
216
+ envpkt inspect # Current directory
217
+ envpkt inspect -c path/to/envpkt.toml # Specific file
218
+ envpkt inspect --format json # Raw JSON dump
219
+ envpkt inspect --resolved # Show resolved view (catalog merged)
220
+ envpkt inspect --secrets # Show secret values from env (masked)
221
+ envpkt inspect --secrets --plaintext # Show secret values in plaintext
222
+ ```
223
+
224
+ The `--secrets` flag reads values from environment variables matching each secret key. By default values are masked (`pos•••••yapp`). Add `--plaintext` to display full values.
225
+
226
+ ### `envpkt exec`
227
+
228
+ Run a pre-flight audit, inject secrets from fnox into the environment, then execute a command.
229
+
230
+ ```bash
231
+ envpkt exec -- node server.js # Audit then run
232
+ envpkt exec --skip-audit -- npm start # Skip the audit
233
+ envpkt exec --strict -- ./deploy.sh # Abort if audit is not healthy
234
+ envpkt exec --profile staging -- ... # Use a specific fnox profile
235
+ ```
236
+
237
+ ### `envpkt env scan`
238
+
239
+ 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.).
240
+
241
+ ```bash
242
+ envpkt env scan # Table output with confidence icons
243
+ envpkt env scan --format json # JSON output
244
+ envpkt env scan --write # Write/append to envpkt.toml
245
+ envpkt env scan --dry-run # Preview TOML that would be written
246
+ envpkt env scan --include-unknown # Include vars with no inferred service
247
+ ```
248
+
249
+ Confidence levels:
250
+
251
+ - **High** (●) — exact name match or recognized value prefix
252
+ - **Medium** (◐) — generic suffix pattern with derived service name
253
+
254
+ ### `envpkt env check`
255
+
256
+ Bidirectional drift detection between `envpkt.toml` and the live shell environment. Checks both directions: TOML keys missing from env, and credential-shaped env vars not tracked in TOML.
257
+
258
+ ```bash
259
+ envpkt env check # Table output
260
+ envpkt env check --format json # JSON output
261
+ envpkt env check --strict # Exit non-zero on any drift
262
+ envpkt env check -c path/to/envpkt.toml # Specify config path
263
+ ```
264
+
265
+ ### `envpkt shell-hook`
266
+
267
+ Output a shell function that runs `envpkt audit --format minimal` whenever you `cd` into a directory containing `envpkt.toml`.
268
+
269
+ ```bash
270
+ # Add to your .zshrc
271
+ eval "$(envpkt shell-hook zsh)"
272
+
273
+ # Add to your .bashrc
274
+ eval "$(envpkt shell-hook bash)"
275
+ ```
276
+
277
+ ### `envpkt mcp`
278
+
279
+ Start the envpkt MCP server (stdio transport) for AI agent integration.
280
+
281
+ ```bash
282
+ envpkt mcp
283
+ ```
284
+
285
+ ## MCP Server
286
+
287
+ envpkt ships an [MCP](https://modelcontextprotocol.io/) server that exposes credential metadata to AI agents. Add it to your MCP client config:
288
+
289
+ ```json
290
+ {
291
+ "mcpServers": {
292
+ "envpkt": {
293
+ "command": "envpkt",
294
+ "args": ["mcp"]
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
339
+
340
+ The optional `[agent]` section identifies the AI agent:
341
+
342
+ ```toml
343
+ [agent]
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
351
+ ```
352
+
353
+ ### Lifecycle Policy
354
+
355
+ The optional `[lifecycle]` section configures audit behavior:
356
+
357
+ ```toml
358
+ [lifecycle]
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
362
+ ```
363
+
364
+ ## Library API
365
+
366
+ 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.
367
+
368
+ ```typescript
369
+ import { boot, bootSafe, loadConfig, computeAudit, scanFleet, resolveConfig } from "envpkt"
370
+
371
+ // Boot API — load config, resolve catalog, audit, inject secrets
372
+ const result = boot({ configPath: "envpkt.toml", inject: true })
373
+ console.log(result.audit.status) // "healthy" | "degraded" | "critical"
374
+
375
+ // Safe variant returns Either instead of throwing
376
+ const safe = bootSafe({ configPath: "envpkt.toml" })
377
+ safe.fold(
378
+ (err) => console.error("Boot failed:", err._tag),
379
+ (result) => console.log(`${result.injected.length} secrets injected`),
380
+ )
381
+
382
+ // Load and audit directly
383
+ const config = loadConfig("envpkt.toml")
384
+ config.fold(
385
+ (err) => console.error("Failed:", err._tag),
386
+ (config) => {
387
+ const audit = computeAudit(config)
388
+ audit.secrets.forEach((s) => {
389
+ s.days_remaining.fold(
390
+ () => console.log(`${s.key}: no expiration set`),
391
+ (days) => console.log(`${s.key}: ${days} days remaining`),
392
+ )
393
+ })
394
+ },
395
+ )
396
+
397
+ // Fleet scan
398
+ const fleet = scanFleet("/opt/agents", { maxDepth: 3 })
399
+ console.log(`${fleet.total_agents} agents, ${fleet.total_secrets} secrets`)
400
+ ```
401
+
402
+ ### Packet Formatting API
403
+
404
+ ```typescript
405
+ import { formatPacket, maskValue } from "envpkt"
406
+
407
+ // formatPacket produces a human-readable text summary of a resolved config
408
+ const text = formatPacket(resolveResult)
409
+
410
+ // With secret values (masked by default)
411
+ const masked = formatPacket(resolveResult, {
412
+ secrets: { DATABASE_URL: "postgres://user:pass@host/db" },
413
+ })
414
+ // DATABASE_URL → postgres = pos•••••t/db
415
+
416
+ // With plaintext secret values
417
+ const plain = formatPacket(resolveResult, {
418
+ secrets: { DATABASE_URL: "postgres://user:pass@host/db" },
419
+ secretDisplay: "plaintext",
420
+ })
421
+ ```
422
+
423
+ ### Environment Scan/Check API
424
+
425
+ ```typescript
426
+ import { envScan, envCheck, generateTomlFromScan, matchEnvVar } from "envpkt"
427
+
428
+ // Scan process.env for credentials
429
+ const scan = envScan(process.env)
430
+ console.log(`Found ${scan.discovered.size} credentials (${scan.high_confidence} high confidence)`)
431
+
432
+ scan.discovered.forEach((m) => {
433
+ const svc = m.service.fold(
434
+ () => "unknown",
435
+ (s) => s,
436
+ )
437
+ console.log(` ${m.envVar} → ${svc} (${m.confidence})`)
438
+ })
439
+
440
+ // Generate TOML blocks from scan results
441
+ const toml = generateTomlFromScan(scan.discovered.toArray())
442
+
443
+ // Check drift between config and live env
444
+ import { loadConfig } from "envpkt"
445
+
446
+ loadConfig("envpkt.toml").fold(
447
+ (err) => console.error(err),
448
+ (config) => {
449
+ const check = envCheck(config, process.env)
450
+ if (!check.is_clean) {
451
+ console.log(`${check.missing_from_env} missing, ${check.untracked_credentials} untracked`)
452
+ }
453
+ },
454
+ )
455
+
456
+ // Match a single env var
457
+ matchEnvVar("OPENAI_API_KEY", "sk-test123").fold(
458
+ () => console.log("Not a credential"),
459
+ (m) => console.log(`Matched: ${m.confidence} confidence`),
460
+ )
461
+ ```
462
+
463
+ ### Catalog Resolution API
464
+
465
+ ```typescript
466
+ import { loadConfig, resolveConfig } from "envpkt"
467
+ import { dirname } from "node:path"
468
+
469
+ const configPath = "agents/pipeline/envpkt.toml"
470
+ loadConfig(configPath).fold(
471
+ (err) => console.error(err),
472
+ (config) => {
473
+ resolveConfig(config, dirname(configPath)).fold(
474
+ (err) => console.error("Catalog error:", err._tag),
475
+ (result) => {
476
+ console.log("Resolved keys:", result.merged)
477
+ console.log("Overridden:", result.overridden)
478
+ // result.config is the flat, self-contained config
479
+ },
480
+ )
481
+ },
482
+ )
483
+ ```
484
+
485
+ ## fnox Integration
486
+
487
+ envpkt integrates with [fnox](https://github.com/jordanburke/fnox) for secret resolution:
488
+
489
+ - `envpkt init --from-fnox` scaffolds `[meta.*]` entries from `fnox.toml`
490
+ - `envpkt audit` detects orphaned keys (in envpkt but not in fnox, or vice versa)
491
+ - `envpkt exec` injects fnox secrets into the subprocess environment
492
+
493
+ ## Development
494
+
495
+ ```bash
496
+ pnpm install
497
+ pnpm validate # format + lint + typecheck + test + build:schema + build
498
+ pnpm test # Run tests only
499
+ pnpm dev # Watch mode
500
+ pnpm demo # Regenerate demo HTML renders in examples/demo/
501
+ ```
502
+
503
+ See [`examples/demo/`](./examples/demo/) for a walkthrough of the catalog system with 3 agents, including styled HTML renders of the inspect output in all 3 display modes (no secrets, masked, plaintext).
504
+
505
+ ## License
506
+
507
+ Apache-2.0