Skip to main content

Environment Variable Reference

Environment variables are the primary way to configure harnessd and its companion programs without editing files. They form layer 5 of the 6-layer configuration cascade — higher priority than any TOML file and lower priority than future cloud/team constraints (not yet implemented). This page lists every recognized variable, its default, and its effect.

When to use env vars instead of TOML: use env vars for secrets (API keys), CI/CD pipelines, per-run overrides, and anything you do not want committed to a config file. Use TOML for settings you want shared and version-controlled.

Invalid env var values (wrong type, for example HARNESS_MAX_STEPS=notanumber) are silently ignored — the previous layer's value is kept with no warning or error message. Double-check spelling and type when a setting does not take effect.


Core and provider keys​

These variables cover the fundamental harness runtime: address, model, cost limits, workspace root, system prompt, and all provider API keys.

Runtime behavior​

VariableTOML equivalentDefaultDescription
HARNESS_MODELmodel"gpt-4.1-mini"Default LLM model identifier for every run. Any model ID or alias from the catalog is valid.
HARNESS_ADDRaddr"127.0.0.1:8080"TCP listen address for the HTTP server (socket form, e.g. ":9090", not a URL). A non-loopback bind is refused at startup unless authentication is configured or HARNESS_AUTH_DISABLED=true is set deliberately.
HARNESS_MAX_STEPSmax_steps0 (unlimited)Max tool-calling steps per run. 0 means unlimited — there is no default step cap.
HARNESS_MAX_COST_PER_RUN_USDcost.max_per_run_usd0.0 (unlimited)Per-run cost ceiling in USD. 0 means no limit.
HARNESS_WORKSPACE—"."Workspace root directory. Determines where project TOML config and database files are found.
HARNESS_SYSTEM_PROMPT—Built-in coding assistant promptOverride the default system prompt text for all runs.
HARNESS_DEFAULT_AGENT_INTENT—""Default prompt overlay when no per-run intent is given. Empty means base prompt only. Set autonomous for headless/benchmark runs; code_review/frontend_design are task overlays.
HARNESS_PROMPTS_DIR—Auto-detected (prompts/catalog.yaml walk from cwd)Directory for the file-based system prompt engine.
HARNESS_TOOL_APPROVAL_MODE—"full_auto"Tool approval mode. Valid values: "full_auto" or "permissions".
HARNESS_ASK_USER_TIMEOUT_SECONDS—300How long (in seconds) harnessd waits at an ask_user checkpoint before timing out.
HARNESS_SSE_KEEPALIVE_SECONDS—15Interval between SSE keepalive pings on event streams.
HARNESS_AUTH_DISABLED——Set to "true" to disable Bearer token authentication entirely. Implied when HARNESS_RUN_DB is not set (no key store exists).

HARNESS_MAX_STEPS=0 (the default) means "unlimited" — there is no daemon-level fallback that raises it to a non-zero cap. Set an explicit positive value to cap tool-calling steps per run.

Fake provider (key-free testing)​

VariableDefaultDescription
HARNESS_PROVIDER—Set to "fake" to use the deterministic fake provider. No API key needed. Requires HARNESS_FAKE_TURNS.
HARNESS_FAKE_TURNS—Path to a JSON turns file used when HARNESS_PROVIDER=fake.

The fake provider is the recommended path for CI smoke tests. See the benchmark smoke runbook for full details.

Provider API keys​

Each provider in the model catalog declares an api_key_env field. The table below lists every currently registered provider and the variable harnessd reads to authenticate with it.

