4 minute read

An AI-based copy editing workflow for the punctilious.

A few things happened.

  1. My brilliant cousin Peter Conti-Brown mentioned that he uses AI to copy edit his writing on Substack (SUBSCRIBE!).
  2. The AAA updated it’s policy on AI use in writing.
  3. HKUST stopped letting us use our research funds to hire copy editors.

This is a big topic. Briefly, use case #1 is transformational. Low cost copy editing is fantastic, #3 is a loss for me. The copy editor that I have had the pleasure of working with, Julie Stieff, has taught me everything that I know about the mechanics of writing, though she should not be held responsible for all of the glaring deficiencies that remain. The quality of feedback from a true professional is irreplaceable. But, it takes time and money. So, here is the workflow that I have developed.

The input:

I write in Neovim using a mix of Markdown and LaTeX, and I use Raycast to interact with various LLMs.1 This means that it is natural for me to have a file called something like /proj/draft/intro.md which I can pop into my paste buffer from the command line (cat intro.md | pbcopy), then launch Raycast AI (I have this on “Meh-i” where Meh is key programmed to send all the modifier keys at once), select the raycast preset for copy editing, and paste the file into the LLM interface.

The preset I have created is just GPT-5 with the following prompt:

Please copy edit the following section of a document that is being prepared with pandoc markdown. Please only make gramatical changes and typographical corrections with minimal disturbance of the document. In particular, you should not convert any LaTeX or markdown markup. for example items surrounded by dollar signs should not be convered (e.g. $\times$) and em-dashes should remain "---" and not be converted, and en-dashes should remain "--" and not be converted. Please place your response in code fences, and enjoy (but behave yourself). Thanks, love you, bye.

Most of this is pretty obvious, but I’m doing a few things here to keep the output clean. First, the reason that I’m asking it to do as little as possible, is that I want to be able to directly compare the two documents. I’m looking for typos, grammatical errors, and the like. But I want to still sound like my weird idiosyncratic self, and I want to be able to quickly identify the changes. Second, I don’t want the LLM to get confused by the dialect of Markdown and LaTeX that I’m using (i.e. whatever came out of my fingers). Third, I’m being nice to the LLM for no other reason than that I am not always a particularly serious person.

Okay, this usually works nicely, and gives me back an edited copy in a code block so I can click the GUI copy button and get it into my paste buffer (where stuff sits waiting for you to paste it).

Now, on to incorporating the changes.

What to do with the output:

My objective here is to create a workflow that allows me to integrate edits quickly, something like the speed at which you can correct spelling errors in Word, but without YOLOing large chunks of text from the LLM into my draft.

Here is what I’ve settled on:

  1. Drop the LLM edited text into a new buffer in Neovim, and save that with some title like intro_ed.md.
  2. Then use vimdiff to open the two files: vimdiff intro* (if you only have intro.md and intro_ed.md in the folder).

This puts the original on the left, and the edited version on the right, and allows you to jump between changes with ]c and [c, and use do and dp to push and pull changes between the two buffers, and all of your other vim incantations work here as well. My favorite is using :%s/old/new/g to make a change everywhere at the same time.

Notice that I’m never dumping text directly into my draft, instead I’m selecting changes and either typing them in, or pulling them with dp and do. This means that I am always between the LLM and my draft. This is similar to how I recommend researchers work with sources: never copy and paste directly from a source into your draft. Always have an intermediate step where you are typing so that you don’t plagiarize by mistake. I’ve caught a few chunks of text like this when refereeing over the years. This is a preventable mistake.2

  1. I highly recommend Raycast if you are a Mac user. I use it as my primary app launcher, clipboard manager, window manager, automator, and LLM interface. There are three reasons why it is great for working with LLMs: (1) you can launch it with a keystroke as use it as a native app, rather than in a browser; (2) Raycast lets you switch between models on the fly, so you can use GPT-{3,4,5}, Claude, or whatever you want without changing apps; (3) Raycast allows me to use these LLMs without a VPN. 

  2. If this sounds like more typing than you would like to do, you can get faster: monkeytype.com