Config and secrets
Who am I
sklp whoami answers in one call what an operator or an AI agent needs
before acting: API login, projects, deploy contexts, stacks and their config
keys. Run it first.
sklp whoami
sklp whoami --jsonReference: sklp whoami.
Authentication
sklp auth manages the CLI's token for the Skalpai API. Logging out removes
the token, keeps the URL and leaves deploy contexts untouched: API login and
deploy targets are separate.
sklp auth login --api-url https://api.skalpai.dev
sklp auth status
sklp auth logoutsklp project list lists the projects you can reach (--stack, --json,
--plain). Commands that act on a project take --project, or read
SKLP_PROJECT.
The CLI's own settings live in ~/.config/sklp/config.yaml, or in the file
SKLP_CONFIG points at.
Stack config
Each stack keeps its configuration in .sklp/<stack>/config.yaml: plain
values and encrypted secrets side by side. Secrets are AES-256-GCM, keyed by
a passphrase, so the file is committable and useless without it. Deploy
resolves ${VAR} references from it.
encryptionsalt: QHULMrEI25dNPdMnoC8y8A==
encryptioniters: 600000
config:
EMAIL_FROM: noreply@example.com
S3_ACCESS_KEY:
secure: v1:...
MISTRAL_MODEL: mistral-large-latest| Command | Effect |
|---|---|
sklp config ls | list keys, secrets shown as <secret> |
sklp config get KEY [--show] | print a value; --show decrypts a secret |
sklp config set KEY VALUE [--secret] | set a value; --secret stores it as secure: |
sklp config rm KEY | remove a key |
sklp config import FILE [--secret] | bulk-import a dotenv file; --secret encrypts every value |
sklp config rotate | re-seal every secret under a new passphrase and salt |
Every verb takes --stack (default prod):
sklp config set --stack web EMAIL_FROM noreply@example.com
sklp config set --stack web --secret RESEND_API_KEY re_xxx
sklp config get --stack web RESEND_API_KEY --show
sklp config import --stack web --secret .env.prodset rewrites the whole file in its canonical layout, so a large first diff
is expected. Reference: sklp config.
The passphrase
sklp resolves the passphrase in this order:
| Order | Source | Set with |
|---|---|---|
| 1 | SKLP_SECRETS_PASSPHRASE env var | export (CI runners, relayed VMs) |
| 2 | a lookup command | sklp config passphrase command '<cmd>' |
| 3 | the OS vault (macOS keychain, libsecret) | sklp config passphrase set |
The command is stored in secrets.passphrase_command of the CLI config; it
must print the passphrase on stdout, and {repo} in it is replaced by the
repo key. It is run once when you set it, so a broken command fails now, not
inside a pipeline. An empty argument clears it.
sklp config passphrase set
sklp config passphrase command 'pass show sklp/{repo}'
sklp config passphrase status # source + whether it decrypts each file
sklp config passphrase unsetstatus names the source and the verdict per config file, never the value.
A pipeline that asks for no secret runs without any passphrase.
Project secrets in core
sklp secret syncs a project's secrets between core and a local dotenv file
(default .env.secret). Core never returns plaintext in a listing: only the
name, the last four characters and whether deploy may read it.
sklp secret list --project <id>
sklp secret push .env.secret --dry-run
sklp secret push .env.secret # deploy-readable by default
sklp secret pull # into .env.secret
sklp secret pull other.env --force # another filename needs --force
sklp secret delete --project <id> OLD_KEYOnly deploy-readable secrets come back on pull. Reference:
sklp secret.
Registry credentials
sklp registry login is the only way a push credential reaches sklp. sklp
never reads ~/.docker/config.json: a credential this verb did not write does
not exist, so a stale docker login cannot authenticate a push behind its back.
sklp registry login --provider scaleway --password-stdin < key.txt
sklp registry login ghcr.io --username me --credential-command 'pass show ghcr'
sklp registry ls # host, username, secret source; never the secret
sklp registry logout ghcr.io--provider (docker-hub, github, scaleway) pre-fills host and username.
--credential-command stores a lookup command instead of the password.
Pull credentials for nodes belong in the registries: block of a
deploy.yaml, as ${VAR} references.
Rules
- Never commit a secret value. Secrets go through
config set --secret,secret pushor a vault;config.yamlholds onlysecure:ciphertext. - Never write a literal password in a deploy.yaml. Use
${VAR}, resolved from the stack config. - Never print a secret to check it. Use
config passphrase statusorregistry ls, which report sources and verdicts. - Rotate with
config rotate, then share the new passphrase through the vault, not a chat.