Skip to main content

Husky configuration reference

This document is the authoritative reference for both configuration files used by Husky:

  • husky.yaml — job definitions and product behavior
  • huskyd.yaml — daemon runtime behavior

1. husky.yaml

husky.yaml is the source of truth for scheduled jobs, pipelines, retries, notifications, tags, healthchecks, outputs, and timezone-aware execution.

Top-level structure

version: "1"
defaults: {}
integrations: {}
jobs: {}

version

  • required
  • currently only "1" is valid

defaults

Values under defaults are applied to jobs that do not override them.

Supported fields:

FieldTypeNotes
timeoutduration stringe.g. 30m, 1h, 90s
retriesintegerinherited when a job does not set retries
retry_delaystringexponential or fixed:<duration>
notify_on_failurebooleanlegacy compatibility field
on_failurestringalert, skip, stop, ignore
default_run_timeHHMM stringfallback time for weekly, weekdays, weekends, and on:[...] jobs that omit time; built-in default is 0300
timezoneIANA timezonefallback for jobs without their own timezone

integrations

Defines named notification integrations. Keys may be provider names or arbitrary names when provider is set explicitly.

Supported providers today:

  • slack
  • discord
  • webhook
  • pagerduty
  • smtp

Provider fields:

FieldUsed byNotes
provideralloptional when inferred from the map key
webhook_urlslack, discord, webhookrequired for those providers
routing_keypagerdutyrequired
hostsmtprequired
portsmtpdefaults to 587 when unset
usernamesmtpoptional
passwordsmtpoptional
fromsmtprequired

Environment interpolation is supported in integration fields via ${env:VAR}.

jobs

Each key in jobs: becomes a job name.

jobs:
my_job:
description: "What the job does"
frequency: daily
time: "0200"
command: "./scripts/run.sh"

Job fields

Required fields

FieldTypeDescription
descriptionstringhuman-readable purpose of the job
frequencystringscheduling mode
commandstringshell command to execute

Scheduling fields

FieldTypeDescription
frequencystringhourly, daily, weekly, monthly, weekdays, weekends, manual, after:<job>, every:<interval>, or on:[day[,day...]]
timeHHMM stringrequired for daily and monthly; optional for weekly, weekdays, weekends, and on:[...]
timezoneIANA timezone stringper-job timezone; falls back to defaults.timezone, then system timezone
catchupbooleanrun missed scheduled jobs after daemon restart

Notes:

  • time is ignored for manual, hourly, every:<interval>, and after:<job> frequencies
  • every:<interval> accepts Go duration syntax such as every:15s, every:15m, or every:2h; intervals must be positive and less than 24 hours
  • on:[...] accepts full weekday names such as on:[monday,friday]
  • weekly means every Monday and is an alias for on:[monday]
  • weekdays is an alias for on:[monday,tuesday,wednesday,thursday,friday]
  • weekends is an alias for on:[saturday,sunday]
  • when weekly, weekdays, weekends, or on:[...] omits time, Husky uses defaults.default_run_time or the built-in default of 0300
  • monthly means the 1st day of each month at the configured time
  • frequency is still a closed set in v1: Husky does not accept cron expressions or parameterized calendar rules such as last_day_of_month
  • timezone validation uses embedded tzdata, so Husky does not depend on system tzdata being present
  • DST gaps and overlaps are handled explicitly by the scheduler

DAG and orchestration fields

FieldTypeDescription
depends_onlist of job namesexplicit upstream dependencies
frequency: after:<job>stringimplicit dependency edge plus dependency-triggered execution
concurrencystringallow, forbid, or replace
working_dirstringworking directory for subprocess execution

Dependency rules:

  • the graph must be acyclic
  • cycles are rejected at startup and reload time
  • downstream jobs only dispatch after upstream success

Reliability fields

FieldTypeDescription
timeoutduration stringhard runtime limit
retriesintegerretry count
retry_delaystringexponential or fixed:<duration>
on_failurestringalert, skip, stop, ignore
sladuration stringinformational runtime budget; must be less than timeout when both are set

