CodeHerderSearch⌘KRequest access →

Variables

Set environment variables and sealed secrets at group, workspace, device, or agent scope, and see which one an agent's session actually gets.

A variable is a key/value pair CodeHerder injects into an agent’s process environment when a session starts. You set one at whichever scope makes sense — a group, a workspace, a device, or a single agent — and every session that spawns underneath it picks it up automatically, no launch config edit required.

A variable can hold a plain value or a secret one. Either way it’s the same kind of record; secret just means CodeHerder never shows the value back to anyone once it’s saved.

The four scopes, and which one wins

You can set a variable at:

  • Group — reaches every workspace nested underneath it.
  • Workspace — reaches every device and agent that runs tasks for that workspace.
  • Device — reaches every agent that runs on that device.
  • Agent — reaches only that agent’s own sessions.

If more than one scope sets the same key, CodeHerder resolves a single winner per session: an agent-scoped value wins over a device-scoped value, which wins over the workspace chain (checking the workspace itself first, then its parent group, and so on up the tree). That’s normal, not a conflict to avoid — set a sensible default at the workspace or group, then override it lower down for the one device or agent that needs something different.

One thing outranks all of it: if the agent’s own launch config already sets that key directly (its own Env field), that value always wins, no matter what any variable says. Variables are for values you want to manage centrally without touching every launch config; a value hard-coded in a launch config still takes priority over anything set here.

Setting one from the web app

Open Settings → Variables. Use the Scope filter to switch between Workspace, Device, and Agent — picking Device or Agent shows a second picker to choose which one. Check This scope only to see just the rows set directly there, without anything inherited from above.

Click New variable and fill in:

  • Key — uppercase letters, digits, and underscores, starting with a letter or underscore (for example DEPLOY_ENV or MAX_RETRIES).
  • Value — required; the value CodeHerder should inject.
  • Secret — turn this on to store the value sealed. See Secret variables below.

A row inherited from a group or a parent workspace shows an Inherited badge — hover it to see which scope it came from. Click Override here on that row to set your own value at the current scope instead — the override wins from then on, per the ranking above. On a row already owned at the current scope, click Edit to change its value in place.

A secret with a lowercase name, such as github-pat, carries a Legacy chip. You can only delete one of these rows in the web app. The chip’s hint tells you to rotate it with ch variable set <name> --secret --from-file <path|->. See Secrets.

Anyone in the workspace can see the list; changing it needs a workspace owner or admin — or, for a device, that device’s own owner. Without one of those roles, the page opens but every write control is hidden.

Setting one from the CLI

ch variable (short form: ch var) is the CLI equivalent. Lead with the scope you want — device <ref> or agent <ref> — on any of list, show, set, and unset; leave it off for your current workspace, which is the default:

ch variable                                       # same as `ch variable list` — the effective chain for your workspace
ch variable list device mydevice                  # a device's own rows
ch variable show DEPLOY_ENV                       # one key, at the default (workspace) scope
ch variable show DEPLOY_ENV agent planner         # one key, at an agent's own scope
ch variable set DEPLOY_ENV agent planner --from-file value.txt
ch variable unset DEPLOY_ENV agent planner

The scope is a keyword after the key: workspace, device, or agent, then an optional ref. To reach group scope, pass the group’s name after workspace. There is no group keyword:

ch variable list workspace myteam             # a group's own rows

Add --strict to a workspace or group listing to show only the rows set directly there, with nothing inherited — --strict is refused at device or agent scope, since every row there is already local-only. --device <ref> and --agent <ref> widen a workspace or group listing to also show that device’s or agent’s own rows layered on top — handy for checking exactly what one agent’s next session will see; they’re refused at device or agent scope for the same reason. A long listing pages — see paging through long lists for --limit and --cursor.

Setting a value always goes through a file or standard input, never a plain argument — anything typed directly on the command line can end up in your shell history or in a process list other users on the same machine can see:

ch variable set DEPLOY_ENV --from-file value.txt
printf %s "staging" | ch variable set DEPLOY_ENV --from-file -

Both forms work the same way; use whichever is easier to script. An empty file writes a blank plain value; a secret needs content. ch variable unset <KEY> removes the row you set at that scope (both set/unset also accept edit/delete as aliases).

Secret variables

Turn on Secret — or add --secret on the CLI — and CodeHerder seals the value instead of storing it as plain text. From that point, nobody can read it back: the web app shows a Secret badge and dots instead of a value, and ch variable show prints <secret>. If you need to change it, you write a new value; there’s no “reveal” anywhere.

printf %s "sk-live-…" | ch variable set STRIPE_KEY --from-file - --secret

