TOML Schema
envpkt.toml is validated against a JSON Schema. The schema is published at:
- npm:
envpkt/schema(importable via package exports) - GitHub:
schemas/envpkt.schema.json
Enable editor autocompletion by adding the schema directive on line 1:
#:schema https://raw.githubusercontent.com/jordanburke/envpkt/main/schemas/envpkt.schema.jsonRoot Fields
Section titled “Root Fields”| Field | Type | Required | Description |
| --------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| version | number | Yes | Schema version number (currently 1) |
| catalog | string | No | Path to shared secret catalog (relative to config file) |
| scope | "shell" | "exec" | No | Whether env export emits this package’s secrets for ambient shell loading (shell) or withholds them so they’re only available via envpkt exec (exec). Default exec. Never affects envpkt exec/env github/env dotenv. |
[namespace] Section
Section titled “[namespace] Section”Optional. Prefixes the injected environment variable name for every
[secret.*] and [env.*] entry, without changing the TOML keys you author or
the names shown in audit/inspect. The TOML key stays the logical name; the
prefix is applied only at the process.env boundary (boot(), exec, env export).
| Field | Type | Required | Description |
| ----------- | -------- | -------- | ------------------------------------------------------------------------------------------ |
| prefix | string | Yes | Prefix applied to injected names (e.g. CIV → CIV__API_KEY) |
| separator | string | No | Separator between prefix and key. Default __. Must be shell-safe — see warning below |
[namespace]prefix = "CIV"separator = "__" # optional, default
[secret.API_KEY] # injected as CIV__API_KEYservice = "example"
[env.LOG_LEVEL] # injected as CIV__LOG_LEVELvalue = "info"A logical key keeps its canonical name everywhere internal (audit, from_key
references, fnox lookup, catalog merge); only the injected/exported name is
prefixed. BootResult.envNames maps each logical key to its wire name.
[identity] Section
Section titled “[identity] Section”Identity and capabilities.
| Field | Type | Required | Description |
| -------------- | --------------------------------------------- | ------------------------ | ------------------------------------------ |
| name | string | Yes (if section present) | Agent display name |
| consumer | "agent" \| "service" \| "developer" \| "ci" | No | Consumer type classification |
| description | string | No | Agent description or role |
| capabilities | string[] | No | Capabilities this agent provides |
| expires | string (date) | No | Agent credential expiration (YYYY-MM-DD) |
| services | string[] | No | Service dependencies |
| key_file | string | No | Path to age identity (private key) file |
| recipient | string | No | Agent’s age public key for encryption |
| secrets | string[] | No | Secret keys this agent needs from catalog |
[secret.<KEY>] Sections
Section titled “[secret.<KEY>] Sections”Per-secret metadata. Each key corresponds to an environment variable name.
| Field | Type | Required | Tier | Description |
| ----------------- | --------------- | -------- | ----------- | ----------------------------------------------------------------------------------- |
| service | string | No | Scan-first | Service this secret authenticates to |
| expires | string (date) | No | Scan-first | Expiration date (YYYY-MM-DD) |
| rotation_url | string (URI) | No | Scan-first | URL for rotation procedure |
| purpose | string | No | Context | Why this secret exists |
| comment | string | No | Context | Free-form annotation or note |
| capabilities | string[] | No | Context | Operations this secret grants |
| created | string (date) | No | Context | Provisioning date (YYYY-MM-DD) |
| rotates | string | No | Operational | Rotation schedule (e.g., 90d, quarterly) |
| rate_limit | string | No | Operational | Rate limit info (e.g., 1000/min) |
| model_hint | string | No | Operational | Suggested model or tier |
| source | string | No | Operational | Secret origin (e.g., vault, ci, manual) |
| encrypted_value | string | No | Value | Age-encrypted ciphertext — mutually exclusive with from_key |
| from_key | string | No | Alias | Reference another secret entry (format: "secret.<KEY>") — see Aliases |
| required | boolean | No | Enforcement | Whether secret is required for operation |
| tags | object | No | Enforcement | Key-value tags for grouping/filtering |
| namespace | string | No | Enforcement | Override the file-level [namespace] prefix for this entry. "" opts out entirely |
[env.<KEY>] Sections
Section titled “[env.<KEY>] Sections”Plaintext environment defaults. Each key corresponds to an environment variable. These are non-secret values that are safe to commit — use [secret.*] for sensitive credentials.
| Field | Type | Required | Description |
| ----------- | -------- | ------------------ | ----------------------------------------------------------------------------- |
| value | string | Yes unless aliased | Default value for this env variable — mutually exclusive with from_key |
| from_key | string | No | Reference another env entry (format: "env.<KEY>") — see Aliases |
| purpose | string | No | Why this env var exists |
| comment | string | No | Free-form annotation or note |
| tags | object | No | Key-value tags for grouping/filtering |
| namespace | string | No | Override the file-level [namespace] prefix for this entry. "" opts out |
[env.NODE_ENV]value = "production"purpose = "Runtime environment mode"comment = "Override to 'development' for local testing"
[env.LOG_LEVEL]value = "info"purpose = "Application log verbosity"Aliases
Section titled “Aliases”Some consumers expect a credential under a different env var name than the one
you use canonically. from_key exposes the same governed value under multiple
canonical names without duplicating it.
[secret.API_KEY]service = "example"expires = "2026-12-31"rotation_url = "https://api.example.com/settings/keys"purpose = "Authenticates envpkt-managed tooling"
# Same governed value, exposed under a second name for a consumer# that hardcodes a different env var name.[secret.LEGACY_API_KEY]from_key = "secret.API_KEY"purpose = "Name required by the legacy consumer"Works identically for [env.*]:
[env.SERVICE_URL]value = "https://api.example.com"
[env.LEGACY_URL]from_key = "env.SERVICE_URL"Rules:
from_keymust be formatted as"secret.<KEY>"or"env.<KEY>".- The target must exist in the same resolved config (after catalog merge).
- The target must not itself be an alias — single hop only.
- An alias cannot also declare a value-producing field (
encrypted_valuefor secrets,valuefor env entries). It has no value of its own. - Cross-type aliasing (secret → env or env → secret) is rejected at load time.
Runtime behavior:
At boot, envpkt injects both the target AND every alias pointing at it, as
separate entries in process.env holding the same value:
$ envpkt exec -- env | grep API_KEYAPI_KEY=sk-...LEGACY_API_KEY=sk-...Audit, envpkt inspect, envpkt env export, and MCP responses all list
aliases as first-class entries, tagged with alias_of so the relationship is
visible. Status (expiration, health) is inherited from the target — an alias
is healthy iff its target is healthy.
envpkt audit --all includes env default drift alongside secret health. Use envpkt audit --env-only to see only env defaults.
Aliases + namespace: a from_key reference is always the logical key
("secret.API_KEY"), independent of any namespace. The alias is injected under
its own namespace resolution, so it can bridge a namespaced canonical value to
a different injected name — e.g. expose a namespaced secret under a plain,
un-prefixed legacy name:
[namespace]prefix = "CIV"
[secret.API_KEY] # injected as CIV__API_KEYservice = "example"
[secret.LEGACY_API_KEY]from_key = "secret.API_KEY" # value copied from API_KEYnamespace = "" # injected as plain LEGACY_API_KEY[lifecycle] Section
Section titled “[lifecycle] Section”Policy configuration for credential lifecycle management.
| Field | Type | Default | Description |
| -------------------- | --------- | ------- | ---------------------------------------------- |
| stale_warning_days | number | 90 | Days since creation to consider a secret stale |
| require_expiration | boolean | false | Require expires on all secrets |
| require_service | boolean | false | Require service on all secrets |
[callbacks] Section
Section titled “[callbacks] Section”Automation callbacks for lifecycle events.
| Field | Type | Description |
| --------------- | -------- | -------------------------------------------- |
| on_expiring | string | Command or webhook when secrets are expiring |
| on_expired | string | Command or webhook when secrets have expired |
| on_audit_fail | string | Command or webhook on audit failure |
[tools] Section
Section titled “[tools] Section”Tool integration configuration. Open namespace for third-party extensions.
[tools]fnox = truemcp = true