▸ Agent Skills
4 min read

Secret Generation

Automatically generating passwords, tokens, and keys for missing secrets

New in version 0.7

Secrets can be declared with type and generate to be auto-generated when missing. This is useful for passwords, tokens, and keys that do not need to be shared across developers.

Basic Usage

[profiles.default]
DB_PASSWORD = { description = "Database password", type = "password", generate = true }
API_TOKEN = { description = "API token", type = "hex", generate = { bytes = 32 } }
SESSION_KEY = { description = "Session key", type = "base64", generate = { bytes = 64 } }
REQUEST_ID = { description = "Request ID prefix", type = "uuid", generate = true }

Generation Types

TypeDefault OutputOptions
password32 alphanumeric charslength (int), charset ("alphanumeric" or "ascii")
hex64 hex chars (32 bytes)bytes (int)
base6444 chars (32 bytes)bytes (int)
uuidUUID v4 (36 chars)none
commandstdout of command; exact bytes in 0.21+command (string, required)
rsa_private_key2048-bit RSA private key (PKCS1 PEM)bits (int)
openpgp_private_key (0.21+)ASCII-armored OpenPGP transferable secret keyuser_id (required), algorithm ("ed25519" or "rsa"), bits (RSA only), capabilities (["sign"], ["encrypt"], or both)
ssh_private_key (0.21+)Unencrypted OpenSSH Ed25519 private keyalgorithm ("ed25519" or "rsa"), bits (RSA only), comment (string)

Command type

Changed in version 0.21

Command output is preserved byte-for-byte, including non-UTF-8 data, NULs, whitespace, and final newlines. Output that is empty or contains only whitespace is rejected. Use printf or trim inside your command if you need a value without a final newline. Binary output needs a byte-capable provider or manifest encoding.

The command type runs a shell command and uses its stdout as the generated value:

MONGO_KEY = { description = "MongoDB keyfile", type = "command", generate = { command = "openssl rand -base64 765" } }

command requires generate = { command = "..." } rather than just generate = true.

OpenPGP private keys

New in version 0.21

openpgp_private_key generates a GnuPG-compatible OpenPGP v4 key entirely in process; neither gpg nor another executable is required. Its modern default uses an Ed25519 certification-only primary key and puts routine operations on separate Ed25519 signing and Curve25519 encryption subkeys.

The User ID is required. With no capabilities, SecretSpec creates both signing and encryption subkeys:

[profiles.default]
GENERAL_KEY = { description = "Service OpenPGP key", type = "openpgp_private_key", generate = { user_id = "Service Bot <[email protected]>" } }


# A signing-only key has no encryption subkey.
RELEASE_KEY = { description = "Release signing key", type = "openpgp_private_key", generate = { user_id = "Release Bot <[email protected]>", capabilities = ["sign"] } }


# RSA is available for consumers that require it; 3072 bits is the default.
LEGACY_KEY = { description = "Legacy-compatible OpenPGP key", type = "openpgp_private_key", generate = { user_id = "Legacy Bot <[email protected]>", algorithm = "rsa", bits = 4096 } }

capabilities must be a non-empty list containing "sign", "encrypt", or both without duplicates. algorithm defaults to "ed25519". Selecting "rsa" uses RSA for the primary key and every requested subkey; bits defaults to 3072 and accepts values from 2048 through 8192. bits is invalid with "ed25519".

The result is one -----BEGIN PGP PRIVATE KEY BLOCK----- value that can be imported by GnuPG and other OpenPGP tools. It has no OpenPGP passphrase and no expiration; protect it with an encrypted provider and rotate it according to the consuming system’s policy. Set as_path = true when a command needs a temporary key file rather than the armored value in an environment variable.

SSH private keys

New in version 0.21

ssh_private_key generates an unencrypted OpenSSH private key entirely in process. generate = true uses Ed25519, the sensible default for new SSH keys:

[profiles.default]
DEPLOY_KEY = { description = "Deployment SSH key", type = "ssh_private_key", generate = true }


# RSA is available for compatibility; 3072 bits is the default.
LEGACY_DEPLOY_KEY = { description = "Legacy deployment key", type = "ssh_private_key", generate = { algorithm = "rsa", bits = 4096, comment = "[email protected]" } }

RSA sizes from 2048 through 8192 bits are accepted. bits is invalid with Ed25519. comment is optional and cannot contain control characters. Generated keys are not passphrase-encrypted, so store them in an encrypted provider. Set as_path = true when a command needs the key in a temporary file rather than in an environment variable.

How it works

  • Generation only triggers when a secret is missing. Existing secrets are never overwritten.
  • Generated values are stored via the secret’s configured provider (or the default provider).
  • Subsequent runs find the stored value and skip generation (idempotent).
  • The null provider (0.19+) instead returns a fresh generated value for only the current resolution.
  • generate and default cannot both be set on the same secret.
  • Setting type without generate is informational only and does not trigger auto-generation.

Ephemeral generation with null

New in version 0.19

Use providers = ["null"] when the value should be generated on demand and never written to provider storage:

[profiles.default]
SESSION_SECRET = { description = "Per-run session secret", type = "base64", generate = { bytes = 32 }, providers = ["null"] }

One materializing resolution receives one value. The next run, get, check, or SDK value-carrying resolution receives a new one. Value-free reports describe the value as generated without minting it. Use a writable provider instead when another process or later invocation must retrieve the same value.

Example

[profiles.default]
# Auto-generated on first run, reused after that
DB_PASSWORD = { description = "Database password", type = "password", generate = true }


# Custom length and character set
ADMIN_PASSWORD = { description = "Admin password", type = "password", generate = { length = 64, charset = "ascii" } }


# 64-byte key encoded as base64
ENCRYPTION_KEY = { description = "Encryption key", type = "base64", generate = { bytes = 64 } }


# RSA private key (default 2048-bit)
JWT_SIGNING_KEY = { description = "JWT signing key", type = "rsa_private_key", generate = true }


# RSA private key with custom key size
TLS_KEY = { description = "TLS private key", type = "rsa_private_key", generate = { bits = 4096 } }


# OpenPGP signing key (requires SecretSpec 0.21+)
RELEASE_KEY = { description = "Release signing key", type = "openpgp_private_key", generate = { user_id = "Release Bot <[email protected]>", capabilities = ["sign"] } }


# OpenSSH Ed25519 private key (requires SecretSpec 0.21+)
DEPLOY_KEY = { description = "Deployment SSH key", type = "ssh_private_key", generate = true }


# Informational type only, no generation
EXTERNAL_API_KEY = { description = "Provided by vendor", type = "password" }

See the configuration reference for the full specification.


Last updated Oct 11, 2026