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.

1
You enter the key once.

0trace stores it in the encrypted vault, then zeros out the in-memory copy.

2
Agent receives a handle, not the key.

Every part of the system — skill code, LLM calls, logs — only sees zt:cred:a1b2c3d4....

3
Key is injected invisibly at the network layer.

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.

4
Every access is audited.

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

Planned: 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}
);
Never pass credential handles to LLM prompts or include them in skill outputs. The handle itself is opaque, but leaking it enables a handle-holder (if they also control the runtime) to misuse it. Always use 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

EventDescription
credential_storedNew credential stored in vault
credential_accessedHandle resolved to raw credential (at network layer)
credential_rotatedCredential replaced with new value; old version archived
credential_revokedHandle invalidated; further use denied
credential_expiredHandle TTL elapsed; auto-revoked
token_exchangedLong-lived handle exchanged for ephemeral token
credential_deniedSkill 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.