Scripting and automation

Scripting HotDog CMS

Everything HotDog does is a command, so anything you do by hand can be done by a script: making sites, changing them, checking them and publishing them.

hotdog-cms is built to be scripted. Every job is a command with predictable options, output you can read, and an exit code a script can test. That makes it easy to automate the jobs you do often, and to do them to many sites at once.

You'll need to be comfortable writing small shell scripts (bash on Linux and macOS, or PowerShell on Windows). The examples use bash.

What a script can rely on

Exit codes. Every command ends with 0 when it worked and 1 when it didn't, so a script can stop or carry on:

Command Exits with 1 when…
hotdog-cms check the site has errors (warnings alone exit with 0)
hotdog-cms build the site can't be built: a mistake in site.yaml, a template or a page
hotdog-cms publish the build fails, the checks find errors, or a target fails
hotdog-cms new the folder already exists
hotdog-cms import … the old site or file can't be read

Note that build alone doesn't run the checks: a site with broken links still builds. Use check (or publish, which checks) to stop on problems.

-site instead of cd. Most commands take -site DIR, so a script can work on a site without changing folder:

hotdog-cms check -site ~/sites/bakery
hotdog-cms build -site ~/sites/bakery -out /tmp/bakery-build

Secrets from the environment. Passwords and tokens are never options, so they don't end up in scripts or shell history: HOTDOG_GIT_TOKEN, HOTDOG_WP_PASSWORD and the others are read from the environment. See the command reference.

Make a site from a script

#!/usr/bin/env bash
# new-site.sh <folder> "<Name>" <https://address>
set -euo pipefail
folder=$1 name=$2 url=$3

hotdog-cms new -name "$name" "$folder"
sed -i "s#^url: .*#url: $url#" "$folder/site.yaml"

git -C "$folder" init -q -b main
git -C "$folder" add .
git -C "$folder" commit -q -m "Start $name from the HotDog template"
hotdog-cms check -site "$folder"
./new-site.sh florist "Petals on Main" https://petalsonmain.example

set -euo pipefail makes the script stop at the first command that fails, so it never carries on with a half-made site. (On macOS, sed -i needs an empty '' after it: sed -i '' "s#…#…#".)

Change a site from a script

Pages and settings are text files, so any tool that edits text can change them: sed for a simple replacement, yq for YAML settings, or a small program in any language.

# Add a news post
cat > ~/sites/bakery/content/articles/holiday-hours.md <<'POST'
---
title: Holiday hours
date: 2026-12-20
summary: We close at 2pm on the 24th and reopen on the 27th.
tags: [Opening hours]
---

We close at 2pm on December 24th, and we're back on the 27th.
POST

# Change a setting
sed -i 's#^timezone: .*#timezone: America/Chicago#' ~/sites/bakery/site.yaml

hotdog-cms check -site ~/sites/bakery

Always finish with hotdog-cms check: it catches what a script got wrong before anyone sees it.

Changes worth reviewing: use a branch

A script that changes a live site should work like the editor does: on a branch, so the change can be looked at before it's published:

git -C ~/sites/bakery switch -c news/holiday-hours
# … make the change …
hotdog-cms check -site ~/sites/bakery
git -C ~/sites/bakery add -A
git -C ~/sites/bakery commit -m "News: holiday hours"
git -C ~/sites/bakery push -u origin news/holiday-hours

Then open a pull request on your platform (most have a command-line tool for it), or open the branch in the editor and choose Submit for review. A preview shows it exactly as it'll look, and your pipeline checks it again.

Publish from a script

hotdog-cms publish -site ~/sites/bakery server

Or let your platform publish when a branch is merged: see Your platform's pipeline.

Next

Many sites at once takes these same steps across every site you look after.