Skip to content

config.yaml

Configure the daemon in config.yaml. Agent-specific settings belong in agent files.

~/.config/wardrik/config.yaml
org: acme
base_url: https://agents.acme.example
defaults:
model: anthropic:claude-sonnet-5
policy: careful
roles:
reader: {rules: [{verbs: [read, events], kinds: [agent]}]}
bindings:
- {org: acme, role: operator, subjects: [user:acme/@ana, group:platform]}
- {org: acme, role: reader, subjects: [agent:triage]}
mcp:
github:
url: https://api.githubcopilot.com/mcp/
credential: github
gated: [create_*]
oauth:
providers:
github:
issuer: https://github.com/login/oauth
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
scopes: [repo]
flow: device
channels:
slack:
type: slack
token: ${SLACK_BOT_TOKEN}
app_token: ${SLACK_APP_TOKEN}
domains: {acme.com: acme}
notify:
targets:
ops: {channel: slack, room: "#ops"}
  • The file is config.yaml in the config directory. If it's missing, every key uses its default.
  • Restart the daemon after a change. wardrik doctor validates the file without starting the daemon.
  • An unknown key or invalid value prevents startup. The error identifies the setting.
  • ${NAME} resolves from the environment, then the env file, then the deployment's vault secret NAME (wardrik vault put NAME). vault, http and storage resolve from the environment only.
Key Default Description
org default the deployment's org
orgs {} additional orgs
roles, bindings {}, [] access control
base_url the HTTP API's URL the daemon's public URL; webhook and OAuth callback URLs are under it
deployment_keys true agents fall back to deployment API keys when their owner has none
allow_private_urls false allow MCP servers, webhooks and OAuth apps at private addresses; local use only
defaults {} default values for keys a definition omits
models {} prices, call options and the gateway for models
mcp {} MCP servers
harnesses {} coding agents over ACP
rest {} HTTP APIs, from their descriptions
checkouts {} git repositories coding agents work in
oauth none OAuth providers
channels {} chat apps
notify {} notice targets
workspace none which agents can mount which workspaces
brave.api_key none the API key for web_search
vault.keys [] vault keys; default: WARDRIK_VAULT_KEY or a generated vault_key file
http the HTTP API's listen address
storage the node's disk the store: Postgres or S3
deployment local the deployment name in each event's source
idle_timeout 900 idle seconds before an agent's process stops, or infinity
retention 30 days to keep events, or infinity
triggers {} trigger options, such as req_options for fetching feeds
cluster one node the nodes that run as one
agents {} agent placement and idle memory settings

tools, tokens and ssh are ignored with a warning.

orgs:
"*":
mcp: [search]
policy: base
payments:
mcp: [stripe, github]
channels: [payments-slack]
notify: [audit]
policy: payments-strict
Key Description
mcp servers from mcp available to its agents
harnesses coding agents from harnesses available to its agents
rest APIs from rest available to its agents
channels channels from channels available to its agents
notify targets from notify available to its agents
policy a policy in policies/ applied to all its agents
  • "*" matches every org. Its servers, channels, targets and policy apply to all orgs.
  • A server, harness, API, channel or target no org lists belongs to the deployment's org.
  • A channel belongs to one org, or to every org if "*" lists it.

Access control follows the Kubernetes RBAC model. Roles define permitted operations; bindings grant roles to users, groups, or agents in an organization.

roles:
reader:
rules:
- {verbs: [read, events], kinds: [agent]}
runbook-editor:
rules:
- {verbs: [define], kinds: [agent], names: [runbooks]}
bindings:
- {org: payments, role: operator, subjects: [user:payments/@ana, group:payments-eng]}
- {org: payments, role: reader, subjects: [agent:triage]}
- {org: payments, role: runbook-editor, subjects: [group:sre]}
Rule key Description
verbs the operation name after the dot (ask for agent.ask), or "*"
kinds agent, ceiling, connection, deployment, mcp_server, notify_target, provider, secret, token, or "*"
names exact resources: agents by name, others by ID; default: all
Binding key Description
org the org it applies in, deployment for the deployment's own resources, or "*" for every org and the deployment
role a role from roles, or operator
subjects user:ORG/@NAME, group:NAME, or agent:NAME for that agent in the binding's org (in deployment, the deployment's own org)
  • The built-in admin role permits all operations on all resources. The CLI’s user:admin has this role across all organizations. It cannot be redefined.
  • The built-in operator role permits all operations on all resource types within its binding’s scope, unless overridden in roles.
  • Tokens aren't in an org, so only a binding in "*" applies to token.

Owners, agents, chat members and errors follow built-in rules.

Set defaults for omitted agent settings. Accepts any agent configuration field, such as model, tools, policy, or retries.

