All playbooks
Playbook 4 of 6

Sync templates on every deploy

A sync task parses templates/ and layouts.yml, then posts everything to Messy's /sync endpoint in a single transaction. Wire it into CI and your templates deploy with your code.

15 min You ship: messy:sync and messy:validate tasks, plus a CI step per environment.
1

Build the sync command

The /sync endpoint upserts layouts, folders and templates in one transaction. If anything in the payload is invalid, nothing is saved, so a broken template can never half-deploy.

01 · sync command
Build a sync command for our Messy templates, using this project's native task runner (rake task, npm script, make target, management command; match the repo).

messy:sync must:
1. Parse templates/layouts.yml into a list of {name, body, transformers} layout objects.
2. Glob templates/**/*.md. For each file, split on lines containing only === (multiple templates per file), then split each section into YAML frontmatter and markdown body on the --- delimiters. Collect {trigger, channel (default "email"), name, subject, preview, body_format (default "markdown"), layout, body}, and set folder to the file's directory path relative to templates/, slashes preserved (Messy creates nested folders from it).
3. Preprocess: replace every occurrence of {{base_url}} in layout and template bodies with the APP_URL environment variable, so links resolve correctly per environment.
4. POST the whole set to <MESSY_API_URL>/sync as one JSON payload:
   {"purge": false, "layouts": [...], "templates": [...]}
   with the usual Bearer MESSY_API_KEY header. Templates upsert by (trigger, channel), so the call is idempotent. It is also all-or-nothing: on any validation error Messy rolls back everything and returns 422 with an errors array. Print the created/updated counts from the response, or the errors.
5. Add a purge variant (messy:sync_purge) that sets "purge": true, deleting templates, layouts and folders in Messy that are absent from the payload. Never make purge the default.

Also add messy:validate: parse everything locally and check each template has trigger, name, channel and body, and that any referenced layout exists in layouts.yml. No API call. Exit nonzero on problems, printing the file and the missing field.
2

Wire it into CI

Validation runs on every pull request; the real sync runs on deploy, once per environment. After this, editing an email is a normal code change: branch, review, merge, deployed.

The API key selects the Messy environment. Your test key syncs to the test environment, your production key to production. Double-check which key each CI stage uses, or template edits quietly land in the wrong place.
02 · ci wiring
Wire the Messy template sync into this repo's CI/CD pipeline (inspect the existing pipeline config and match its style).

- On every pull request or merge request: run messy:validate. It needs no secrets and fails fast on malformed templates.
- On deploy to each environment: run messy:sync with that environment's MESSY_API_KEY and that environment's public APP_URL, after the app deploy step succeeds.
- Add the keys as CI secrets, never in the repo. One secret per environment.
- Log the sync response counts in the job output so every deploy shows what changed in Messy.