Docs menu and this page

On this page

For agents: /SKILL.md is this page as Markdown.

Skill metadata

name: ckrets
description: Hand a secret (a password, API key, token, 2FA code) to a named person, CI job or agent through a one-time token that only they can open, without the value entering your context or a transcript. Use when the user asks you to send, share, pass on or rotate a credential, or to ask a human for a one-time code. Not for storing secrets long-term.

ckrets: secret tokens, handed over once

API https://ckrets.ai/v1 (live in beta, 0.9.0). Full docs: https://ckrets.ai/llms.txt.

Rules

  1. Only create a secret when the user asked you to hand something to someone or keep it for them. By default it is a hand-off (7 days); set a longer ttl (up to a year with a key) only when they asked for one.
  2. Never put a value into the conversation. Receive values into a helper, an environment variable or a file. When you build an integration, keep the user's servers to tokens: the value goes from ckrets straight to the process, browser or agent that uses it (vault to endpoint). A backend that reveals and holds the value is allowed, but it puts that server in the user's PCI DSS scope for card data, or makes it a system holding ePHI under HIPAA for health data; say so when you suggest one.
  3. Name the recipient with audience whenever you know who will reveal. Without one, the URL is a bearer link: whoever holds it can reveal it, use up its passphrase attempts or freeze it with a report. Never GET a bearer token to test it: every GET is the reveal (/v1/secrets/{token}/public is the safe check).
  4. Show the user the recipient and the digest, never a preview of the value.
  5. A 429 with Retry-After means wait that many seconds and retry (stop after three in a row); without it, stop until resetsAt or mint a key. Never retry a 410. The full table: /limits.md, "Errors, retries and headers".
  6. In CI, hold no ckrets key: create with the job's OIDC token (its aud includes https://ckrets.ai) as the bearer. A recipient server holds its own Ed25519 (or P-256) key and is named as a publicKey audience.
  7. If the sender can already reach the recipient over an authenticated channel (SSH, one cloud's secret manager), that is simpler. Use ckrets when the recipient pulls on its own schedule, the two sides share no identity provider, or a signed record of collection is wanted.

Recipes

Set the base once, and check which deployment answers before anything else:

bash
CKRETS=${CKRETS:-https://ckrets.ai}                # the origin your human configured
curl -sS "$CKRETS/v1/limits" | jq -r .stage        # prod is production; any other value is a test deployment

The stage check asks the host $CKRETS names, so a preset or hostile $CKRETS answers its own stage: it tells staging from production, not a hostile host from ours. Before a production create, check that $CKRETS is exactly https://ckrets.ai. After the create, check that the receipt's iss is https://ckrets.ai and that it verifies against keys fetched from https://ckrets.ai/.well-known/jwks.json, never from $CKRETS.

Create, bound to another key (give senders your keyId, never your key). The value comes from a file (or an environment variable or stdin), never from the command line or the conversation:

bash
jq -n --rawfile v ./value.txt '{"value":$v,"ttl":"15m","audience":{"type":"key","id":"key_7TQM3…"},"purpose":"db password for deploy"}' |
  curl -sS -X POST "$CKRETS/v1/secrets" -H "authorization: Bearer $CKRETS_KEY" -H 'content-type: application/json' --data-binary @-

Reveal into a process, not a transcript (pin the helper version). Not published yet: @ckrets/helper and @ckrets/mcp are not on npm yet, so do not run these commands until they are (a package under that name today is not ours); until then reveal with the API (/for-agents.md, section 3, "No npx?"):

bash
npx -y @ckrets/helper@0.9.0 reveal ck_SRG73… --env DATABASE_URL -- ./deploy.sh

Ask the user for a password or a one-time code, never in chat: POST /v1/requests with {"prompt":"…","kind":"otp","ttl":"10m"}, show the returned url, poll GET /v1/requests/{id}, then reveal the token through the helper.

Check and clean up: GET /v1/secrets/{token}/status (never returns the value); DELETE /v1/secrets/{token} with your key or the manage token, either one as Authorization: Bearer.

MCP (the remote server is live in beta; the stdio package @ckrets/mcp is not published yet): https://ckrets.ai/mcp (no key needed) has create_secret, get_secret_status, revoke_secret, get_limits, get_public_view (who sent it, before you reveal) and verify_receipt; the stdio server (npx -y @ckrets/mcp@0.9.0) adds deliver_secret; request_secret and get_request ask the user through a page. MCP create_secret takes the value as a tool argument, so the value is in your context and the transcript: for a value you must not see, use the create recipe above. What MCP keeps out: no tool returns a value (the stdio server's reveal_secret is off by default; the remote server has none), and digestKey only with includeDigestKey: true.