Behavior notes:

  • timeout kills the process group after graceful termination attempts
  • sla does not kill a job; it marks the run and fires notifications while the job continues
  • on_failure: stop halts the pipeline by preventing downstream continuation after terminal failure

Environment fields

FieldTypeDescription
envmap of string to stringper-job environment values

Environment values may use ${env:HOST_VAR} interpolation.

The executor environment precedence is:

  1. host environment
  2. daemon executor.global_env from huskyd.yaml
  3. per-job env

Tags

FieldTypeDescription
tagslist of stringslabels for filtering and bulk operations

Tag constraints:

  • lowercase alphanumeric plus hyphen
  • max 10 tags per job
  • max 32 characters per tag

Notifications

notify supports four lifecycle hooks:

  • on_failure
  • on_success
  • on_sla_breach
  • on_retry

Each hook accepts either shorthand or object form.

Shorthand:

notify:
on_failure: slack:#ops

Object form:

notify:
on_success:
channel: webhook:https://example.test/hook
message: "job={{ job.name }} status={{ run.status }}"
attach_logs: last_30_lines
only_after_failure: true

NotifyEvent fields:

FieldTypeMeaning
channelstringdestination in <provider>:<target> form
messagestringtemplated message
attach_logsstringnone, all, or last_<N>_lines
only_after_failurebooleanonly meaningful on on_success

See notifications.md for behavior details.

Healthchecks

healthcheck:
command: "curl -fsS http://127.0.0.1:8080/ready"
timeout: "30s"
on_fail: mark_failed

Fields:

FieldTypeMeaning
commandstringcommand to execute after a successful main command
timeoutduration stringhealthcheck timeout; defaults to 30s
on_failstringmark_failed or warn_only

Behavior:

  • healthchecks only run if the main job exits successfully
  • mark_failed converts the run into a failure and can trigger retries
  • warn_only keeps the run successful but sets hc_status=warn

Output capture

output:
file_path: last_line
record_count: json_field:total
version: regex:v([0-9.]+)
exit_status: exit_code

Supported capture modes:

ModeMeaning
last_linefinal non-empty stdout line
first_linefirst stdout line
json_field:<key>parse stdout as JSON and extract key
regex:<pattern>capture regex match group from stdout
exit_codecapture numeric exit code

See output-passing.md for full details.

Example husky.yaml

version: "1"
defaults:
timeout: "30m"
retries: 2
retry_delay: exponential
timezone: "America/New_York"

integrations:
slack:
webhook_url: "${env:SLACK_WEBHOOK_URL}"
pagerduty:
routing_key: "${env:PAGERDUTY_ROUTING_KEY}"

jobs:
ingest:
description: "Download source data"
frequency: on:[monday,tuesday,wednesday,thursday,friday]
time: "0200"
command: "./scripts/ingest.sh"
output:
file_path: last_line
notify:
on_failure: slack:#ops

transform:
description: "Transform the ingested file"
frequency: after:ingest
command: "python transform.py --input {{ outputs.ingest.file_path }}"
timeout: "20m"
sla: "10m"
on_failure: stop
healthcheck:
command: "python verify.py"
timeout: "30s"
on_fail: mark_failed
tags: ["etl", "release"]

2. huskyd.yaml

huskyd.yaml configures the daemon process itself.

Top-level sections

SectionPurpose
apibind address, base path, TLS, CORS, timeouts
authauth type and RBAC
logstructured logging and audit log
storageSQLite path and retention
schedulerconcurrency limits, catchup window, shutdown timeout, jitter
executorpool size, shell, working directory, resource limits, global env
metricsmetrics endpoint surface
tracingtracing surface
secretssecrets backend surface
alertsdaemon-level notifications
dashboarddashboard runtime customisation
http_clientoutbound HTTP client behavior
processPID file and process-level settings

