Manifest reference

Complete field reference for the SteadyCron v2 YAML manifest — jobs, channels, rules, variables, tags, and namespaces.

The v2 manifest is the authoritative definition of your SteadyCron account. A single file (or a directory of files) declares every job, alert channel, tag, and variable the CLI manages.

Top-level structure

namespace: my-app        # optional — scopes IaC ownership
variables:               # server-side template variables (list of objects)
channels:                # alert channel definitions
tags:                    # reusable tag definitions
shaping:                 # rate-limit hints
jobs:                    # HTTP jobs and heartbeat checks
                         # alert rules are declared per job under jobs[].rules

namespace

A string that scopes all resources in this manifest. The CLI only manages (and with --prune, only deletes) resources that belong to this namespace — so IaC-managed jobs and manually created jobs can coexist safely in the same account.

namespace: production

Omitting namespace uses the default namespace. See Namespaces & ownership for multi-environment setups.

jobs[]

Each entry is either an HTTP job (kind: http) that calls your endpoint on a schedule, or a heartbeat check (kind: heartbeat) that expects a ping from your own cron.

Common fields

FieldTypeRequiredDescription
idstringNoStable reconciliation key. When set, renames are safe — the id never changes, so heartbeat ping URLs are preserved. Falls back to name when absent.
namestringYesDisplay name shown in the dashboard and alert messages. Must be unique within the manifest.
kindhttp | heartbeatNoJob type. Defaults to http.
schedulestringYes*Five-field cron expression (minute hour dom month dow).
intervalintegerYes*Fixed interval in seconds (10–86400). Alternative to schedule.
timezonestringNoIANA timezone name, e.g. Europe/Berlin. Defaults to UTC.
pausedbooleanNoCreate or keep the job in a paused state.
tagsstring[]NoTag references as "key:value" strings, e.g. ["env:prod", "team:backend"].
rulesobject[]NoPer-job alert rules. See Alert rules.

*Exactly one of schedule or interval is required.

HTTP job fields

FieldTypeRequiredDescription
methodstringNoHTTP method. One of GET, POST, PUT, PATCH, DELETE. Defaults to GET.
urlstringYesEndpoint to call. Supports ${ENV} (CLI substitution) and {{template_var}} (server-side) placeholders.
headersobjectNoAdditional request headers. Values support ${ENV} placeholders.
bodystringNoRequest body. Supports {{template_var}} placeholders.
timeoutintegerNoRequest timeout in seconds. Defaults to 60.
retriesintegerNoNumber of retries on non-2xx response or timeout. Defaults to 0.
retry_backoffintegerNoSeconds between retries. Defaults to 30.
retry_on_timeoutbooleanNoCount timeouts as failures for retry purposes. Defaults to true.
retry_on_statusinteger[]NoHTTP status codes that trigger a retry (100–599).
skip_if_runningbooleanNoSkip execution if the previous run is still active. Defaults to false.
misfire_policystringNoBehavior when a scheduled fire is missed: do_nothing (default) or fire_once_now.

Heartbeat check fields

FieldTypeRequiredDescription
graceintegerNoSeconds to wait after the expected ping time before alerting. Defaults to 60.
stuck_run_detectionbooleanNoAlert when a run exceeds max_run_duration. Defaults to true.
max_run_durationintegerNoMaximum allowed run duration in seconds (60–86400).

channels[]

Alert channels referenced by job rules via their id or name.

FieldTypeRequiredDescription
idstringNoStable reference key used in jobs[].rules[].channel.
namestringYesHuman-readable name shown in the dashboard and alert messages.
kindstringYesOne of slack, discord, email, telegram, webhook.
configobjectNoKind-specific key-value configuration. Use ${ENV} placeholders — never commit real secrets.
channels:
  - id: ops-slack
    name: Slack #ops
    kind: slack
    config:
      webhook_url: ${SLACK_WEBHOOK_URL}