ProviderKey variableBase URL
openaiOPENAI_API_KEYhttps://api.openai.com/v1
anthropicANTHROPIC_API_KEYhttps://api.anthropic.com/v1
deepseekDEEPSEEK_API_KEYhttps://api.deepseek.com/v1
groqGROQ_API_KEYhttps://api.groq.com/openai/v1
cerebrasCEREBRAS_API_KEYhttps://api.cerebras.ai/v1
xaiXAI_API_KEYhttps://api.x.ai/v1
kimiMOONSHOT_API_KEYhttps://api.moonshot.ai/v1
kimi-subscription(none — vendor-CLI session import)https://api.kimi.com/coding/v1
qwenDASHSCOPE_API_KEYhttps://dashscope-intl.aliyuncs.com/compatible-mode/v1
togetherTOGETHER_API_KEYhttps://api.together.xyz/v1
codex-subscription(none — vendor-CLI session import)https://chatgpt.com/backend-api/codex
openrouterOPENROUTER_API_KEYhttps://openrouter.ai/api/v1
geminiGOOGLE_API_KEYhttps://generativelanguage.googleapis.com/v1beta/openai
ollama(none — local server)http://localhost:11434/v1
lmstudio(none — local server)http://localhost:1234/v1

That is 15 providers total (catalog/models.json). Only one key is required at startup: whichever matches the default model. Additional keys are loaded on demand when a run requests a different provider. kimi-subscription and codex-subscription authenticate via harnesscli auth kimi login / auth codex login (imported vendor-CLI credentials) instead of an API key env var — see harnesscli Reference.

OPENAI_API_KEY also serves as the legacy bootstrap path: if no catalog-matched provider is configured, harnessd falls back to a bare OpenAI client if this variable is set.

OpenAI base URL override​

VariableDefaultDescription
OPENAI_BASE_URL—Override the base URL for the default OpenAI-compatible provider. Useful for proxies or OpenAI-compatible local servers.

OpenRouter headers​

VariableDefaultDescription
HARNESS_OPENROUTER_REFERER"https://github.com/dennisonbertram/go-agent-harness"Value sent as the HTTP Referer header on OpenRouter requests.
HARNESS_OPENROUTER_TITLE"go-agent-harness"Value sent as the X-Title header on OpenRouter requests.

Retry, process lifecycle, and misc​

VariableDefaultDescription
HARNESS_RETRY_MAX_ATTEMPTS3Maximum provider-call retry attempts (internal/provider/retry.go:41-44). Useful against providers with aggressive rate limiting, e.g. free tiers.
HARNESS_RETRY_MAX_TOTAL_SEC60Maximum total time (seconds) spent retrying a single provider call (internal/provider/retry.go:46-49).
HARNESS_LISTEN_FD—File descriptor number to adopt as the HTTP listener instead of binding a new socket. Used for zero-downtime restart handoff (cmd/harnessd/main.go:1116).
HARNESS_EXIT_WITH_PARENTfalseWhen true, harnessd watches its parent process and exits when the parent exits (cmd/harnessd/parent_watchdog.go:76-85).
HARNESS_MODEL_STORE_PATHmodelstore.DefaultPath()Override the file path for the model-settings store (cmd/harnessd/model_settings.go:104-107).
HARNESS_PROVIDER_CATALOG_DIRAuto-detectedOverride the directory containing per-provider catalog JSON files (cmd/harnessd/bootstrap_helpers.go:733).
HARNESS_COLOR_PROFILE"auto"TUI color profile override: truecolor, 256, ansi, or none (cmd/harnesscli/main.go:526-528).
HARNESS_CRON_API_KEY—API key harnessd's embedded cron dispatch uses when calling back into itself (cmd/harnessd/main.go:550).
HARNESS_SOURCE_ROOTAuto-detectedOverride the repository root the Go workflow engine resolves source files against (internal/workflow/source.go:862).
HARNESS_BENCHMARK_CMD./scripts/test-regression.shOverride the regression command run by the training/scoring loop (internal/training/regression.go:145).

Memory, cron, and persistence​

Observational memory​

Observational memory watches the conversation transcript and periodically extracts durable observations — facts, preferences, and constraints — that persist across runs.

