ish secret reference.
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 exampleGROQ_API_KEY). Anything else is rejected before the call leaves your machine.
Secrets live on the workspace, alongside 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.
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 concern, not a secret one.How a secret gets used
A chatbot endpoint config can carry placeholders anywhere in the rendered request, most often in a header:{{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.
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):
Stdin
--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.File
--value-file <path> reads from disk. Pass - as the path to read stdin instead.Positional
A bare value on the command line. Convenient, but it lands in shell history. Avoid it in scripts.
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. |
{{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, 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 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
Site access
The reserved-key sibling: credentials for reaching a gated URL in an
interactive study, written in pairs.Workspaces
Where secrets live, and what else a workspace holds.
ish secret reference
Every flag for
ish secret list, set, and delete.chatbot tools
Wiring a chatbot endpoint, where
{{secret:KEY}} placeholders get used.