Write-only secrets
This page explains write-only secrets in sMind by Spacing Mind: how a provider key is stored and referenced, what you can see afterwards (a set flag and a short fingerprint), where it is used and what it does not protect against. It is for people who add keys to provider instances.
sMind by Spacing Mind, version 0.17.0. This page describes the 0.17.0 release.
A provider instance that talks to another vendor needs a key. smind stores that key for you and lets you set, replace or clear it, but never shows it again: the store is write-only.
Set, replace and clear a key
In Settings → Providers, open the instance. The Keys card lists each key as Set · ••••abcd or Not set. The four characters are the end of a fingerprint (a hash of the key), not of the key: enough to see that a key changed, not enough to use it.
- Replace key opens a password dialog. The field is emptied as soon as you submit.
- Clear key asks for confirmation, then removes the stored value.
Only a person can do this. Agents and plugins are refused, and no call returns a stored value. When you add an instance with Add from recipe, the key you paste is stored the same way.
Reference a key from config.yaml
An instance's env can reference a stored key by name. The key itself never goes in the file:
providers:
custom:
- id: zai
extends: claude-native
env:
ANTHROPIC_BASE_URL: https://api.z.ai/api/anthropic
ANTHROPIC_AUTH_TOKEN: {secret: zai-key}An env value is one of a plain literal, {secret: <name>} (a reference to a stored key) or {passthrough: true} (copy the variable from the daemon's own environment at launch, for keys you export outside smind). A variable whose name marks it as a key (for example ANTHROPIC_AUTH_TOKEN or OPENAI_API_KEY) must be a reference or a passthrough: a key written inline is rejected, naming the field. The one exception is ANTHROPIC_API_KEY, which accepts an empty value where a vendor needs the variable set but empty. Each launch type allows only certain variable names; the list is in Providers.
Where the value lives and when it is used
Values are kept in smind.db, with the same protection as account credentials. A key is resolved only when a run launches, and goes into that child process's environment. Deleting an instance from config.yaml and reloading providers (or restarting smind) removes its stored keys.
What is protected
A stored key never appears in config.yaml, in a command line, in logs, in events, in the provider list, in error text or in anything sent over a relay.
What is not protected
The agent's own shell can read its environment. By default Claude Code does not hide the token from its Bash tool. For Claude Code instances that hold a key, smind adds best-effort deny rules for the obvious ways to print it (env, printenv, set, export -p, declare -x, echo $NAME, and reading /proc/*/environ or the provider folder under SMIND_HOME). These are pattern matches and are easily bypassed; they raise the cost of a careless prompt injection and do not stop a determined one. Codex and other agents have no equivalent, because their shell tools inherit the environment.
So: use a narrowly scoped key with a spend limit, and for Codex or other vendors put a local gateway (for example LiteLLM) in front, so the agent holds only a throwaway token.
smind does not turn on Claude Code's own environment scrubbing by default, because with it on Claude Code forces the permission mode back to default, which conflicts with smind's permission modes. You may opt in per instance with CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: "1" in the instance env if you accept that.