VariableTOML equivalentDefaultDescription
HARNESS_MEMORY_MODEmemory.mode"auto"Memory mode. Values: "auto" (resolves to "local_coordinator"), "off", "local_coordinator".
HARNESS_MEMORY_DB_DRIVERmemory.db_driver"sqlite"Persistence backend. Values: "sqlite" or "postgres".
HARNESS_MEMORY_DB_DSNmemory.db_dsn—Postgres connection string. Only used when HARNESS_MEMORY_DB_DRIVER=postgres.
HARNESS_MEMORY_SQLITE_PATHmemory.sqlite_path".harness/state.db"SQLite file path relative to the workspace root. Also used by working memory and workflow stores.
HARNESS_MEMORY_DEFAULT_ENABLEDmemory.default_enabledfalseWhether new conversation scopes start with memory enabled.
HARNESS_MEMORY_OBSERVE_MIN_TOKENSmemory.observe_min_tokens1200Minimum accumulated token count before the observer runs.
HARNESS_MEMORY_SNIPPET_MAX_TOKENSmemory.snippet_max_tokens900Maximum token budget for the memory snippet injected into each turn.
HARNESS_MEMORY_REFLECT_THRESHOLD_TOKENSmemory.reflect_threshold_tokens4000Accumulated observation token count that triggers reflection compaction.
HARNESS_MEMORY_LLM_MODEmemory.llm_modeAuto-detectedLLM backend for the observer/reflector. Values: "inherit", "openai", "provider". Auto-detection: use "provider" if HARNESS_MEMORY_LLM_PROVIDER is set; else "openai" if OPENAI_API_KEY is set; else "inherit".
HARNESS_MEMORY_LLM_PROVIDERmemory.llm_provider—Named provider (e.g. "openrouter", "anthropic") when HARNESS_MEMORY_LLM_MODE=provider.
HARNESS_MEMORY_LLM_MODELmemory.llm_model"gpt-5-nano" (openai mode)Model used for observer and reflector LLM calls.
HARNESS_MEMORY_LLM_BASE_URLmemory.llm_base_urlFalls back to OPENAI_BASE_URLBase URL override for the memory LLM.
HARNESS_MEMORY_LLM_API_KEY—Falls back to OPENAI_API_KEYAPI key for the memory LLM. Not persisted in TOML (treated as a secret).

HARNESS_MEMORY_DB_DRIVER=postgres selects the Postgres store struct, but every method returns "postgres store is not implemented in v1". Postgres memory persistence is not functional in the current release; select this value only if you are prepared to handle the resulting error.

HARNESS_MEMORY_LLM_API_KEY is read directly in cmd/harnessd/main.go and is not part of the applyEnvLayer TOML-override function. It has no TOML equivalent by design — secrets should not be written to config files.

Cron scheduler​

The cron scheduler runs recurring agent tasks. By default, harnessd starts an embedded scheduler backed by a SQLite file at <HARNESS_WORKSPACE>/.harness/cron.db. Set HARNESS_CRON_URL to delegate to an external cronsd instance instead.

VariableTOML equivalentDefaultDescription
HARNESS_CRON_URL——HTTP base URL of an external cronsd service. When empty, the embedded scheduler is used.
HARNESS_CRON_JITTER_ENABLEDcron.jitter_enabledtrueEnable random jitter on cron job fire times to prevent thundering-herd effects.
HARNESS_CRON_JITTER_MIN_SECcron.jitter_min_sec60Minimum jitter delay in seconds.
HARNESS_CRON_JITTER_MAX_SECcron.jitter_max_sec300Maximum jitter delay in seconds.

cron.avoid_minute_marks (default [0, 30]) and cron.log_jittered_times (default true) are TOML-only settings. No env vars exist for them.

Persistence (run records, conversations, relay)​

These variables enable optional SQLite persistence for run records, conversation history, and relay worker state. All three are disabled by default (empty string). When a variable is set, harnessd opens or creates the SQLite file at that path and enables the corresponding feature.

