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

# Secrets

> Per-workspace key/value secrets that back {{secret:KEY}} placeholders in chatbot endpoint config.

A **secret** is a named value stored on the [workspace](/concepts/workspace) that ish substitutes into an outgoing request at dispatch time. The reason it exists is the chatbot modality: when a study points at a chatbot endpoint, ish makes the HTTP call itself, and the call usually needs an API key in a header. You do not want that key sitting in the endpoint config as plain text. You store it once as a secret, reference it by name, and ish resolves it on the wire.

This is the mental model and the why. For the exact flags, see the [`ish secret` reference](/cli/generated/secret).

## What a secret is

Each secret is a key, a write-only value, and a little metadata: an optional description, a scope, and timestamps. The key is the part you reference; the value is the part ish keeps. Keys are uppercase by convention and validate against a strict shape: start with a letter, then letters, digits, and underscores only (for example `GROQ_API_KEY`). Anything else is rejected before the call leaves your machine.

Secrets live on the workspace, alongside [site access](/concepts/site-access), the sources you upload, and the people in your pool. Every study in that workspace can reference them. Configure a key once and every chatbot study you run in that workspace resolves it the same way.

<Note>
  Secrets are not for `interactive`, media, or document studies. ish only renders `{{secret:KEY}}` when it dispatches the request itself, which is the chatbot path. A browser-rendered URL gated behind a wall is a [site access](/concepts/site-access) concern, not a secret one.
</Note>

## How a secret gets used

A chatbot endpoint config can carry placeholders anywhere in the rendered request, most often in a header:

```
Authorization: Bearer {{secret:GROQ_KEY}}
X-API-Key:     {{secret:CUSTOMER_BOT_KEY}}
```

When a study dispatches, the renderer looks up each `{{secret:KEY}}` in the workspace's secret store and substitutes the stored value. The config you commit holds only the placeholder; the value never appears in it.

<Warning>
  A missing key renders as the empty string, not an error. The request still goes out, just without the value, so the bot will most likely answer with a 401. That is the signal that a secret is unset or misspelled. Check the key before you check the bot.
</Warning>

## Values are write-only

You set a value; you never read it back. The backend's list endpoint returns keys and metadata only, and the CLI strips any value-shaped field client-side before printing as a second line of defense. `ish secret list` shows you which keys exist, their type, and their scope. It cannot show you what they hold, by design. To rotate a value, set the key again with the new value; to remove it, delete the key.

This is why the input matters more than the output. Three input modes feed a value in, and you pick exactly one per call (passing two is a usage error, exit 2):

<Columns cols={3}>
  <Card title="Stdin" icon="terminal">
    `--value-stdin` reads from a pipe. Best when the value comes from another process (`gcloud secrets`, `op read`, an env var). The value never lands in your shell history.
  </Card>

  <Card title="File" icon="file-lock">
    `--value-file <path>` reads from disk. Pass `-` as the path to read stdin instead.
  </Card>

  <Card title="Positional" icon="keyboard">
    A bare value on the command line. Convenient, but it lands in shell history. Avoid it in scripts.
  </Card>
</Columns>

<Tip>
  Prefer stdin or a file for any real key, so the secret stays out of your shell history. A bare `-` as the positional value is accepted as shorthand for `--value-stdin`: `printf %s "$KEY" | ish secret set GROQ_API_KEY -`.
</Tip>

## Scope

Every secret carries a scope, set with `--scope` and defaulting to `agent`:

| Scope     | Set with          | Intent                                                                     |
| --------- | ----------------- | -------------------------------------------------------------------------- |
| `agent`   | default           | The secret an autonomous agent reaches for when wiring up a chatbot study. |
| `project` | `--scope project` | A workspace-wide value shared across the project.                          |

Scope is a label on where the secret belongs, not a second gate on top of workspace membership. Pick the one that describes who owns the value. Both resolve into a `{{secret:KEY}}` placeholder the same way.

## Reserved keys belong to site access

Three key families are reserved and cannot be created or deleted as plain secrets: `BASIC_AUTH_*`, `SESSION_COOKIE_*`, and `LOGIN_*` (matched case-insensitively on the prefix). These are the credentials behind [site access](/concepts/site-access), and they are written in pairs (a username with its password, a cookie name with its value) so the backend's pairing rule is never half-satisfied.

Both `ish secret set` and `ish secret delete` reject a reserved key (exit 2, `error_code: "validation_error"`) and point you at `ish workspace site-access` instead. The guard sits on `delete` as well as `set`, so a `secret delete LOGIN_PASSWORD --yes` can never silently drop a live site-access credential. Always manage those through the [site access](/concepts/site-access) surface.

## Secret or inline header?

Not every header value needs to be a secret. The line is sensitivity and how often it changes:

* **Inline it in the endpoint config** when the value is the same across every environment and not sensitive: a vendor name, an API version, a content type.
* **Store it as a secret** when the value is per-workspace, rotates, or should not be committed to a config file: an API key, a bearer token.

## Where to go next

<Columns cols={2}>
  <Card title="Site access" icon="lock" href="/concepts/site-access">
    The reserved-key sibling: credentials for reaching a gated URL in an `interactive` study, written in pairs.
  </Card>

  <Card title="Workspaces" icon="folder-open" href="/concepts/workspace">
    Where secrets live, and what else a workspace holds.
  </Card>

  <Card title="ish secret reference" icon="terminal" href="/cli/generated/secret">
    Every flag for `ish secret list`, `set`, and `delete`.
  </Card>

  <Card title="chatbot tools" icon="https://mintcdn.com/ish/Cj54DaF8kB36LM0P/images/logos/mcp.svg?fit=max&auto=format&n=Cj54DaF8kB36LM0P&q=85&s=0c73b17e3c604fa31be5c00cc898a957" href="/mcp/generated/tools-chatbot" width="24" height="24" data-path="images/logos/mcp.svg">
    Wiring a chatbot endpoint, where `{{secret:KEY}}` placeholders get used.
  </Card>
</Columns>
