Documentation
Secret Management
0trace uses an opaque handle model: agents and skills never receive raw credential values. The real key is injected at the network layer for a fraction of a second and then discarded — it never appears in logs, LLM conversations, or memory.
The Opaque Handle Model
When you store a credential in 0trace, you type the key once. From that point on, every
part of the system — the agent, the skill, the LLM — only ever sees a placeholder like
zt:cred:a1b2c3d4.... This placeholder is meaningless without the running
0trace runtime authenticating it.
0trace stores it in the encrypted vault, then zeros out the in-memory copy.
Every part of the system — skill code, LLM calls, logs — only sees zt:cred:a1b2c3d4....
When a skill calls http.post_authenticated, 0trace fetches the raw key,
uses it to authenticate the request, and discards it. The skill never sees it.
Every credential operation — read, use, rotation — is written to the tamper-evident audit log with a timestamp, run ID, and agent ID.
What gets stolen if the host is compromised
Traditional credential storage
Attacker reads ~/.config/credentials.json or environment variables and
finds raw API keys in plaintext. Keys are immediately usable from anywhere.
0trace opaque handles
Attacker finds placeholder codes like zt:cred:a1b2c3d4. These are
inert without the running 0trace runtime, valid authentication, and the specific
service scope the handle was issued for.
Credential Vault
The 0trace vault uses XChaCha20-Poly1305 symmetric encryption for credentials at rest. The vault key itself is derived from a master secret stored in the OS keychain (macOS Keychain, Linux Secret Service, or Windows Credential Manager) — it is never written to the filesystem.
Vault properties
- XChaCha20-Poly1305 authenticated encryption — tampering is detectable
- Per-credential encryption keys — compromise of one credential does not expose others
- Keys locked to a specific service scope — a Slack token cannot be used for an Anthropic API call
- Handles expire automatically based on a configurable TTL
- All access is logged in the hash-chained audit trail
- Handles can be revoked immediately without affecting other credentials
Isolation guarantee
Each skill that declares secrets.read can only access handles explicitly
assigned to it by the operator. A skill cannot enumerate available handles, cannot
request handles for other services, and cannot access handles assigned to other skills.
CLI Commands
zt credentials store/rotate/migrate (interactive
key entry at the CLI) are implemented as internal runtime modules but not yet wired into
the zt command dispatcher. Today, credentials are provisioned through the
vault backend configuration (local vault or an external vault — see
External Vault Integrations) and managed at the CLI via
zt secrets, shown below.
Listing handles
zt secrets list
Handle ID Provider Name Created Expires
──────────────────────────────────────────────────────────────────────
zt:cred:a1b2c3d4 anthropic api_key 2025-01-15 never
zt:cred:e5f6a7b8 slack bot_token 2025-01-20 never
zt:cred:c9d0e1f2 my-service db_password 2025-01-22 2026-01-22 Rotating a credential handle
zt secrets rotate zt:cred:a1b2c3d4
# Triggers rotation via the configured vault backend
# and writes a credential_rotated audit event Auditing credential access
zt secrets audit
Time Handle Agent Action Run ID
──────────────────────────────────────────────────────────────────────────
2025-01-20T14:32:01 zt:cred:a1b2c3d4 metrics-bot use run_abc
2025-01-20T14:35:22 zt:cred:e5f6a7b8 notifier use run_def
2025-01-21T09:11:04 zt:cred:a1b2c3d4 metrics-bot rotate — Breach reporting
zt secrets breach-report --hours 24
# Exports breach events detected within the given window (default: last 24h) Hot-reloading vault config
zt secrets reload
# Reloads vault backend configuration without a service restart Using Credentials in Skills
Skills access credentials through the secrets.read capability.
The skill receives an opaque handle — never the raw value.
Declaring the capability
## Capabilities
- secrets.read
- net.egress:https://api.example.com
- net.dns Getting a handle
## Execution
let handle = host.call("secrets.get", "my-api-key");
// handle = "zt:cred:a1b2c3d4..." — opaque, not the real key Making authenticated requests
Pass the handle to http.post_authenticated. The runtime injects the real
credential at the network layer — the skill code never sees the raw value.
let result = host.call(
"http.post_authenticated",
"https://api.example.com/v1/data",
handle,
{"query": input.query}
); http.post_authenticated to keep the credential at the network layer.
Token exchange
For services that use short-lived tokens (AWS STS, OAuth 2.0), declare
secrets.token.exchange and call secrets.exchange. This
exchanges the long-lived handle for a short-lived ephemeral handle scoped to a
single operation.
## Capabilities
- secrets.read
- secrets.token.exchange
- net.egress:https://sts.amazonaws.com
## Execution
let static_handle = host.call("secrets.get", "aws-access-key");
let ephemeral_handle = host.call("secrets.exchange", static_handle, {
role_arn: "arn:aws:iam::123456789012:role/my-role",
duration_s: 900
});
// ephemeral_handle expires in 15 minutes automatically External Vault Integrations
0trace can delegate credential storage to an external vault. The 0trace opaque handle model is preserved — skills still receive handles, not raw values. The vault backend is the source of truth.
HashiCorp Vault
Configure 0trace to use HashiCorp Vault as the credential backend:
vault:
provider: hashicorp
address: https://vault.example.com
auth_method: approle # or: token, kubernetes, aws
role_id: "your-role-id"
secret_id_handle: zt:cred:vault-secret-id
kv_mount: secret
kv_path_prefix: 0trace/ Once configured, credentials are provisioned to Vault instead of the local vault. Skills continue to use secrets.get with the same handle syntax — the backend is transparent. zt secrets reload hot-reloads this configuration without a service restart.
AWS Secrets Manager
vault:
provider: aws_secrets_manager
region: us-east-1
auth_method: iam_role # or: access_key
kms_key_id: arn:aws:kms:... # Optional: customer-managed KMS key
secret_prefix: "0trace/" IAM role authentication is recommended. 0trace calls GetSecretValue at execution time and never caches the raw value beyond the duration of the network call.
Azure Key Vault
vault:
provider: azure_key_vault
vault_url: https://my-vault.vault.azure.net
auth_method: managed_identity # or: client_secret, certificate Precedence
If an external vault is configured, it takes precedence over the local vault for all credential reads. Credentials stored locally before configuring an external vault can be migrated with:
zt credentials migrate --to hashicorp-vault zt credentials migrate is planned but not yet wired into the CLI dispatcher.
Key Rotation
Manual rotation
zt secrets rotate zt:cred:a1b2c3d4 The old handle remains valid for a configurable grace period (default: 0 seconds), giving in-flight runs time to complete before the old key is invalidated.
Scheduled rotation
Configure automatic rotation for credentials that support it:
credentials:
anthropic/api_key:
rotation:
enabled: true
interval_days: 90
notify_channel: slack # Notify on rotation success/failure Emergency revocation
If a credential is suspected to be compromised:
# 1. Rotate the handle immediately
zt secrets rotate zt:cred:a1b2c3d4
# 2. Pull recent breach signal for this handle
zt secrets breach-report --hours 24
# 3. Export audit evidence for the incident
zt audit export run_abc123 --output incident-evidence.json Audit Trail
Every credential operation is written to the hash-chained audit log. The audit trail is export-ready for SOC 2 and ISO 27001 compliance reviews.
Credential audit event types
| Event | Description |
|---|---|
credential_stored | New credential stored in vault |
credential_accessed | Handle resolved to raw credential (at network layer) |
credential_rotated | Credential replaced with new value; old version archived |
credential_revoked | Handle invalidated; further use denied |
credential_expired | Handle TTL elapsed; auto-revoked |
token_exchanged | Long-lived handle exchanged for ephemeral token |
credential_denied | Skill attempted to access handle it was not assigned |
Exporting for compliance
# Review credential access events
zt secrets audit
# Export breach events from a given window
zt secrets breach-report --hours 720 # last 30 days
# Export the full audit bundle for a specific run (includes all events)
zt audit export run_abc123 --output audit-bundle.json Audit bundles include the full hash chain so the integrity of the log can be independently verified without access to the 0trace runtime.