Content Agent Guide

Each unit of content lives in its own file. Releases and shows use JSON; blog posts use Markdown. This is deliberate: adding content should never require editing a central index.

Invariants

  • Do not edit legacy/.
  • Do not delete or silently rewrite imported records.
  • Keep IDs stable forever. Generate a new UUID for every new release, track, and show.
  • File names MUST begin with an ISO date or year. Release and show files end in .json; blog files end in .md.
  • Public prose MUST use a single hyphen (-), never an em dash or en dash. Do not alter punctuation inside archival lyrics.
  • Run npm run validate:content after every content change.

Add a show

Create site/content/shows/YYYY-MM-DD-short-name.json:

json
{
  "date": "2026-10-24",
  "location": "Thessaloniki, Greece",
  "venue": "Venue name",
  "eventName": "w/ Other Band",
  "id": "new-uuid-here"
}

Use null for eventName when there is no named event or billing note. Add "hidden": true to preserve a record without publishing it. The site decides whether a visible show is upcoming from its date at build time.

Add a release

Copy the closest file in site/content/releases/. Keep these rules:

  • releaseDate and each track's releaseDate use YYYY-MM-DDT00:00:00.000Z.
  • imageUrl uses ../../assets/img/music/filename.jpg for compatibility with imported records.
  • Put the matching square artwork at site/public/assets/img/music/filename.jpg.
  • links contains imported listening links and MUST remain unchanged for existing releases.
  • Add a current listening or store destination under additionalLinks. The loader combines both arrays for display.
  • Every track needs a title, duration, release date, lyrics, an ID, and a links array. Use "None (Instrumental Track)" for an instrumental.

Add a blog post

Create site/content/blog/YYYY-MM-DD-short-title.md with frontmatter followed by Markdown:

md
---
id: stable-short-id
title: Post title
date: 2026-10-24
author: Sewn Mouth
---

Write the post in **Markdown**.

Use a new stable ID and keep the filename date aligned with date. Raw HTML is rendered as text.

Put uploaded media under site/public/assets/blog/. Images can use normal Markdown or the media directive:

md
![Useful alternative text](/assets/blog/studio.jpg)
@[image](/assets/blog/studio.jpg "Recording at the studio")
@[video](/assets/blog/rehearsal.mp4 "Rehearsal clip")

YouTube and Spotify directives accept their normal share URL. Bandcamp requires the src URL from Bandcamp's embed player:

md
@[youtube](https://www.youtube.com/watch?v=VIDEO_ID "Music video")
@[spotify](https://open.spotify.com/album/ALBUM_ID "Listen on Spotify")
@[bandcamp](https://bandcamp.com/EmbeddedPlayer/album=ALBUM_ID/size=large/ "Listen on Bandcamp")

The optional quoted text is used as the caption and accessible player title. Repository images support AVIF, GIF, JPEG, PNG, and WebP; videos support MP4, OGV, and WebM. Files under site/public/assets/ are managed by Git LFS.

Correct historical data

If a human explicitly requests a correction to imported content, update both the unit file and its matching snapshot in legacy/, explain the correction in the commit message, and run npm run check. Never make this choice autonomously.