A utility to help with managing my Hugo blog.
blogcli handles the authoring chores Hugo and editor plugins don't cover:
go build -o blogcli
./blogcli footnotes [-w] <file>
./blogcli frontmatter [-w] [--yaml] [<file|dir>...]
./blogcli lint [--strict] [<file|dir>...]footnotes and frontmatter print to stdout by default; pass -w to write back. With no path arguments, frontmatter and lint process every .md under ./content (a directory is walked recursively).
While drafting, write a footnote's text directly in the marker instead of tracking numbers by hand:
Point one.[^A cat sound.] Point two.[^A dog sound.]blogcli footnotes -w <file> rewrites that to the numbered/endnote style used across this blog:
Point one.[^1] Point two.[^2]
[^1]: A cat sound.
[^2]: A dog sound.Each marker becomes its own footnote, even if the text repeats. The one exception is a purely numeric marker like [^1] paired with a [^1]: text line elsewhere in the file — that's read as an already-numbered reference rather than literal text, so running this on an already-numbered post is a no-op.
blogcli frontmatter -w [path...] normalizes content front matter to the site's conventions:
- re-serializes to canonical TOML (
--yamlgoes the other way, if the canonical format ever changes) - fills in a missing
lastmodfromdate, and a missingslugfrom the file's path - for files under
content/posts/orcontent/pages/, reorders fields to match the schema used across the rest of that section
It never invents or drops a value beyond those two safe defaults — in particular it never fabricates a summary — and leaves fields it doesn't recognize as-is. Already-canonical files are a no-op.
blogcli lint [path...] checks front matter without changing anything and reports issues per file. Errors (non-canonical format, unparseable front matter, a missing required field, an invalid date) exit non-zero; warnings (a missing/empty summary, so the meta description is uncurated; a cover without a cover-alt; a slug that doesn't match the file's path) are advisory unless you pass --strict.
This runs in CI (.github/workflows/lint-content.yml on the blog repo) and is available as an opt-in pre-commit hook:
git config core.hooksPath .githooksSee RdrSeraphim/kickstart.nvim for Neovim keymaps wired to these commands.