api

FieldTypeMeaning
addrstringbind address, e.g. 127.0.0.1:8420
base_pathstringURL prefix like /husky
tls.enabledbooleanenable HTTPS
tls.cert / tls.keystringPEM files required when TLS enabled
tls.min_versionstring1.2 or 1.3
tls.client_castringoptional mutual TLS CA bundle
cors.allowed_originslistCORS allowlist
cors.allow_credentialsbooleanallow credentialed CORS
timeouts.*duration stringsHTTP server read/write/idle timeouts

auth

FieldTypeMeaning
typestringnone, bearer, basic, oidc
bearer.token_filestringtoken file, hot-reloaded on SIGHUP
bearer.tokenstringinline token, supported but less preferred
basic.userslistusername / bcrypt hash entries
oidc.*objectdeclared config surface; not implemented yet
rbaclistexplicit per-role route grants

log

FieldTypeMeaning
levelstringdebug, info, warn, error
formatstringtext or json
outputstringstdout, stderr, file
file.*objectfile rotation config
audit_log.*objectseparate audit log file

storage

FieldTypeMeaning
enginestringcurrently only sqlite is supported
sqlite.pathstringDB path override
sqlite.wal_autocheckpointintegerSQLite pragma
sqlite.busy_timeoutduration stringSQLite busy timeout
retention.max_ageduration stringdelete completed runs older than this
retention.max_runs_per_jobintegercap completed history per job

scheduler

FieldTypeMeaning
max_concurrent_jobsintegerglobal semaphore ceiling
catchup_windowduration stringmax age for catchup-triggered missed schedules
shutdown_timeoutduration stringgraceful drain timeout
schedule_jitterduration stringper-trigger jitter to reduce bursts

executor

FieldTypeMeaning
pool_sizeintegerbounded worker pool size
shellstringshell path used for commands
working_dirstringdaemon-wide working-dir override
resource_limits.*objectprocess resource settings
global_envmapenvironment injected into every job

alerts

Daemon-level notification hooks:

  • on_daemon_start
  • on_sla_breach
  • on_forced_kill

These are distinct from per-job notify settings.

dashboard

FieldTypeMeaning
enabledbooleandisable dashboard while keeping API surface
titlestringdashboard title override
accent_colorstringvisual theme value
log_backfill_linesintegerhistorical lines sent before live stream
poll_intervalduration stringclient polling cadence

http_client

Controls outbound HTTP used by notifications and other integrations.

FieldType
timeoutduration string
max_retriesinteger
retry_backoffduration string
proxystring
ca_bundlestring

process

FieldTypeNotes
user / groupstringfuture-facing / platform-dependent process identity settings
pid_filestringPID file override
ulimit_nofileintegerprocess file descriptor limit
watchdog_intervalduration stringsystemd-style watchdog support surface

3. Defaults and validation notes

Important validation rules

  • version must be "1"
  • DAGs must be acyclic
  • time must be zero-padded HHMM
  • timezone must resolve as an IANA timezone
  • sla must be less than timeout when both are set
  • tags must follow the lowercase/hyphen format constraints
  • retry_delay must be exponential or fixed:<duration>
  • concurrency must be allow, forbid, or replace
  • on_failure must be alert, skip, stop, or ignore
  • huskyd.yaml auth type must be one of none, bearer, basic, oidc
  • huskyd.yaml storage engine is currently limited to sqlite

What is declared but not fully implemented

Husky accepts some future-facing daemon config sections today, but not every declared field is fully wired into the runtime yet. In particular:

  • OIDC auth is declared but rejected at startup
  • Postgres storage is declared but rejected at startup
  • some metrics, tracing, secrets, and process-level fields are currently schema/default surface rather than deeply wired operational features

4. Validation commands

Validate config:

husky validate
husky validate --strict

Show effective config:

husky config show

Strict mode adds warnings for documentation/operability issues such as missing descriptions and missing notify configs.