Server secrets
Give harnessd its model, tracker and push credentials in secrets.env, per-project files, or the write-only overlay admins change from the app.
harnessd reads secrets from files you control on the server, plus an overlay that admins change from the app. Values set from the app are write-only: only names ever come back.
Where values come from#
| Layer | Where | Scope |
|---|---|---|
secrets_file | /etc/harness/secrets.env, mode 0600 | Server-wide |
projects[].secrets_file | For example /etc/harness/projects/<name>.env, mode 0600 | One project, overriding server-wide values |
| The overlay | data_dir/secrets/remote.json, mode 0600 (directory 0700) | Server-wide and per project, set by admins from the app |
An overlay value wins over the file's value with the same name. Removing it from the app falls back to the file's. The files are never rewritten.
secrets.env#
The file is KEY=VALUE lines. # starts a comment, a leading export is allowed, and values may be wrapped in single or double quotes.
# chmod 600, owner harness. Never commit the real file.
# Agent / model credentials: injected only into agent processes, never into hooks or $VAR resolution.
CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat…
# ANTHROPIC_API_KEY=sk-ant-api…
# OPENAI_API_KEY=sk-…
# HARNESS_GATEWAY_API_KEY=sk-… # LiteLLM virtual key (give it a budget)
# Tracker credentials referenced from WORKFLOW.md as $VAR (resolved host-side, stripped from agents):
CLICKUP_API_TOKEN=pk_…
# GITHUB_TOKEN=github_pat_…
# Branch publishing (git push + gh pr create at hand-off), and cloning https projects added from the app.
# Host-only; stripped from every agent and hook environment. Use a fine-grained token limited to the
# project repos with Contents: read/write and Pull requests: read/write. Requires `gh` for PRs.
HARNESS_GITHUB_TOKEN=github_pat_…
# HARNESS_GITLAB_TOKEN=glpat-…
# Cloudflare sandboxes: the bridge Worker's HARNESS_BRIDGE_TOKEN. Host-only; never passed to agents.
# HARNESS_CLOUDFLARE_TOKEN=…
# Anything else is a variable for $VAR references and hooks:
SENTRY_DSN=https://…sudo chown harness:harness /etc/harness/secrets.env
sudo chmod 600 /etc/harness/secrets.env
sudo systemctl restart harnessdharnessd check fails if the file is readable by group or others.
How each kind of name is used#
| Names | Used for | Reaches |
|---|---|---|
ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, OPENAI_API_KEY | Agent credentials | The egress proxy's relay, in memory; sandboxes get a placeholder |
HARNESS_GATEWAY_API_KEY, LITELLM_API_KEY | Gateway key | The egress proxy's relay, in memory; sandboxes get a placeholder |
HARNESS_GITHUB_TOKEN, HARNESS_GITLAB_TOKEN | Push, PRs, cloning | The server's own git, through a credential helper |
HARNESS_CLOUDFLARE_TOKEN | The bridge | The server only |
| Everything else | $VAR in WORKFLOW.md, hooks, docker.env | Hooks; sandboxes only for names in docker.env (model credentials never) |
Every value of 8 characters or more is redacted from anything the server hands out: transcripts, run errors, container logs, connection-test errors.
Change secrets from the app#
- Open Server Settings or the project's secrets
For server-wide values: the server's Server Settings → Credentials (model keys) or Environment (any variable). For one project: the project's … menu → Project Secrets & Test Logins….
- Set, replace or remove
Rows show only names and where each comes from: file or set from the app. Fields start empty; typing a value replaces it. Remove… removes a value set from the app, falling back to the file's.
- Enter a code
Every change asks for a fresh code from your authenticator. In Server Settings, one code covers a whole Save. Changes are audited by name, never by value.
Values must be one line, up to 16 KB. Names are environment-variable names: letters, digits and _, starting with a letter or _, up to 128 characters.
After a change, every project reloads its workflow, so $VAR references and credentials pick up the new value without a restart.