CLI Commands Reference
The SecretSpec CLI provides commands for managing secrets across different providers and profiles.
Global Options
Section titled “Global Options”These options are available on every command:
| Option | Description |
|---|---|
-f, --file <FILE> | Path to secretspec.toml (default: auto-detect). Env: SECRETSPEC_FILE |
--reason <REASON> | Reason for accessing secrets, recorded by providers that support audit logging (e.g. Proton Pass agent sessions). Takes precedence over PROTON_PASS_AGENT_REASON. Env: SECRETSPEC_REASON |
$ secretspec run --reason "Deploying web frontend" -- ./deploy.shCommands
Section titled “Commands”Initialize a new secretspec.toml configuration file from an existing .env file.
secretspec init [OPTIONS]Options:
--from <PATH>- Path to .env file to import from (default:.env)
Example:
$ secretspec init --from .env.example✓ Created secretspec.toml with 5 secretsconfig init
Section titled “config init”Initialize user configuration interactively.
secretspec config initExample:
$ secretspec config init? Select your preferred provider backend:> keyring: System keychain? Select your default profile:> development✓ Configuration saved to ~/.config/secretspec/config.tomlconfig show
Section titled “config show”Display current configuration.
secretspec config showExample:
$ secretspec config showProvider: keyringProfile: developmentconfig provider add
Section titled “config provider add”Add a provider alias to your user-level configuration (~/.config/secretspec/config.toml).
To share aliases with your team, declare them in a top-level [providers] table in secretspec.toml instead — they take precedence over user-level aliases on name conflict.
secretspec config provider add <ALIAS> <URI> [--credential NAME=PROVIDER]...Arguments:
<ALIAS>- Short name for the provider (e.g.,prod_vault,shared)<URI>- Provider URI (e.g.,onepassword://Production,env://)
Options:
--credential <NAME=PROVIDER>- Declare a provider credential and its source.NAMEis semantic and provider-specific, such asaccess_tokenorrole_id. Repeatable. Only the bare-string source form is expressible on the command line; add arefby editing the config.
Example:
$ secretspec config provider add prod_vault "onepassword://Production"✓ Provider alias 'prod_vault' added: 'onepassword://Production'
$ secretspec config provider add bws "bws://project-uuid" --credential access_token=keyring✓ Provider alias 'bws' added: 'bws://project-uuid' credentials: access_token=keyring run 'secretspec config provider login bws' to store the credentialsconfig provider list
Section titled “config provider list”List all configured user-level provider aliases. Project-level aliases declared in secretspec.toml are not shown by this command.
secretspec config provider listExample:
$ secretspec config provider listprod_vault → onepassword://Productionshared → onepassword://Sharedenv → env://config provider remove
Section titled “config provider remove”Remove a provider alias from your user-level configuration. To remove a project-level alias, edit the [providers] table in secretspec.toml directly.
secretspec config provider remove <ALIAS>Arguments:
<ALIAS>- Name of the alias to remove
Example:
$ secretspec config provider remove prod_vault✓ Provider alias 'prod_vault' removedconfig provider login
Section titled “config provider login”Store the credentials a provider alias declares. Prompts (hidden input) for each credential and writes it to its source provider at the exact location resolution reads it back from. Runs in a project, like set and check.
secretspec config provider login <ALIAS>Arguments:
<ALIAS>- Name of the alias whose credentials to store
Example:
$ secretspec config provider login bwsEnter access_token for provider 'bws' (source: keyring): ****✓ stored access_token in keyring at myproject/default/access_token
Run 'secretspec check --provider bws' to verify authentication.A read-only source provider is rejected. An alias that declares no credentials reports that there is nothing to store.
Check if all required secrets are available, with interactive prompting for missing secrets.
secretspec check [OPTIONS]Options:
-p, --provider <PROVIDER>- Provider backend to use-P, --profile <PROFILE>- Profile to use-n, --no-prompt- Don’t prompt for missing secrets (exit with error if any are missing)--json- Print a value-free resolution report as JSON instead of prompting--explain- Print a value-free, human-readable resolution trace instead of prompting
Example:
$ secretspec check --profile production✓ DATABASE_URL - Database connection string✗ API_KEY - API key for external service (required)Enter value for API_KEY (profile: production): ****✓ Secret 'API_KEY' saved to keyring (profile: production)Resolution report (--json / --explain)
Section titled “Resolution report (--json / --explain)”--json and --explain report how every declared secret resolved for the
active profile without prompting and without ever printing a secret value. Both
exit non-zero when a required secret is missing, so they work as a CI gate.
--explain prints a human-readable trace:
$ secretspec check --profile production --explainprofile: productionprovider: keyring:// DATABASE_URL ok source keyring:// JWT_SECRET ok generated LOG_LEVEL ok default value SENTRY_DSN missing optional STRIPE_KEY MISSING required--json emits a versioned, machine-readable object for tooling and CI. Each
entry reports the status (resolved, missing_required, missing_optional),
whether the value came from a provider (source_provider, credential-free), a
generator (generated), or a committed default (default_applied), and whether
it is exposed as_path. No secret values appear. The canonical JSON Schema is
committed at schema/resolution-report.schema.json.
$ secretspec check --profile production --json{ "schema_version": 1, "provider": "keyring://", "profile": "production", "secrets": [ { "name": "DATABASE_URL", "status": "resolved", "required": true, "source_provider": "keyring://", "default_applied": false, "generated": false, "as_path": false }, { "name": "STRIPE_KEY", "status": "missing_required", "required": true, "default_applied": false, "generated": false, "as_path": false } ]}Get a secret value.
secretspec get [OPTIONS] <NAME>Options:
-p, --provider <PROVIDER>- Provider backend to use-P, --profile <PROFILE>- Profile to use
Example:
$ secretspec get DATABASE_URL --profile productionpostgresql://prod.example.com/mydbschema
Section titled “schema”Emit a single-root JSON Schema for the manifest’s typed shape: by default the
union SecretSpec (safe for any profile); with --profile, that profile’s exact
fields. Value-free: reads only the manifest, never a provider.
secretspec schema [OPTIONS]Options:
-P, --profile <PROFILE>- Emit the schema for this profile’s fields instead of the union-o, --output <FILE>- Write to this file instead of stdout
Rather than ship a typed-accessor generator per language, feed this schema to
quicktype, which generates an idiomatic type and
deserializer for any language. Name the type with --top-level. At runtime, hand
the generated deserializer the flat {SECRET_NAME: value} map from the SDK’s
fields() helper:
$ secretspec schema | quicktype -s schema --top-level SecretSpec --lang python -o secrets_gen.pyfrom secretspec import SecretSpecfrom secrets_gen import SecretSpec as Secrets # quicktype-generated, typed
resolved = SecretSpec.builder().with_reason("boot").load()s = Secrets.from_dict(resolved.fields())print(s.database_url) # typed strThe same pattern works in every SDK: Go UnmarshalSecretSpec(resolved.FieldsJSON()),
TypeScript Convert.toSecretSpec(resolved.fieldsJson()), Ruby
SecretSpec.from_dynamic!(resolved.fields).
Set a secret value.
secretspec set [OPTIONS] <NAME> [VALUE]Options:
-p, --provider <PROVIDER>- Provider backend to use-P, --profile <PROFILE>- Profile to use
Example:
$ secretspec set API_KEY sk-1234567890✓ Secret 'API_KEY' saved to keyring (profile: development)Run a command with secrets injected as environment variables.
secretspec run [OPTIONS] -- <COMMAND>Options:
-p, --provider <PROVIDER>- Provider backend to use-P, --profile <PROFILE>- Profile to use
Examples:
# Run npm with secrets available as environment variables$ secretspec run --profile production -- npm run deploy
# Verify secrets are injected$ secretspec run -- env | grep DATABASE_URLDATABASE_URL=postgresql://localhost/mydbThe --provider override applies to every secret, including those with a
ref field: refs are redirected
to the overriding provider just like convention secrets. This makes it easy to
point refs at fixtures during tests without editing the manifest:
# Resolve every secret, refs included, from a fixtures file$ secretspec run --provider dotenv:.env.fixtures -- cargo testimport
Section titled “import”Import secrets from one provider to another.
secretspec import <FROM_PROVIDER>The destination provider and profile are determined from your configuration. Secrets that already exist in the destination provider will not be overwritten.
Arguments:
<FROM_PROVIDER>- Provider to import from (e.g.,env,dotenv:/path/to/.env)
Example:
# Import from environment variables to your default provider$ secretspec import envImporting secrets from env to keyring (profile: development)...
✓ DATABASE_URL - Database connection string○ API_KEY - API key for external service (already exists in target)✗ REDIS_URL - Redis connection URL (not found in source)
Summary: 1 imported, 1 already exists, 1 not found in source
# Import from a specific .env file$ secretspec import dotenv:/home/user/old-project/.envUse Cases:
- Migrate from .env files to a secure provider like keyring or OnePassword
- Copy secrets between different profiles or projects
- Import existing environment variables into SecretSpec management
Show the local audit log of secret access.
secretspec audit [--project <NAME>] [--action <ACTION>] [-n <N>] [--json]Options:
--project <NAME>- Only show entries for this project--action <ACTION>- Only show entries for this action (get,set,check,run,import)-n, --tail <N>- Show only the last N entries--json- Output raw JSON Lines instead of the formatted summary
The log location is read from your user-global config ([audit] in ~/.config/secretspec/config.toml), defaulting to the per-user state directory.
Example:
$ secretspec audit --action run -n 52026-06-04T18:06:29Z run found ./deploy.sh API_KEY,DATABASE_URL (my-app/production) reason: deploy [claude-code]
# Pipe raw entries to jq$ secretspec audit --json | jq 'select(.outcome == "missing")'Environment Variables
Section titled “Environment Variables”| Variable | Description |
|---|---|
SECRETSPEC_PROFILE | Default profile to use |
SECRETSPEC_PROVIDER | Default provider to use |
SECRETSPEC_FILE | Path to secretspec.toml (same as --file) |
SECRETSPEC_REASON | Reason for accessing secrets (same as --reason) |
Quick Start Workflow
Section titled “Quick Start Workflow”# Initialize from existing .env$ secretspec init --from .env
# Set up user configuration$ secretspec config init
# Import existing secrets (optional)$ secretspec import env # or: secretspec import dotenv:.env.old
# Check and set missing secrets$ secretspec check
# Run your application$ secretspec run -- npm start