Just a heads up (though I’m sure many have already tried this) but Claude Code + Hugo seems to work very well. I instantiated a Claude Code instance in my (quite old) hugo repo, and was able to build out some functionality that I’ve wanted for a while, but couldn’t be bothered to debug into production.
For example, claude helped me whack together auto-generated galleries (dumping images in a folder /low /high and having them auto-build a page around that folder and work properly with the excellent photoswipe library (parsing heights and widths of the images properly, for example). Pasting the relevant code below.
I knew Hugo was capable of things like this, but the technical specifics were beyond my patience. Really nice to be able to plug into Hugo’s advanced low-level operating parameters which staying at a relatively “high level” abstraction.
<div class="photogallery">
{{ $galleryName := path.Base .File.Dir }}
{{ if eq $galleryName "misc" }}
{{ $galleryName = .File.ContentBaseName }}
{{ end }}
{{ $imageCount := 0 }}
<!-- Find all jpg images in the content folder -->
{{ $contentPath := printf "content/misc/%s" $galleryName }}
{{ $files := slice }}
<!-- Function to check if a path has image file extension -->
{{ $isImageFile := (slice ".jpg" ".jpeg" ".png" ".gif" ".webp") }}
<!-- Get all files in the directory -->
{{ range (readDir $contentPath) }}
{{ $file := . }}
{{ $fileExt := path.Ext $file.Name | lower }}
<!-- Only include files with image extensions and skip index.md -->
{{ if and (ne $file.Name "index.md") (in $isImageFile $fileExt) }}
{{ $files = $files | append $file }}
{{ $imageCount = add $imageCount 1 }}
{{ end }}
{{ end }}
<!-- Sort files by name to maintain consistent order -->
{{ $sortedFiles := sort $files "Name" }}
<!-- Display all images in the gallery -->
{{ range $index, $file := $sortedFiles }}
{{ $fileName := $file.Name }}
{{ $highResPath := printf "/misc/%s/%s" $galleryName $fileName }}
{{ $lowResPath := printf "/misc/%s/low/%s" $galleryName $fileName }}
{{ $highResContent := printf "content/misc/%s/%s" $galleryName $fileName }}
<!-- Check if low-res version exists -->
{{ $lowResExists := fileExists (printf "content/misc/%s/low/%s" $galleryName $fileName) }}
{{ $displayPath := $highResPath }}
{{ if $lowResExists }}
{{ $displayPath = $lowResPath }}
{{ end }}
<!-- Get image dimensions at build time if possible -->
{{ $width := 0 }}
{{ $height := 0 }}
{{ $ratio := 1.0 }}
{{ $colSpan := 1 }}
{{ $rowSpan := 1 }}
{{ if eq (path.Ext $fileName | lower) ".jpg" }}
{{ with (imageConfig $highResContent) }}
{{ $width = .Width }}
{{ $height = .Height }}
{{ $ratio := 1.0 }}
{{ if gt .Height 0 }}
{{ $ratio = div (float .Width) (float .Height) }}
{{ end }}
<!-- Wide panoramic images -->
{{ if gt $ratio 1.8 }}
{{ $colSpan = 2 }}
{{ end }}
<!-- Very tall images -->
{{ if lt $ratio 0.6 }}
{{ $rowSpan = 2 }}
{{ end }}
{{ end }}
{{ end }}
<!-- Create a human-readable caption from filename -->
{{ $caption := $fileName }}
{{ $caption = replace $caption ".jpg" "" }}
{{ $caption = replace $caption ".jpeg" "" }}
{{ $caption = replace $caption ".png" "" }}
{{ $caption = replace $caption ".gif" "" }}
{{ $caption = replace $caption ".webp" "" }}
{{ $caption = replace $caption "-" " " }}
{{ $caption = replace $caption "_" " " }}
<div class="gallery-item-container"
style="{{ if gt $colSpan 1 }}grid-column: span {{ $colSpan }};{{ end }}{{ if gt $rowSpan 1 }}grid-row: span {{ $rowSpan }};{{ end }}">
<a href="{{ $highResPath }}"
class="gallery-item"
data-gallery-index="{{ add $index 1 }}"
data-pswp-caption="{{ $caption }}"
data-pswp-width="{{ $width }}"
data-pswp-height="{{ $height }}"
data-src="{{ $highResPath }}">
<img src="{{ $displayPath }}"
alt="{{ $caption }}"
loading="lazy" />
</a>
</div>
{{ end }}
{{ if eq $imageCount 0 }}
<p>No images found in this gallery.</p>
{{ end }}
</div>
</div>