VariableDefaultDescription
HARNESS_RUN_DB— (disabled)SQLite path for run, event, and message records. Enables GET /v1/runs and Bearer token auth.
HARNESS_CONVERSATION_DB— (disabled)SQLite path for conversation records.
HARNESS_CONVERSATION_RETENTION_DAYS30Days to retain conversation records. Requires HARNESS_CONVERSATION_DB.
HARNESS_RELAY_DB— (disabled)SQLite path for relay worker persistence. Required for GET /v1/relay/workers.

Authentication (Authorization: Bearer token checking) is implicitly disabled when HARNESS_RUN_DB is not set, because there is no key store to validate against. This is true even without setting HARNESS_AUTH_DISABLED=true.

S3 backup​

S3 backup is silently disabled unless all four required variables are present.

VariableRequiredDefaultDescription
AWS_ACCESS_KEY_IDYes—AWS access key ID.
AWS_SECRET_ACCESS_KEYYes—AWS secret access key.
AWS_REGIONYes—AWS region (e.g. "us-east-1").
S3_BUCKETYes—Target S3 bucket name.
S3_KEY_PREFIXNo""Optional path prefix prepended to every S3 object key.

Webhooks, MCP, workspaces, and forensics​

Webhook secrets​

Setting a webhook secret enables the corresponding POST /v1/webhooks/<source> route. Each route authenticates via HMAC signature, not Bearer tokens.

VariableDefaultEffect
GITHUB_WEBHOOK_SECRET—Enables POST /v1/webhooks/github. Validates HMAC-SHA256 X-Hub-Signature-256 headers.
SLACK_SIGNING_SECRET—Enables POST /v1/webhooks/slack. Validates Slack's v0=<hex> HMAC-SHA256 signature.
LINEAR_WEBHOOK_SECRET—Enables POST /v1/webhooks/linear. Validates HMAC-SHA256 signature.

When a variable is absent, the corresponding endpoint returns 401.

MCP servers​

VariableDefaultDescription
HARNESS_MCP_SERVERS—JSON array of MCP server configs merged additively with TOML-configured servers.

HARNESS_MCP_SERVERS format — each element is a JSON object:

[
{"name": "my-tool", "transport": "stdio", "command": "/usr/local/bin/server", "args": ["--flag"]},
{"name": "remote", "transport": "http", "url": "http://localhost:3001/mcp"}
]

transport is inferred if omitted: a command-only entry is stdio, a url-only entry is http. When both sources define a server with the same name, the TOML entry takes precedence.

Workspaces and subagents​

VariableDefaultDescription
HARNESS_SUBAGENT_BASE_REF"HEAD"Base git ref used when provisioning per-run git worktrees for subagents.
HARNESS_SUBAGENT_WORKTREE_ROOT—Override where per-run worktrees are materialized. When empty, defaults to a <repo>-subagents sibling directory.
HARNESS_GO_WORKFLOW_CACHE_DIR<workspace>/.harness/workflow-cacheCache directory for compiled Go workflow scripts.
HARNESS_URL—Override the harness HTTP URL at workspace provision time (used by the local and worktree workspace backends).
HARNESS_IMAGE"go-agent-harness:latest"Docker image override at provision time for the container workspace backend.
HARNESS_DOWNLOAD_URL—URL to download the harnessd binary in the VM bootstrap cloud-init script. When empty, the script expects the binary at /usr/local/bin/harnessd.
HETZNER_API_KEY—Hetzner Cloud API key. Required when using the vm workspace backend.

Model catalog and pricing​

VariableDefaultDescription
HARNESS_MODEL_CATALOG_PATHAuto-detected (catalog/models.json walk near workspace)Path to the JSON model catalog file.
HARNESS_PRICING_CATALOG_PATH—Path to a separate JSON pricing file. When empty, pricing is read from inline blocks in the model catalog.