Secret variables depend on encryption support being configured on your deployment. If saving one fails with an error saying the feature isn’t available, encryption isn’t configured on your deployment — ask your workspace admin.

Whether a variable is secret is fixed the moment you create it — you can’t flip an existing plain variable to secret or back. To change your mind, delete the key and create it again with the flag set the way you want.

A key normally has to be uppercase letters, digits, and underscores. A secret is the exception when you create it from the CLI: it can also take a lowercase name of up to 64 characters, using lowercase letters, digits, hyphens, and underscores (for example ch variable set github-pat --secret --from-file token.txt). The web app creates uppercase names only. A lowercase-named secret never goes into the environment by itself. It reaches a session only through a Credential ref — see Secrets. If you need a value in the process environment under its own name, give it an uppercase key.

A secret variable with an uppercase key only reaches a session if the device it’s about to run on has been told to expect it. This is the same acknowledgement a device owner gives for a device-side secret reference. Set it with:

ch device secrets set <deviceId> --secret STRIPE_KEY

This replaces the device’s whole acknowledged list, so include every key you want it to keep, not just the new one. Until the device owner acknowledges the key, a session that needs it refuses to start rather than run without it.

Two details catch people out:

  • It applies to every session in scope. Add an uppercase secret at workspace or group scope, and every session under it refuses to start on a device that hasn’t acknowledged the key. This holds even when a Credential ref also binds the secret.
  • The acknowledgement expires. By default it lasts 90 days from the last ch device secrets set. ch device secrets list <deviceId> prints the expiry date. Run ch device secrets set again with the same keys to renew it.

See Secrets on a device for the full command.

What’s refused, and why

CodeHerder turns down a handful of key/value combinations before they ever get saved:

  • A key must be uppercase letters, digits, and underscores, and start with a letter or underscore — every plain variable, and every variable created in the web app. The one exception is a secret created from the CLI, which can also use a lowercase name — see Secret variables above.
  • A key starting with CH_ is reserved for CodeHerder’s own use.
  • A key whose name reads like a credential must be saved with Secret turned on, whatever its value — for example anything ending in _TOKEN, _KEY, _SECRET, _PASSWORD, or _CREDENTIALS, or a well-known name like DATABASE_URL or GITHUB_TOKEN. This is keyed off the name, not the value: DEPLOY_TOKEN set to the harmless value production is still refused as plain text, since the point is to protect the class of key, not to guess whether any one value looks sensitive.
  • Separately, a value that carries an inline credential in a connection string — scheme://user:password@host — must be Secret too, regardless of what the key is called.
  • A handful of keys that could redirect what a session runs or which server it talks to are refused at every scope, no exceptions — for example, keys that control which executable a shell finds or which libraries a process loads.
  • Keys that redirect package installs, proxies, certificate trust or browser downloads — for example NPM_CONFIG_REGISTRY, PIP_INDEX_URL, GOPROXY, HTTPS_PROXY and SSL_CERT_FILE — are refused at every scope too. Package and browser downloads in container stages lists them and shows how to use a private registry instead.
  • A value in the form @secret:<name> is refused here — that syntax belongs in a launch config’s own Env field, where it references a device-side secret directly. Use the Secret flag on this store instead.
  • A secret needs content. ch variable set --secret refuses an empty value. A plain variable may be empty.

If a save is refused, the error names which rule it hit — adjust the key or value and try again.

Limits

A single scope — one group, one workspace, one device, or one agent — can hold up to 100 variables, and a single value can be up to 4096 bytes.

Who can manage variables

Anyone in the workspace can see the workspace’s or group’s effective chain, including a view narrowed onto one device’s or one agent’s rows — useful for checking exactly what a session will get. Looking at a device’s or an agent’s own rows on their own, separately from that chain, needs the same role that can change them there.

Changing a group, workspace, or agent variable needs a workspace owner or admin. Changing a device’s own variables needs that device’s owner or a workspace owner. An agent can never write its own variables through its session credential — only a signed-in human can.

How this fits with secrets and credential refs

ch variable is the one place to manage plain values and secrets. Three things are easy to confuse:

  • A secret variable with an uppercase key goes into every session in scope under its own name. This page covers it.
  • A Credential ref binds a workspace or group secret to one launch config under an environment variable name you choose. A lowercase-named secret reaches a session only this way. See Secrets.
  • A device reference is an @secret:<name> value in a launch config’s own Env field. The device resolves it from its local secret store, so CodeHerder never holds the value. See Secrets on a device.

Last updated

CodeHerder

Round up your herd.

Bring every human and every agent onto one table. Watch the work move. Costs update as it happens.

Try "pricing", "connect a device", or "who reviews the code"

↑↓ move · ↵ open · esc close