Environment and variables
Define global and per-project variables, reference them from WORKFLOW.md, and control exactly what reaches an agent's sandbox.
SI Fabrik keeps two layers of environment variables: a global one for every project on the host, and a per-project one. $NAME references in WORKFLOW.md and hooks see both, with the project's value winning. Sandboxes see only the names you list.
Where to set them#
| Layer | Mac app | harnessd |
|---|---|---|
| Global | Settings → Environment (Keychain) | secrets_file (secrets.env, mode 0600), plus variables an admin sets from the app |
| Per project | Edit Project → Environment (Keychain, one item per project) | projects[].secrets_file (mode 0600, checked by harnessd check), plus variables set from the app |
GUI apps don't inherit your shell's environment, so a token you exported in ~/.zshrc isn't visible to SI Fabrik. Define tracker keys such as CLICKUP_API_TOKEN in Settings → Environment.
Add a variable#
- Global
Open Settings → Environment, press +, and enter a Name and Value. Values are stored in your login Keychain.
- Per project
Open the project's … menu → Edit Project…. Under Environment, press Add Variable. A name that also exists globally shows overrides global.
- Reference itWORKFLOW.md
tracker: kind: clickup provider: api_token: $CLICKUP_API_TOKEN workspace: root: ${WORKSPACES}/storefront docker: env: [SENTRY_DSN, FEATURE_FLAGS_KEY] # passed into the sandbox by name
Rules#
- Precedence: a project's value wins over the global one with the same name.
- Where they're used:
$NAMEand${NAME}inWORKFLOW.mdare resolved on the host. Hooks get the merged environment. - What reaches a sandbox: only the names in
docker.env, passed by name (-e NAME) so values never appear on a command line. Push tokens and model credentials are never passed; the model credential is added by SI Fabrik's relay instead. - Tracker credentials are resolved on the host and stripped from agent processes.
Credential names#
Some names are credentials. In a project's environment they replace the global credential for that project only:
| Name | Used as |
|---|---|
ANTHROPIC_API_KEY | Anthropic API key for Claude Code |
CLAUDE_CODE_OAUTH_TOKEN | Token from claude setup-token |
OPENAI_API_KEY | OpenAI key for Codex |
HARNESS_GATEWAY_API_KEY, LITELLM_API_KEY | Gateway key |
These names never enter hook or agent environments, and never take part in $VAR expansion. The runners inject credentials explicitly, and Cloudflare sandboxes only ever see a placeholder. A project that sets one kind of Claude credential (ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN) uses only that kind.
Give each project its own LiteLLM virtual key in Edit Project → Environment as LITELLM_API_KEY. LiteLLM then enforces a budget per project.
Reserved host-only names, stripped from every agent and hook environment: HARNESS_GITHUB_TOKEN, HARNESS_GITLAB_TOKEN, HARNESS_CLOUDFLARE_TOKEN.
Check where values come from#
The Workflow tab's inspector has a Variables panel. It lists every variable the workflow references (including docker.env names) and its source: project, global, SI Fabrik process, or not set.