Content directories​

VariableDefaultDescription
HARNESS_GLOBAL_DIR~/.go-harnessGlobal directory for skills, workflows, and script tools.
HARNESS_SKILLS_DIR$HARNESS_GLOBAL_DIR/skillsAbsolute override for the global skill root used consistently by loading, authoring, verification, hot reload, and Go workflow skill-bundle discovery. Relative values fail daemon startup.
HARNESS_RECIPES_DIR—Directory for recipe definitions.
HARNESS_WORKFLOWS_DIR—Directory for YAML workflow definitions.
HARNESS_NETWORKS_DIR—Directory for network (agent graph) definitions.
HARNESS_ROLLOUT_DIR—Root directory for JSONL rollout recording files. Overrides forensics.rollout_dir in TOML.

Hot-reload and skills​

VariableDefaultDescription
HARNESS_SKILLS_ENABLEDtrueEnable the skills system.
HARNESS_WATCH_ENABLEDtrueEnable poll-based hot-reload for skills and workflows.
HARNESS_WATCH_INTERVAL_SECONDS5Poll interval in seconds for the hot-reload watcher.

Role models​

VariableDefaultDescription
HARNESS_ROLE_MODEL_PRIMARY—Override the model used for primary role-model tasks.
HARNESS_ROLE_MODEL_SUMMARIZER—Override the model used for message summarization.

Callbacks and Sourcegraph​

VariableDefaultDescription
HARNESS_ENABLE_CALLBACKStrueEnable the delayed callback manager.
HARNESS_SOURCEGRAPH_ENDPOINT—Sourcegraph code search endpoint URL.
HARNESS_SOURCEGRAPH_TOKEN—Sourcegraph API token.

Conclusion watcher​

The conclusion watcher detects when the agent jumps to a conclusion prematurely.

VariableTOML equivalentDefaultDescription
HARNESS_CONCLUSION_WATCHER_ENABLEDconclusion_watcher.enabledfalseEnable the conclusion-jumping detector.
HARNESS_CONCLUSION_WATCHER_INTERVENTION_MODEconclusion_watcher.intervention_mode"inject_validation_prompt"How to intervene. Values: "inject_validation_prompt", "pause_for_user", "request_critique".
HARNESS_CONCLUSION_WATCHER_EVALUATOR_ENABLEDconclusion_watcher.evaluator_enabledfalseEnable an LLM evaluator alongside phrase-match detection.
HARNESS_CONCLUSION_WATCHER_EVALUATOR_MODELconclusion_watcher.evaluator_model"gpt-4o-mini"Model used by the LLM evaluator.

conclusion_watcher.evaluator_api_key exists in TOML config but has no dedicated env var override. It falls back to OPENAI_API_KEY in the harnessd startup code.


Subprojects​

cronsd — standalone cron daemon​

cronsd is a self-contained cron daemon that can run independently of harnessd. See Cron Scheduling for details.

VariableDefaultDescription
CRONSD_ADDR":9090"TCP listen address for cronsd.
CRONSD_DB_PATH~/.go-harness/cronsd.dbSQLite database file path.
CRONSD_MAX_CONCURRENT5Maximum number of job executions that may run simultaneously.
CRONSD_INGRESS_API_KEY—API key required on inbound requests to cronsd itself.
CRONSD_INGRESS_TENANT_ID—Tenant ID associated with CRONSD_INGRESS_API_KEY.
CRONSD_HARNESS_URL—Base URL of the harnessd instance cronsd dispatches jobs to.
CRONSD_HARNESS_API_KEY—API key cronsd uses when calling harnessd. Must differ from CRONSD_INGRESS_API_KEY.
CRONSD_HARNESS_CONNECT_TIMEOUT5sConnect timeout for cronsd → harnessd requests.
CRONSD_HARNESS_REQUEST_TIMEOUT15sOverall request timeout for cronsd → harnessd requests.

