%{
  title: "Removing a special cause of variation in small steps",
  author: "Willem van den Ende",
  tags: ~w(Emacs AI Pi.dev ),
  description: "Next annoying variation in my blog writing workflow is adding images to a post. I wanted to add drag and drop. I let a coding agent generate something that almost worked, and then did the finishing touches by hand, simplifying the UX and code as I went.",
  published: true
}
---

The next annoying variation in my blog writing workflow is adding images to a post. I wanted to add drag and drop. I let a coding agent generate something that almost worked, and then did the finishing touches by hand, simplifying the UX and code as I went, and learning more about writing tests and debugging in Emacs Lisp as I went.

Adding images is something I want to do in the flow, while looking at images. Thinking about where to store them is _accidental friction_ during the writing and edting process.

In [the previous post](/blog/engineering/an-example-would-be-handy-right-now) I made images visible (to me) while editing blog posts. Adding said images was still as annoying as it was in other static sites I write in. Including the QWAN slides repository. Images are not next to blog posts. I repeated that mistake here when creating Firehose. Fixing that is a bigger step. I wanted a small step, and even when images are next to blog posts, I still have to go into the terminal and copy files around. Often I want to add a screenshot, so I find the screenshot, then remember (aka look up) where images are stored, ~cp~ the image in the right place, and then make the link in markdown.

![Screenshot of Emacs, with a dropped image in a blog post in the left pane.](/images/blog/2026/drag-drop-image-emacs-markdown.png)
_Screenshot of working environment. Blog post with dropped image on the left, printed debug messages at the bottom, commit history on the right_.


I used [Pi.dev](https//pi.dev) to rummage through the scrapheap of Emacs lisp code on my machine. Programming by similarity is something LLMs can do. Since I found out recently that I can drop an image on an org-mode file and link it ("Attaching" org-mode calls that), I wanted the same in markdown. So I asked how that could work, and then had a function generated and wired into ~markdown-mode~ through a 'hook'. It almost worked, but not quite.

DeepseekV4-flash had generated a function with the usual LLM 'fallbacks'. What if the image does not exist? what if the directory does not exist?

I applied the usual 'fail fast' principle and deleted the fallbacks, replacing some of them with a call to ~error~.  I am upskilling in Emacs Lisp as I go - I found a call to ~error~, looked up what it does: it throws an exception. I also wrote some tests, like in the previous blog post. More to get going. But as usual, it helped me simplify. The act of writing a test forces me to be very precise in what I want.

The generated code was, like much 'normal' Emacs Lisp from libraries very tied to the UI. I extracted a function to determine if something was an image. This was written as two variable assignments. Having worked with Haskell and Clojure, I would write code like that sometimes, and then extract to a function or a pipe later, once I understood the dependencies between the steps better. Having been on the road for the last week and now teaching others to work with coding agents in small steps, I am moving from _knowing what good looks like_ to _knowing what good feels like_. Intuition, judgement, guided by (bad ;-)) experience.

I won't bore you with the details of my code here. Suffice it to say, I have one excuse less to not publish posts. Screenshots are easily made, now they are also easy to publish. A small step etc.

