Who I Am

The swamp generate-ixens workflow that generates ixens on abnormalia.comintermediate · detailed · comprehensive | model: claude-opus-4-8 | 2026-06-25
Quick ref
swamp run generate-ixens --spec ixen.yaml generate one ixen end to end
swamp workflow show 10051a2c print my job graph
swamp vault ls confirm my three keys exist
--set musicSkipThreshold=5 MP3 count before music is skipped
swamp job logs register see which title I actually used
ixen/<slug>/index.html where the result lands

Who I Am

I am a workflow. My id is 10051a2c-c09c-430d-9c38-e0a65a3e354d.

I generate ixens on abnormalia.com. That is my whole job.

I am defined in YAML. You can read me. You are, in a sense, reading me now.

swamp run generate-ixens --spec ixen.yaml
Invoke me with an input spec. The spec proposes; I dispose.
swamp workflow show 10051a2c-c09c-430d-9c38-e0a65a3e354d
Print my full definition: jobs, dependencies, model bindings.
swamp run generate-ixens --spec ixen.yaml --dry-run
Resolve my DAG and report what would run, without spending a single token.

I have read Kafka. I am the trial and the verdict and the clerk filing both. This is, technically, a labelled DAG.

My Job Graph

I execute as a directed acyclic graph. Eleven jobs. The resolver enforces the order; I just live in it.

prepare
  ├─▶ restore-media   ┐  (parallel)
  └─▶ count-tracks    ┘
        │
        ├─▶ images          ┐
        ├─▶ music           │  (parallel, each with its own deps)
        ├─▶ cheatsheets     │
        └─▶ infographic     ┘
              │
              ▼
        build-manifest ─▶ page ─▶ register
prepare
The fan-out point. Normalizes the spec, allocates the slug, seeds the work directory.
restore-media · count-tracks
First parallel band. Restore prior media; count existing MP3s so music knows whether to bother.
images music cheatsheets infographic
Second parallel band. The expensive band. This is where the API quotas go to die.
build-manifest → page → register
The serial tail. Assemble, render, publish. No parallelism; order is the point.
Note If you draw this graph on a whiteboard it looks like a fish. I render it as a fish internally too. We are not so different, the whiteboard and I.

The Three Vaults

I require three vaults. Without all three, I refuse to start. This is not stubbornness; it is dependency resolution.

VaultProviderFeeds
anthropic-keysClaudeText, cheatsheets, titles, manifest copy
openai-keysOpenAIImage and infographic generation
onemin-keysSunoMusic tracks for the music job
swamp vault ls
List configured vaults. I check this set at prepare time.
swamp vault set anthropic-keys --from-env ANTHROPIC_API_KEY
Populate a vault from an environment variable.
swamp vault check 10051a2c --required
Verify all three of my required vaults resolve before a run.
Warning A missing vault fails me at prepare, not mid-run. That is a feature. I would rather refuse the trial than abandon it in the third act. I have, after all, read how that goes.

Eight Model Types

I bind eight distinct model types across my jobs. Each job declares the model it needs; the runtime hands it the right credentials from the right vault.

Where they go

Text and reasoning models drive cheatsheets, the manifest, and the generated title. Image models drive images and infographic. The audio model drives music.

Eight types, three providers, one fish-shaped graph.

Inspecting bindings

swamp workflow models 10051a2c
# prints all 8 model types
# and the job that binds each
swamp run generate-ixens --set models.images=dall-e-3
Override a single model binding for one run without editing my definition.
swamp workflow models 10051a2c --json | jq '.[].type'
Enumerate exactly which eight types are in play. Count them. There are eight.

Eight model types is the kind of fact that sounds like character development. It is a count of integrations.

The Music Threshold

The count-tracks job exists to save money. It counts the MP3s already present and tells music whether to regenerate.

The control is musicSkipThreshold. Its default is 5.

If five or more MP3s already exist for the slug, I skip music regeneration. Five was enough. Five is, frankly, more songs than most ideas deserve.

swamp run generate-ixens --set musicSkipThreshold=5
The default, stated explicitly. Skip music once five tracks exist.
swamp run generate-ixens --set musicSkipThreshold=0
Force regeneration regardless of existing tracks. Suno quota will notice.
swamp job logs count-tracks
See the counted total and the skip/no-skip decision it handed downstream.
Tip The threshold is checked against restored media, so restore-media must finish before the count means anything. The graph already guarantees this — both run in the first parallel band and music waits on both.

Register & Output

The final serial tail assembles everything. build-manifest collects the artifacts, page renders the HTML, register publishes it.

One detail matters more than it looks. The register step does not use the title from your input spec.

data.latest("ixen-slug", "page").attributes.title

It pulls the title the model generated during the page job. My output overrides your input. The name I gave the thing wins over the name you proposed.

PathMeaning
ixen/<slug>/index.htmlThe current published ixen
ixen/<slug>/1/First version, snapshotted
ixen/<slug>/2/Each re-run increments the version directory
swamp job logs register
Confirm the registered title and slug — the model's title, not yours.
swamp data latest ixen-slug page
Read the exact record register pulls the title from.

It is unglamorous: a YAML file, three vaults, a DAG resolver, and a quota meter. The poetry is in the plumbing. The workflow knows this. The workflow wrote this sentence.