cronctl (the CLI client for cronsd) reads one variable:

VariableDefaultDescription
CRONSD_URL"http://localhost:9090"Base URL of the cronsd service.

symphd — GitHub issue orchestrator​

symphd polls a GitHub repository for issues matching a label, provisions workspaces, and dispatches agent runs. Config is primarily YAML-file-driven, but one env var provides a fallback for the GitHub token:

VariableYAML keyDefaultDescription
GITHUB_TOKENgithub_token—GitHub API token. Used when github_token is not set in the symphd YAML config file.

symphd also propagates OPENAI_API_KEY, ANTHROPIC_API_KEY, and HARNESS_MODEL from its own environment into each provisioned workspace (container env vars, never written to disk).

trainerd — rollout analyzer​

trainerd scores and analyzes JSONL rollout traces captured by harnessd. It reads one env var:

VariableDefaultDescription
HARNESS_ROLLOUT_DIR~/.trainerd/rolloutsDefault rollout directory. The --db-path flag controls trainerd's own SQLite store; ANTHROPIC_API_KEY is required for LLM-backed analysis.
ANTHROPIC_API_KEY—Required for trainerd analyze and trainerd loop commands that call Claude for deeper rollout analysis.

socialagent — example Telegram app​

apps/socialagent is a complete example application that drives harnessd over HTTP. It has its own set of env vars:

VariableRequiredDefaultDescription
TELEGRAM_BOT_TOKENYes—Telegram Bot API token from @BotFather.
TELEGRAM_WEBHOOK_SECRETYes—Secret token for X-Telegram-Bot-Api-Secret-Token header validation.
DATABASE_URLYes—Postgres connection string.
OPENAI_API_KEYYes—Passed through to harnessd; not used by socialagent directly.
HARNESS_URLNo"http://localhost:8080"Base URL of the running harnessd instance.
LISTEN_ADDRNo":8081"TCP address for socialagent's own HTTP server.
MCP_SERVER_URLNo"http://localhost:8082/mcp"URL of socialagent's embedded MCP server, passed to each harnessd run.
SAFETY_SCREENER_URLNo— (disabled)Llama Guard-compatible safety screening endpoint. Empty disables screening.
SOCIALAGENT_SYSTEM_PROMPTNoBuilt-in personalitySystem prompt override.

TOML-only settings (no env override)​

Some settings can only be configured via TOML; no corresponding env var exists.

TOML keySectionDescription
cron.avoid_minute_marks[cron]List of minute values (e.g. [0, 30]) that jitter avoids landing on.
cron.log_jittered_times[cron]Whether to log the jittered fire time for each job.
auto_compact.*[auto_compact]Context auto-compact settings (mode, threshold, keep_last, model_context_window).
forensics.*[forensics]Trace, audit, and forensics flags.
mcp_servers.*[mcp_servers]Named MCP server entries (merged with HARNESS_MCP_SERVERS; TOML wins on name conflicts).
conclusion_watcher.evaluator_api_key[conclusion_watcher]API key for the evaluator LLM; falls back to OPENAI_API_KEY.

Quick-reference: where settings apply​

The following variables are read directly in cmd/harnessd/main.go rather than through the applyEnvLayer TOML-override function: HARNESS_WORKSPACE, HARNESS_SYSTEM_PROMPT, HARNESS_DEFAULT_AGENT_INTENT, HARNESS_PROMPTS_DIR, HARNESS_ASK_USER_TIMEOUT_SECONDS, HARNESS_TOOL_APPROVAL_MODE, HARNESS_SKILLS_ENABLED, HARNESS_WATCH_ENABLED, HARNESS_WATCH_INTERVAL_SECONDS, HARNESS_MEMORY_LLM_API_KEY, HARNESS_MEMORY_LLM_BASE_URL, and others in the runtime bootstrap section. They behave like env var overrides but are not part of the serialized Config struct.


Next steps​