Reference
secrets.json
Structured credential store schema
Gitignored. Managed by TypeClaw under the env-wins / file-never-auto-mutated policy (/concepts/secrets-policy).
{
"version": 2,
"providers": {
"fireworks": { "type": "api_key", "key": "fw_xxx" },
"minimax": { "type": "api_key", "key": "sk-cp-xxx" },
"openai": { "type": "api_key", "key": { "env": "MY_CUSTOM_OPENAI_KEY" } },
"anthropic": {
"type": "oauth",
"access_token": "…",
"refresh_token": "…",
"expires_at": 1735776000000
}
},
"channels": {
"slack-bot": {
"botToken": { "value": "xoxb-…" },
"appToken": { "env": "CI_SLACK_APP_TOKEN" }
},
"discord-bot": { "token": "…" },
"telegram-bot": { "token": "…" },
"kakaotalk": {
"currentAccount": "alice@example.com",
"accounts": {
"alice@example.com": {
"oauth_token": "…",
"refresh_token": "…",
"device_uuid": "…",
"email": "alice@example.com",
"encryptedPassword": {
"v": 1,
"alg": "AES-256-GCM",
"kid": "…",
"iv": "…",
"ciphertext": "…",
"authTag": "…",
"createdAt": 1735776000000
}
}
}
}
}
}The Secret shape
type Secret = string | { value?: string; env?: string }The string form is shorthand for { value }. The object form lets you bind a credential to a custom env-var name.
Resolution order
For any secret-bearing field:
process.env[secret.env]ifenvis setprocess.env[canonicalEnvName](platform's standard env var)secret.valuefromsecrets.json- Otherwise missing
Providers
type | Fields | Env-wins? |
|---|---|---|
api_key | key: Secret | yes |
oauth | access_token, refresh_token, expires_at, … | no (stateful refresh) |
Channel adapters
| Adapter | Fields |
|---|---|
slack-bot | botToken: Secret, appToken: Secret |
discord-bot | token: Secret |
telegram-bot | token: Secret |
kakaotalk | currentAccount: string | null, accounts: Record<accountId, KakaoAccountRecord> |
KakaoTalk account record
| Field | Type | Notes |
|---|---|---|
oauth_token | string | OAuth access token; rotated by SDK on refresh |
refresh_token | string | OAuth refresh token; rotated on the same cycle |
device_uuid | string | SDK-generated, persisted to skip phone-passcode confirmation on re-login |
email | string | typeclaw-only; renewal cron uses it for attemptLogin |
encryptedPassword | EncryptedBlob | typeclaw-only; AES-256-GCM envelope, key at ~/.typeclaw/keys/<containerName>.key |
| (other SDK fields) | catchall-passthrough for upstream-controlled fields |
Encrypted blob envelope
type EncryptedBlob = {
v: 1
alg: 'AES-256-GCM'
kid: string // key id, matches the on-disk key filename
iv: string // base64
ciphertext: string // base64
authTag: string // base64
createdAt: number // epoch ms
}AAD is typeclaw:kakaotalk-password:v1:<containerName>:<accountId>, so ciphertext copied across accounts or containers fails authentication on decrypt.
Legacy shapes
Only the v2 envelope is accepted. The v1 envelope, pre-envelope flat shape, and auth.json filename are no longer supported — parseSecretsFile rejects them with an error. If you have an old file in one of these shapes, rewrite it to the v2 format shown above before booting.