models:
prices:
zai:glm-5.1: {input: 0.60, output: 2.20}
zai_coding_plan:glm-5.1: {priced_as: zai:glm-5.1, markup: 0.1}
options: {temperature: 0.2, receive_timeout: 600000}
gateway:
fallbacks: {anthropic:claude-sonnet-4-5: [openai:gpt-5]}
limits: {anthropic: {requests_per_minute: 4000, tokens_per_minute: 400000}}
Key Default Description
prices {} prices for models not in the catalog, in dollars per million tokens
options {} options passed to ReqLLM for every model call
gateway breakers only fallbacks, limits and breakers every model call goes through; see Model gateway
  • A price takes input, output, cache_read, cache_write, or priced_as another model; each with an optional markup.
  • options accepts settings supported by ReqLLM, such as base_url. Timeouts are in milliseconds. Agent-level model_options override these defaults.
  • wardrik reload applies changes to all of them.
mcp:
github:
url: https://api.githubcopilot.com/mcp/
credential: github
only: [list_commits, get_commit]
notes:
command: npx
args: [-y, notes-mcp]
timeout: 30
Key Description
url, headers a Streamable HTTP endpoint, used as given
command, args, env a program run over stdio; not with url
only, except tool names to include or exclude
prefix the tool name prefix; default: the server's name
credential the secret or connected account name used for each owner
credential_header, credential_scheme default authorization and Bearer
credential_env the environment variable for a command server's credential
timeout a call's limit in seconds; default 60
max_result_bytes maximum result size sent to the model; default 131072
cost each call's cost, as {usd: 0.001}
gated tools that need approval: true, false, or globs; default: tools not marked read-only
trusted true disables the outside label on its results

Agents reference a server's tools as github/*. Orgs and users add their own with wardrik server add.

harnesses:
claude:
command: claude-agent-acp
env: {ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY}"}
meta: {claudeCode: {options: {settingSources: []}}}
options: {mode: default}
context: [CLAUDE.md, AGENTS.md]
timeout: 1800
Key Description
command, args the coding agent, run over stdio in each worktree
env environment variables; it also gets HOME, PATH and a few basics
meta sent as _meta when a session starts
options session config options by category or ID, such as {mode: default, model: opus}
instructions text added to every session's instructions
context files in the repository added to the instructions, when present
description what the calling model reads about the tool
timeout a call's limit in seconds; default 1800
idle seconds the coding agent runs with no call; default 900

Each harness is a tool of the same name. Its requests are calls named by ACP kind, as claude/execute. See Connect coding agents.

checkouts:
demo: ~/acp-demo
core: {path: ~/src/core, base: origin/main, fetch: true}
Key Description
path the repository; a path alone is {path: ...}
base the ref new branches start from, and sweeps compare with; default HEAD
fetch true runs git fetch before each new branch and each sweep; default false

Worktrees go in worktrees/ in WARDRIK_DATA_HOME. A daily sweep removes each one whose work is in base.

rest:
ga4:
discovery: https://analyticsdata.googleapis.com/$discovery/rest?version=v1beta
base_url: https://analyticsdata.googleapis.com/
auth: {oauth2: {credential: google}}
only: [properties_runReport, properties_getMetadata]
read_only: [properties_runReport]
github:
openapi: https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json
base_url: https://api.github.com
schemes: {token: bearer}
auth: {token: {credential: github}}
only: [issues_*, pulls_list]
Key Description
discovery a Google Discovery document: its URL, or its path from the config directory
openapi an OpenAPI 3 document, in JSON or YAML: its URL, or its path from the config directory; an API has discovery or openapi
base_url where calls go; secrets are sent only here
auth a source for each scheme the description names: {credential: NAME} or {key: NAME}
headers headers every call sends, each a source or a string
schemes schemes the description doesn't name, each bearer, {header: NAME} or {query: NAME}, sent on every operation before its own; auth gives each a source
argument_headers headers each tool takes as optional arguments, by name with what they're for, as {login-customer-id: The manager account's ID}
only operations to offer, by name or glob; default: all it can sign in to
read_only operations that change nothing, beyond GETs
idempotent operations safe to repeat, beyond GET, PUT and DELETE
timeout a call's limit in seconds; default 30
max_result_bytes maximum answer size sent to the model, as JSON; default 131072
max_schema_bytes each tool's schema size, as JSON, where it can be; deeper objects are named instead, and NAME__describe gives their fields; default 16384
trusted true disables the outside label on its results

Each API is a tool group of the same name: an agent file lists tools: [ga4] and gets one tool per operation, as ga4__properties_runReport. Each tool definition goes into every model call, so list only the operations agents need. An operation only a glob names is left out where its tool name would be over 64 characters.

  • {credential: NAME} is the signed-in account of the person the agent acts for, from the oauth provider NAME or an app added for it. Until they sign in, the call waits.
  • {key: NAME} is a key in the vault, sealed with wardrik vault put NAME --for api_key for the agent's owner, its org or the deployment.
  • Operations that aren't read-only need approval unless a policy allows them.
  • A description that can't be read is logged and read again each minute. Until then, its API offers no tools.
