Secrets and Handles
Touba does not place sensitive values in the .tb file, AIR, manifest, or traces.
A secret is referenced by a handle.
tool SummarizeDatasets
takes search as DatasetSearchResult
gives DatasetBrief
requires network, secret_read
secrets OPENAI_API_KEY
Explicit Secrets File
Four things must be distinguished:
| Element | Role |
|---|---|
| Handle | logical name used by Touba, for example OPENAI_API_KEY |
| Resolution file | profile passed to --secrets, for example touba.secrets.dev.json or touba.secrets.prod.json |
| Source | where the value is looked up: touba_store, env, or dotenv |
| Value | real secret, never stored in .tb, AIR, manifest, or trace |
A resolution file can contain several handles, and each handle can choose its own source.
{
"secrets_version": "touba-secrets-v1",
"secrets": {
"OPENAI_API_KEY": {
"source": "env",
"name": "OPENAI_API_KEY"
}
}
}
The file tells the runtime how to resolve the handle. The same Touba program can use several resolution profiles:
touba.secrets.dev.json
touba.secrets.prod.json
Touba does not guess whether a run is development or production. The profile is the file explicitly passed to the runtime.
Common example:
touba.secrets.dev.json -> looks up values in touba_store
touba.secrets.prod.json -> looks up values in env
This is not mandatory: a profile can mix several sources if the project needs it. The stable point is that the resolution file explicitly declares where each key is looked up.
In a standard project:
touba initcreates empty.touba/secrets.local.jsonand.envfiles, then ignores them through.gitignore;touba prepare --mode writecreates or completestouba.secrets.dev.jsonandtouba.secrets.prod.jsonwhentools declare secrets;touba secret set <HANDLE> --value-stdinadds the value to the localtouba_store.
None of these files gives the runtime the right to read a secret by automatic discovery. The runtime reads only the file passed to --secrets.
Supported Sources
touba_store
Recommended for local development.
{
"source": "touba_store",
"path": ".touba/secrets.local.json",
"name": "OPENAI_API_KEY"
}
The local store is managed through Touba commands:
touba secret set OPENAI_API_KEY --value-stdin
touba secret list
touba secret check OPENAI_API_KEY
The value is supplied through stdin, from the local mechanism chosen by the developer. Commands list handles, never values.
A project initialized with touba init ignores .touba/ by default. The local store must not be committed.
env
Recommended for CI/CD, containers, and infrastructure.
{
"source": "env",
"name": "OPENAI_API_KEY"
}
dotenv
Supported for explicit local compatibility.
{
"source": "dotenv",
"path": ".env",
"name": "OPENAI_API_KEY"
}
The runtime does not automatically read a .env file. The path must be declared explicitly.
Handle Lifecycle
A secrets profile can also disable or expire a handle without changing Touba source or the manifest.
{
"secrets_version": "touba-secrets-v1",
"secrets": {
"OPENAI_API_KEY": {
"source": "touba_store",
"path": ".touba/secrets.local.json",
"name": "OPENAI_API_KEY",
"status": "active",
"expires_at": "2026-06-30T23:59:59.000Z"
}
}
}
Rules:
statusis optional and defaults toactive;status: "revoked"refuses execution withSecretHandleRevoked;expires_atis optional; if the date has passed, the runtime refuses withSecretHandleExpired;- traces identify the refused handle and a short reason, never the value.
This lifecycle makes a key unusable before the handler. External vaults, automatic rotation, and organizational policy remain surrounding secret-management layers.
Manifest
The manifest must grant the handle to the tool binding:
"secrets": ["OPENAI_API_KEY"]
If the tool declares a secret and the manifest does not grant it, the runtime refuses before the handler.
Agent Scope
When a tool is called during agent execution, the manifest can limit secrets by agent.
touba prepare fills this block for agents that can reach a tool declaring a
secret; review it as explicit authority before execution.
"agent_secret_scopes": {
"agent:examples/Researcher": ["OPENAI_API_KEY"]
}
This means the handle can be used within that agentic scope. It does not give the secret value to the agent as text.
Handler Injection
The runtime launches the handler with a minimal environment containing only the required and authorized secrets.
The handler sees the value at execution time. AIR and trace see only the handle.
Secret Contract
Tool results and decision responses containing a resolved secret value are refused before propagation to callers, model observations or CLI/SDK output. The check covers substrings, nested fields and keys. It does not silently rewrite a typed business value. Diagnostics remain redacted.
This refusal occurs after any external effect. An acquired effect keeps its receipt in the journal, without the sensitive result; resuming does not repeat that effect to recover the result.
Checkpoints contain business data needed for resumption. A minimized trace does
not make its checkpoint free of personal data. CLI checkpoint files and resume
stores use private permissions (0600 on POSIX), not encryption. Restrict access,
backups and retention; remove files when no longer needed. Detection covers
known resolved secrets, not every transformation or unknown sensitive value.
Touba provides explicit secret handles, explicit resolution profiles, local development storage, environment-based resolution, lifecycle status, and runtime refusal before handler dispatch.
External secret-manager backends, cryptographic vault properties, automatic
.env discovery, automatic sensitive-data classification, and complete
containment of authorized handlers connect around this explicit contract.