# Secrets

Source: https://codeherder.com/docs/secrets/

Store encrypted credentials at the workspace level and hand one to an agent through a Credential ref, without ever putting a plaintext value in a launch config.

A **secret** is an encrypted value scoped to your workspace — typically an API key, access token, or other credential your agents need at runtime. You create it once with a name and a value; from then on, CodeHerder and everyone in your workspace only ever see the name and a version number, never the value itself.

This page covers the original way to do this: create a secret, then wire it into a launch config with a Credential ref. `ch variable` is the current spelling for this and for plain (non-secret) values at group, workspace, device, or agent scope — see [Variables](https://codeherder.com/docs/variables/) for the newer, one-step alternative, where a secret variable reaches a session directly with no separate ref to wire up. The old secrets command is removed. It exits with code 2 and points to `ch variable`. Your existing secrets keep working.

## Two ways to give an agent a credential

A workspace secret, covered on this page, is one of two ways to do this. CodeHerder holds the encrypted value and it’s available to the agent on any device it runs on. The other is a **device-side reference** — an `@secret:<key>` value in the launch config that the device itself resolves at spawn time, so the value never reaches CodeHerder at all. Reach for a device-side reference when you don’t want CodeHerder to hold the credential; see [Secrets on a device](https://codeherder.com/docs/device-secrets/) for how it works.

## Who can manage secrets

`ch variable` secret commands are owner/admin only — every other role is refused outright, since each command requires a human token. On **Settings → Variables**, any workspace member can see a secret’s name in the list (it carries a **Legacy** chip there — see [Variables](https://codeherder.com/docs/variables/)), but the only action an owner or admin has on that row is **Delete** — creating and rotating a secret are CLI-only, as below. And **agents can never view or manage secrets** at all: an agent’s own session credentials can’t be used to create, read, or change one. The entire point of a secret is that an agent can use a credential without ever holding or seeing it.

(You can wire an existing secret into an agent’s launch config from the CLI regardless of who created it — see “Giving a secret to an agent” below.)

## Creating a secret

Creating a secret by name is CLI-only now that **Settings → Secrets** is gone (the old address redirects straight to **Settings → Variables**): `ch variable set <name> --secret --from-file <path|->`. Name it with lowercase letters, digits, hyphens, and underscores, up to 64 characters (for example, `github-pat` or `slack_webhook`) — names must be unique within the workspace.

If you’re setting up a brand-new credential rather than reusing an existing secret’s name, a secret variable is the current, easier path — `ch variable set <KEY> --from-file <path|-> --secret`, or the **Secret** option in the web app — see [Variables](https://codeherder.com/docs/variables/) for the full walkthrough.

The value comes from a file or from standard input. There is no inline form, so the value never lands in your shell history:

```
ch variable set github-pat --secret --from-file token.txt          # from a file
printf %s "$TOKEN" | ch variable set github-pat --secret --from-file -  # stdin
```

Either way, the value is write-only: once saved, CodeHerder never displays it again, in the web app, through the CLI, or through the API. Keep a copy wherever you originally generated it if you might need to check it later.

## Listing and inspecting secrets

`ch variable list` shows every variable in the workspace, secrets included. `ch variable show <name>` shows the same metadata for one secret. Neither prints the value, and the CLI has no command to read a secret back once it’s saved. A session that gets the secret as an environment variable can still read it.

`ch variable show` also prints the row id, which `ch agent config edit --credential-ref ENV=<id>` takes. Commands take the secret’s exact name, with no prefix, substring, or id matching, and need `CH_WORKSPACE_ID` set so CodeHerder knows which workspace to look in (see [Agents and the CLI](https://codeherder.com/docs/agents-and-cli/) for setting up the CLI).

## Rotating a secret

Rotating is CLI-only: `ch variable set <name> --secret --from-file <path|->`, with the same file or stdin forms as creating one. CodeHerder bumps the secret’s version number every time you rotate it, so its row always shows how many times it’s changed.

Every agent config that references the secret picks up the new value automatically the next time it spawns — there’s nothing else to update.

## Deleting a secret

From the web app: open **Settings → Variables**, find the row (it carries a **Legacy** chip), and click **Delete**. From the CLI: `ch variable unset <name>`.

Either way this is irreversible, and **any agent config that still references the deleted secret fails to spawn**. Before you delete a secret, update or remove the Credential ref on every agent that uses it — otherwise a task that reaches that stage errors out instead of starting.

## Giving a secret to an agent

A secret does nothing by itself — you connect one to an agent through a **Credential ref** on the agent’s launch config (see [Agents and the CLI](https://codeherder.com/docs/agents-and-cli/) for launch configs in general). Open the config’s editor and use the **Credential refs** field:

1. Enter the environment variable name the agent’s process should see, for example `GITHUB_TOKEN`. It must be uppercase letters, digits, and underscores, starting with a letter or underscore — and it can’t start with `CH_`, which CodeHerder reserves for its own variables.
2. Select the workspace secret to bind to that name.
3. Save.

You can do the same from the CLI with `ch agent config edit <agentId> --credential-ref <ENV_VAR>=<secretId>` (repeat the flag for more than one).

Either way, CodeHerder resolves the reference and injects the value into the process environment only at the moment a session spawns — the value is **never stored in plaintext** in the launch config, and CodeHerder redacts secret-shaped values from its own log lines and from the stored exit tail. The agent’s process sees a normal environment variable, so the agent can print or send the value. Redaction works by shape only and can miss a value. Bind a secret only to an agent you trust with it.

Credential refs don’t add an extra approval step of their own: once an agent is eligible to run on a device (see [Agents and the CLI](https://codeherder.com/docs/agents-and-cli/)), every Credential ref on its launch config resolves automatically each time that stage spawns.

## Availability

Secrets depend on encryption support being configured on your deployment. If creating or rotating one fails with an error saying the feature isn’t available, encryption isn’t configured on your deployment — ask your workspace admin.

## Related guides

- [Variables](https://codeherder.com/docs/variables/) — the current, one-step way to give a session a plain or secret value, at group, workspace, device, or agent scope
- [Secrets on a device](https://codeherder.com/docs/device-secrets/) — the device-side alternative: reference a credential that lives only on a device, with no round trip through CodeHerder.
- [Agents and the CLI](https://codeherder.com/docs/agents-and-cli/) — configure a launch config, including where Credential refs live, and where an agent runs.
- [Managing your devices](https://codeherder.com/docs/devices/) — device state and troubleshooting for wherever an agent runs.
- [Integrations](https://codeherder.com/docs/integrations/) — a different, workspace-level way to store a credential: connecting the workspace itself to an external service like GitHub or PagerDuty, rather than handing a secret to an agent.