Alert rules {#alert-rules}

Alert rules are defined per job under jobs[].rules. Each rule binds a trigger event to a notification channel.

jobs:
  - id: weekly-digest
    name: Weekly digest email
    kind: http
    schedule: "0 9 * * 1"
    url: https://api.myapp.com/jobs/digest
    rules:
      - channel: ops-slack
        trigger: on_failure
        severity: p1
      - channel: ops-slack
        trigger: on_recovery
FieldTypeRequiredDescription
channelstringYesChannel id or name to notify.
triggerstringYesEvent that fires the rule: on_failure, on_recovery, on_missed_heartbeat.
severitystringNoSeverity label forwarded to the channel (e.g. p1, p2, p3).
paramsobjectNoTrigger-specific parameters.
dedup_window_secondsintegerNoAlert deduplication window in seconds.

tags[]

Tags group jobs in the dashboard. Each tag has a key and value; jobs reference them as "key:value" strings.

tags:
  - id: env-prod
    key: env
    value: prod
  - id: team-backend
    key: team
    value: backend

Job reference: tags: ["env:prod", "team:backend"]

FieldTypeRequiredDescription
idstringNoStable reference key.
keystringYesTag category (e.g. env, team).
valuestringYesTag value (e.g. prod, backend).
colorstringNoHex color code for the dashboard.

variables

Server-side template variables. Each variable is an object with id, name, and value. The CLI resolves ${ENV_VAR} in value at apply time; the server substitutes {{name}} in HTTP job fields at execution time. Secrets never end up in git.

variables:
  - id: digest-token
    name: digest_token
    value: ${DIGEST_TOKEN}

Use {{digest_token}} in HTTP url, headers, or body fields.

FieldTypeRequiredDescription
idstringNoStable reference key.
namestringYesVariable name used in {{name}} server-side substitutions.
valuestringNoVariable value. Supports ${ENV_VAR} CLI substitution.

shaping

Request shaping controls concurrency and rate limits for HTTP jobs — useful when many jobs fire at the same minute and you need to spread load.

shaping:
  max_concurrent_jobs: 5
  max_jobs_per_minute: 30
FieldTypeDescription
max_concurrent_jobsintegerMaximum number of HTTP jobs running in parallel.
max_jobs_per_minuteintegerMaximum HTTP job executions per minute.

Complete example

namespace: production

variables:
  - id: digest-token
    name: digest_token
    value: ${DIGEST_TOKEN}

channels:
  - id: ops-slack
    name: Slack #ops
    kind: slack
    config:
      webhook_url: ${SLACK_WEBHOOK_URL}

tags:
  - id: env-prod
    key: env
    value: prod
  - id: team-backend
    key: team
    value: backend

jobs:
  - id: weekly-digest
    name: Weekly digest email
    kind: http
    method: POST
    url: https://api.myapp.com/jobs/digest
    schedule: "0 9 * * 1"
    timezone: Europe/Berlin
    timeout: 120
    retries: 3
    tags: ["env:prod", "team:backend"]
    rules:
      - channel: ops-slack
        trigger: on_failure
        severity: p1
      - channel: ops-slack
        trigger: on_recovery

  - id: nightly-backup
    name: Nightly DB backup
    kind: heartbeat
    schedule: "0 2 * * *"
    grace: 1800
    tags: ["env:prod"]
    rules:
      - channel: ops-slack
        trigger: on_missed_heartbeat
        severity: p1

Secrets: two mechanisms, side by side

${ENV_VAR_NAME}{{template_var}}
Resolved byCLI at apply timeServer at execution time
Works inAny fieldHTTP job url, headers, body only
Use forAPI keys, webhook URLs, environment-specific valuesDynamic per-execution values
Exported asPlaceholder ${VAR}Placeholder {{var}}

steadycron export emits both kinds of placeholder wherever it detects a secret or a template variable, so the exported manifest is safe to commit as-is.