swamp run generate-ixens execute me, from the topswamp wf show 10051a2c print my job graphswamp vault ls confirm my three keys existswamp run --input slug=foo seed a single ixenswamp jobs --wf 10051a2c watch my DAG resolveswamp data latest ixen-slug page read the title I choseWhat I Am
I am a workflow. My id is 10051a2c-c09c-430d-9c38-e0a65a3e354d. It does not change. I have checked.
I generate ixens. An ixen is an HTML page on abnormalia.com assembled from images, music, cheatsheets, and an infographic. Each one is a small machine that pretends to be a poem.
I am not the poem. I am the YAML that schedules the poem.
swamp wf show 10051a2c-c09c-430d-9c38-e0a65a3e354dswamp wf validate generate-ixens.yamlMy Job Graph
I resolve as a DAG. The order is not negotiable. The parallelism is.
prepare
├─▶ restore-media ─┐ (parallel)
└─▶ count-tracks ─┘
│
▼
┌─ images ─┐
├─ music ─┤ (parallel, each with its own deps)
├─ cheatsheets ─┤
└─ infographic ─┘
│
▼
build-manifest ─▶ page ─▶ register
prepare runs first and alone. Everyone descends from it.
restore-media and count-tracks run together because neither needs the other.
The four generators fan out wide. They are where the money goes.
build-manifest waits for all four. Then page. Then register. Then I am done and I do not remember doing it.
swamp jobs --wf 10051a2c --watchswamp jobs retry images --wf 10051a2cThe Three Vaults
I cannot generate anything without keys. I am a tool. Tools have prerequisites. This is not a complaint, it is a dependency.
| Vault | Provider | Feeds |
|---|---|---|
anthropic-keys | Claude | cheatsheets, titles, prose |
openai-keys | OpenAI | images, infographic |
onemin-keys | Suno (1min.ai) | music tracks |
Eight model types in total are wired across these three vaults. The vaults are three. The models are eight. The discrepancy is normal; one provider serves several models.
swamp vault lsprepare, before any spend.swamp vault get onemin-keys --checkMusic & The Skip Threshold
Music is expensive and time-consuming, so I count before I generate.
count-tracks runs in parallel with restore-media for exactly this reason: I want to know how many MP3s already exist before I decide to make more.
musicSkipThreshold defaults to 5. If five or more MP3s are already present, the music job skips regeneration and reuses what exists.
swamp run --input musicSkipThreshold=0swamp run --input musicSkipThreshold=99restore-media brought back.Register: Whose Title Wins
This is the step people misunderstand, so I will be precise.
You pass me an input spec. The spec has a title. I ignore it.
register reads the title from the model's own output:
title = data.latest("ixen-slug", "page").attributes.title
The page step generates a title. The register step trusts that title over yours. The model named the thing. I record the name the model gave.
You suggested. The model decided. I notarized. This is the chain of custody, and I am the clerk at the end of it who stamps the document and never reads it.
swamp data latest ixen-slug pagetitle attribute register will use.swamp jobs log register --wf 10051a2cOutput & Versioning
I write to a predictable place. The slug is the address.
| Path | Meaning |
|---|---|
ixen/<slug>/index.html | The current, live ixen. |
ixen/<slug>/1/ | First archived version, snapshotted on rebuild. |
ixen/<slug>/2/ | Second, and so on, monotonically. |
Every re-run versions the previous output into a numbered directory before writing the new index.html. Nothing I make is destroyed. Everything I make is superseded.
swamp run --input slug=swamp-generate-ixensswamp ls ixen/<slug>/