> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tinycloud.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets, Vault, and Variables

> Manage encrypted secrets, encrypted vault data, and plaintext variables

Use this page when you need to pick the right storage layer for sensitive or non-sensitive configuration.

## Choose the layer

| Layer | Command | Best for |
| - | - | - |
| Encrypted secrets | `tc secrets` | API keys, passwords, tokens |
| Encrypted vault data | `tc vault` | Low-level encrypted key paths |
| Plaintext variables | `tc vars` | URLs, feature flags, log levels |

## `tc secrets`

```bash theme={null}
tc secrets network init
tc secrets network show
tc secrets doctor
tc secrets put STRIPE_KEY "sk_live_..."
tc secrets get STRIPE_KEY
tc secrets list
tc secrets delete STRIPE_KEY
tc secrets manage
```

`tc secrets` stores values in the literal `secrets` space by default and supports logical scopes with `--scope`.

```bash theme={null}
tc secrets put DATABASE_URL "postgres://..." --scope prod
tc secrets get DATABASE_URL --scope prod
tc secrets list --scope prod
```

You can also target another owned space with `--space`.

### Read and write options

| Command | Flags |
| - | - |
| `get <name>` | `--raw` or `--value-only` prints only the value; `-o, --output <file>` writes it to an owner-only (0600) file atomically; `--delegation <source>` reads through a delegation file or imported profile |
| `put <name> [value]` | `--file <path>` or `--stdin` keeps the value out of shell history |
| `doctor [name]` | `--scope`, `--network` (default `default`) |
| `network grant <did> [name]` | Grants another DID decrypt on the network |

`tc secrets manage` opens Secret Manager at `https://secrets.tinycloud.xyz`.

### A secret that does not exist yet

`tc secrets get` on a missing name exits `4` with `NOT_FOUND`. The hint is a
Secret Manager link for that name, scope, and space, so the owner can add the
value in the browser without it passing through the terminal or an agent.
CLI 1.1.0 beta links straight to the add form with the name filled in.

## Give an agent read access to a secret

An agent reads named secrets through its own profile, with a scoped OpenKey
login that the owner approves. The manifest names exactly the secrets the agent
may read:

```bash theme={null}
cat > agent-secrets.json <<'JSON'
{ "app_id": "my.agent", "name": "My agent", "space": "secrets", "secrets": { "OPENAI_API_KEY": true } }
JSON
tc init --name agent-secrets --key-only
tc --profile agent-secrets auth login --method openkey --paste \
  --manifest agent-secrets.json \
  --owner did:pkh:eip155:1:0xOWNER_ADDRESS --expiry 7d
# Send the owner the approval URL printed on stderr, then paste back their code.
tc --profile agent-secrets secrets get OPENAI_API_KEY --raw
```

* `secrets: { NAME: true }` requests `kv/get` on that one secret, `capabilities/read`
  on the `secrets` space, and decrypt on the owner's default secrets network.
* `--owner` is the `did:pkh` of the account that will approve. The secrets
  network belongs to the owner, so a fresh profile needs it; without it the
  login fails with `OWNER_DID_UNKNOWN`.
* Device login (`--device`) cannot grant secrets. Use `--paste` or the browser
  flow.
* Run headless without a grant for the name, a secrets command fails fast with
  `PERMISSION_DENIED` (exit `5`). With a missing or expired session it fails
  with `AUTH_REQUIRED` (exit `3`) and names the scoped login to run.

From the SDK, `secrets.listAll()` returns every secret name the session can
see, global and scoped, as `{ name, scope? }` entries. It never returns values.

## Match an app manifest

An app manifest's `secrets` field and `tc secrets` address the same encrypted
vault entries when their names and scopes match:

| Manifest declaration | CLI command | Backing path in the `secrets` space |
| - | - | - |
| `"API_KEY": ["read"]` | `tc secrets put API_KEY "..."` | `vault/secrets/API_KEY` |
| `"API_KEY": { "scope": "my-app", "actions": ["read"] }` | `tc secrets put API_KEY "..." --scope my-app` | `vault/secrets/scoped/my-app/API_KEY` |

A scoped secret is a separate entry from a global secret with the same name;
TinyCloud does not fall back from one to the other. The manifest declares the
access an app requests during sign-in, while the CLI or SDK writes the value.

See the [complete app manifest and resolved path mapping](/reference/protocol/app-manifests#complete-runtime-app-manifest)
for a copyable browser-app example.

## `tc vault`

`tc vault` is the lower-level encrypted KV layer. It requires a private key.

```bash theme={null}
tc vault unlock --private-key 0x...
tc vault put my-app/api-key "sk_live_..."
tc vault get my-app/api-key
tc vault list
tc vault head my-app/api-key
tc vault delete my-app/api-key
```

## `tc vars`

`tc vars` stores plaintext configuration in the `variables/` prefix and also requires a private key.

```bash theme={null}
tc vars put API_BASE_URL "https://api.example.com"
tc vars get API_BASE_URL
tc vars list
tc vars delete API_BASE_URL
```

## Private keys

Use `TC_PRIVATE_KEY` or `--private-key` for `vault` and `vars`. `secrets` can use the active authenticated profile, but it also accepts a private key override.

<Note>
  The CLI source treats `tc secrets network init` as the way to create or reuse the default secrets encryption network, and `tc secrets doctor` as the quickest access check.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.