Skip to main content
Version: 1.0.0

Secrets and Handles

Touba does not place sensitive values in the .tb file, AIR, manifest, or traces.

A secret is referenced by a handle.

source.tb
tool SummarizeDatasets
takes search as DatasetSearchResult
gives DatasetBrief
requires network, secret_read
secrets OPENAI_API_KEY

Explicit Secrets File​

Four things must be distinguished:

ElementRole
Handlelogical name used by Touba, for example OPENAI_API_KEY
Resolution fileprofile passed to --secrets, for example touba.secrets.dev.json or touba.secrets.prod.json
Sourcewhere the value is looked up: touba_store, env, or dotenv
Valuereal secret, never stored in .tb, AIR, manifest, or trace

A resolution file can contain several handles, and each handle can choose its own source.

touba.secrets.dev.json
{
"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:

Structure
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:

Output
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 init creates empty .touba/secrets.local.json and .env files, then ignores them through .gitignore;
  • touba prepare --mode write creates or completes touba.secrets.dev.json and touba.secrets.prod.json when tools declare secrets;
  • touba secret set <HANDLE> --value-stdin adds the value to the local touba_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.

touba.secrets.dev.json
{
"source": "touba_store",
"path": ".touba/secrets.local.json",
"name": "OPENAI_API_KEY"
}

The local store is managed through Touba commands:

Terminal
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.

touba.secrets.prod.json
{
"source": "env",
"name": "OPENAI_API_KEY"
}

dotenv​

Supported for explicit local compatibility.

touba.secrets.dev.json
{
"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.

touba.secrets.dev.json
{
"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:

  • status is optional and defaults to active;
  • status: "revoked" refuses execution with SecretHandleRevoked;
  • expires_at is optional; if the date has passed, the runtime refuses with SecretHandleExpired;
  • 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:

touba.manifest.json
"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.

touba.manifest.json
"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.