oauth:
client_name: Acme agents
providers:
github:
issuer: https://github.com/login/oauth
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
scopes: [repo]
flow: device
  • A provider's name is the credential name it supplies.
  • Provider keys: issuer, resource, authorization_endpoint, token_endpoint, client_id, client_secret, client_auth (post or basic), scopes, flow (browser or device) and authorization_params.
  • With oauth set, orgs and users can add their own OAuth apps, even without providers.
  • Browser sign-ins redirect to {base_url}/oauth/callback.
channels:
slack:
type: slack
token: ${SLACK_BOT_TOKEN}
app_token: ${SLACK_APP_TOKEN}
domains: {acme.com: acme}
members: {U0G9QF9C6: user:acme/@jon}
Key Description
type required; slack
token the bot token; without it, one token per workspace is stored in the vault
signing_secret verifies Slack's requests at /v1/channels/NAME/
app_token receives events over Socket Mode instead
client_id, client_secret, redirect_uri for a Slack app installed in many workspaces
domains email domain to org; [email protected] acts as user:acme/@ana
members member ID to user; wins over domains
offering, deciding messages for a room with no agent, and for a member who can't approve
  • The name is lower-case letters, digits and -. shell, ssh, terminal and oauth are reserved.
  • Members without a domains or members mapping receive an access-denied message.
  • An agent is available in a channel if its definition's channels lists it.

See Slack.

notify:
retries: {attempts: 5, max_wait: 30000}
targets:
ops: {channel: slack, room: "#ops"}
audit: {webhook: {url: https://hooks.example.com/wardrik, secret: "${WEBHOOK_SECRET}"}}
  • A target is a room (channel, room) or a webhook (url, secret).
  • A target name can't contain :.
  • retries sets notice retries; default {attempts: 3, max_wait: 10000}.
  • Orgs and users add their own webhooks over the HTTP API.
workspace:
shared:
agent:runbooks:
read: [agent:triage, agent:oncall]
write: [agent:ops]

shared lists the agents whose workspaces can be mounted, each with the agents allowed to read and write it. Each is agent:NAME, in the mounting agent's org.

Key Default Description
port 4747 the port
ip 127.0.0.1 the listen address; default: WARDRIK_HTTP_IP
trusted_workers false true disables the outside label on tool worker results
Key Default Description
enabled true false turns off the dashboard at /web
storage:
postgres:
url: postgres://wardrik:${PGPASSWORD}@db.internal:5432/wardrik
# or
storage:
s3:
bucket: wardrik
endpoint: https://<account>.r2.cloudflarestorage.com
region: auto
access_key_id: ${S3_ACCESS_KEY_ID}
secret_access_key: ${S3_SECRET_ACCESS_KEY}
s3 key Default Meaning
bucket required the bucket, which must exist
endpoint required the service's URL; requests are path-style
access_key_id, secret_access_key required the key
region us-east-1 as the service names it
session_token none for temporary credentials
prefix wardrik object key prefix within the bucket
headers {} sent with every request

Configure either postgres or s3. Without storage, the store is on disk in WARDRIK_DATA_DIR. See Storage.

cluster:
nodes: [a, b, c]
Key Description
nodes short names for nodes on one machine, or full names, one per machine
dns a name whose A and AAAA records are the nodes, as wardrik@ADDRESS
size the number of nodes, with dns

cluster is read as the daemon starts. See Run a cluster.

agents:
max_per_node: 5000
max_memory: 80
max_cpu: 90
hibernate_after: 60
Key Default Description
max_per_node none agents and conversations a node runs
max_memory none percent of the machine's memory above which a node takes no new agents
max_cpu none percent of its CPU above which a node takes no new agents
hibernate_after none seconds idle before an agent compacts its memory

New agents start on the node with the most available capacity. See Spread agents.

Variable Default Contents
WARDRIK_CONFIG_DIR ~/.config/wardrik config.yaml, agents/, policies/
WARDRIK_DATA_DIR ~/.local/share/wardrik/store the store
WARDRIK_DATA_HOME ~/.local/share/wardrik vault_key, cli_token, worktrees/
WARDRIK_STATE_DIR ~/.local/state/wardrik logs
WARDRIK_ENV_FILE env in the config directory extra environment variables
WARDRIK_NODE none which node of a cluster this is

The defaults follow XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME.

~/.config/wardrik/env
ANTHROPIC_API_KEY=sk-ant-...
export SLACK_BOT_TOKEN="xoxb-..."