Server (harnessd)

harnessd.yaml reference

Every key in the server's configuration file, its default, and the security checks harnessd runs on it.

harnessd reads one YAML file, by default /etc/harness/harnessd.yaml. Pass another with --config, or set HARNESSD_CONFIG. Relative paths in the file resolve against the file's own folder, and ~ is expanded. The server never rewrites this file: changes made from the app are kept in a private overlay on top of it.

Complete example#

/etc/harness/harnessd.yaml
# Validate with: harnessd check --config /etc/harness/harnessd.yaml
#
# Secure by default: harnessd refuses to start if it would listen on every interface, without TLS,
# with a world-readable key or secrets file, or without an admin account.

# Loopback: the Mac app connects through an SSH tunnel (see /server/connecting).
# Never 0.0.0.0 unless allow_all_interfaces: true.
listen: 127.0.0.1:8443

# TLS 1.3 only. Clients pin the certificate; a self-signed one works through the SSH tunnel.
tls:
  cert: /etc/harness/tls/fullchain.pem
  key:  /etc/harness/tls/privkey.pem          # chmod 600

# Host-side tracker tools for agent sandboxes. Use the docker bridge address so only containers reach it.
tools_listen: 172.17.0.1:7879

data_dir: /var/lib/harness                    # users, audit log, repos, logs (0700)
secrets_file: /etc/harness/secrets.env        # chmod 600

session:
  idle_minutes: 60
  absolute_hours: 12
lockout:
  max_failures: 5
  lock_minutes: 15
auth:
  require_totp_for_admins: true               # harnessd user totp <admin>

# Route all model traffic through LiteLLM (key in secrets.env as HARNESS_GATEWAY_API_KEY).
gateway:
  base_url: http://10.8.0.20:4000
  enabled_by_default: true
  auth_header: bearer
  models:
    opus: claude-opus-5-5
    sonnet: claude-sonnet-5-5
    haiku: claude-haiku-5-5
  tags: true

# Caps across every project on this server. Projects add their own limits: in WORKFLOW.md.
limits:
  max_concurrent_agents: 6
  daily_budget_usd: 200
  daily_token_budget: 50000000

# Hosts every sandbox may reach (allowlist mode). Omit default_allow to use the built-in list.
sandbox:
  network:
    default_allow: [registry.npmjs.org, pypi.org, files.pythonhosted.org, github.com, codeload.github.com]
  cloudflare:
    bridge_url: https://harness-sandbox-bridge.your-account.workers.dev   # + HARNESS_CLOUDFLARE_TOKEN in secrets.env

projects:
  - name: shop-storefront
    repo: git@github.com:your-org/shop-storefront.git   # cloned into data_dir/repos (deploy key)
    workflow: WORKFLOW.md
    auto_start: true
    secrets_file: /etc/harness/projects/shop-storefront.env   # optional, 0600: overrides secrets.env
  - name: shop-api
    path: /srv/checkouts/shop-api                         # an existing checkout, used in place
    auto_start: false

Network#

KeyDefaultDescription
listenrequiredhost:port (or [ipv6]:port) for the API. Port defaults to 8443. Must be a specific interface. Use 127.0.0.1:8443 and an SSH tunnel; see Connect the app to a server.
allow_all_interfacesfalseSet true to allow 0.0.0.0, :: or * in listen. Deliberately awkward.
trusted_proxiesnoneCIDR ranges (or single addresses) of load balancers in front of the server, for example [10.0.0.0/16]. Only a connection from one of them can name the client in X-Forwarded-For, and the client is the rightmost address that isn't a trusted proxy. Without it the header is ignored. See Behind a load balancer.
tls.certPEM certificate chain. TLS 1.3 only.
tls.keyPEM private key. Must be mode 0600.
insecure_http_behind_proxyfalsePlain HTTP, only when listen is 127.0.0.1, ::1 or localhost, behind a TLS-terminating proxy on the same host.
tools_listen172.17.0.1:7879 on Linux, 127.0.0.1:7879 on macOSThe agents' MCP tools listener; serves only /mcp/<session-token>, without TLS. On Linux use the Docker bridge; on a Mac with Docker Desktop, loopback works (containers reach it as host.docker.internal). Port defaults to 7879.

Storage#

KeyDefaultDescription
data_dir/var/lib/harnessUsers, audit log, cloned repos, run history, logs and the secrets overlay. Kept at 0700.
secrets_fileKEY=VALUE file of server-wide secrets and variables. Must be 0600. See Secrets.

Sessions and sign-in#

KeyDefaultDescription
session.idle_minutes60A session ends after this long without a request. Must be positive.
session.absolute_hours12A session ends this long after sign-in, regardless of activity. Over 24 is warned about.
lockout.max_failures5Failed sign-ins per account within the window before it's locked. Per IP address the threshold is 4× this.
lockout.lock_minutes15The window and the lock's duration.
auth.require_totp_for_adminsfalseAdmins must have an authenticator enrolled to sign in; check fails while any active admin has none. Recommended.

Model gateway#

Server-wide equivalent of Settings → Model Gateway. The key goes in secrets.env as HARNESS_GATEWAY_API_KEY (or LITELLM_API_KEY).

KeyDefaultDescription
gateway.base_urlGateway URL.
gateway.enabled_by_defaulttrue when base_url is setRoute every project through it unless it opts out.
gateway.auth_headerbearerbearer or x-api-key.
gateway.models.opus, .sonnet, .haiku, .codexModel slots.
gateway.tagstruex-litellm-tags spend tags.
gateway.disable_experimental_betasfalseFor proxies that reject Claude Code's beta fields.
gateway.wire_apiresponsesCodex: responses or chat.

Limits#

KeyDefaultDescription
limits.max_concurrent_agentsnoneAgents at once across all projects.
limits.daily_budget_usdnoneDispatch stops for the day once all projects together reach it.
limits.daily_token_budgetnoneThe same, in tokens.

Sandbox#

KeyDefaultDescription
sandbox.network.default_allowSI Fabrik's built-in listHosts every sandbox may reach. See Network policy.
sandbox.cloudflare.bridge_urlBridge Worker URL for sandbox.provider: cloudflare. Token: HARNESS_CLOUDFLARE_TOKEN in secrets.env.

Projects#

KeyDefaultDescription
projects[].namerequiredUnique name; how clients see the project.
projects[].repoGit URL, cloned once into data_dir/repos/<name>.
projects[].pathAn existing checkout, used in place. Set repo or path.
projects[].workflowWORKFLOW.mdPath of the workflow file inside the repository.
projects[].auto_startfalseStart the orchestrator when the server starts.
projects[].secrets_fileThe project's own KEY=VALUE file (0600), layered over secrets_file.

See Projects on a server.

Security checks#

harnessd check runs these checks, and harnessd serve runs them again and refuses to start on any error:

CheckError when
Interfacelisten binds every interface without allow_all_interfaces: true
TLSNo tls.cert/tls.key, unless plain HTTP is allowed on loopback with insecure_http_behind_proxy
File modestls.key, secrets_file or any projects[].secrets_file is readable by group or others, or missing
Tools listenertools_listen binds every interface, or equals listen
Trusted proxiesA trusted_proxies range is wider than /8 (IPv4) or /32 (IPv6). An entry that isn't an address or range stops the file from loading.
LifetimesSession or lockout values aren't positive
AdminsThere's no active admin account
Admin TOTPrequire_totp_for_admins is on and an active admin has no authenticator

Warnings: tools_listen on loopback (Docker sandboxes can't reach it), session.absolute_hours over 24, trusted_proxies set while listen binds every interface, and no projects configured.

See also#