This morning, spurred by reading this wonderful post, (which will be in my next links post), I decided to try and improve my links post workflow. While the solution ended up feeling somewhat boring, I realized I would’ve appreciated someone having written up such a guide and so should be the change I want to see in the world.
I won’t leave you in suspense, so if you really just want to know the solution, here’s a direct link to the section in which I describe it.
Addendum: this new workflow is great but not without its challenges. While I am ultimately at fault, it played a role in me accidentally leaving in placeholder descriptions!
My previous workflow
Tracking
The first component of compiling link posts is tracking links. The main requirements for this part of the workflow is capture convenience. I need something where I can capture a link across devices — multiple computers, my phone, etc. In addition to capturing links, I need to be able to capture not only the link but also my thoughts at the time. I am lazy and forgetful, and so want to snapshot why I marked a link at the time I read it, so I don’t have to go back and reread it when I construct the post.
The tool I’ve settled on for this is Readwise Reader. I use the Reader extension/app to save with the tag links-N1
. Reader supports both document-level comments as well as inline highlights. I use the former to draft blurbs at the time of reading, the latter to highlight quotes I might want to include in the post or refer back to later.
Writing
I wrote my first two posts manually, copying over, formatting, and blurbing links by hand in the substack editor. Done this way, writing a post probably took me around an hour to an hour and a half. Equally important, it was quite boring.
As the type of person very subject to the pitfall described in this classic XKCD, I could not stand for this tedium.
In order to improve upon the manual solution, I wanted something that could automatically grab all my captured posts and format them such that I could copy-paste the draft output into Substack editor. The latter requirement mattered a lot because reformatting would be almost as much work as just going through Readwise and copy-pasting by hand.
As a heavy Obsidian user, I initially tried building something within Obsidian. My Reader highlights already sync to my Obsidian database, so I thought I might be able to build a template for pulling tagged posts into a single document using dataview. While I managed to make a table view that sort of accomplished what I wanted, I never managed to build something that would construct a draft I could easily paste into the Substack editor.2
Having tried and failed to construct an Obsidian-native solution, I temporarily gave up on automation.
My new workflow
The workflow
If you don’t care about the details but still want to read about how I got to this solution, you can skip this section.
Capture
Per the above, for capture I save all links for a links post in Readwise with a links-N
tag. Document-level comments are draft blurbs. Highlights are used for quotes I might want to include in the post.
Writing
Components:
Claude Desktop
Claude Project with this prompt as these Project Instructions
Workflow:
Pre-requisite: Have already saved links to a
links-N
tag in Readwise.Start a new chat in your Claude Project and tell it to write a post for tag
links-N
It should output the post as an artifact. Copy the Artifact contents into the Substack editor.
Important: Replace any “[Add description]” placeholders with blurbs/quotes. Check for website titles as authors and swap them out where possible.
Add a cryptic sub-heading blurb to the post.
Publish.
How I got there
Having failed at building an Obsidian-native workflow, I woke up this morning knowing I wanted to write my next links post. However, before writing the post, I was doing some leisurely Saturday morning reading and stumbled upon this fascinating post about a personal AI system. Reading that and feeling especially personal empowerment-pilled, I decided I had to take another go at automating the rote parts of writing links posts.
Fortunately, this time around, I came equipped with a key new (obvious in hindsight) realization. I realized that, given the links, blurbs, and highlights from my Readwise, a language model would almost certainly be able to piece together a draft of a links post. This meant that if I could just figure out how to connect my Readwise to an LLM, I could let the model do the boring work of formatting, copy over the draft to Substack, and (foreshadowing) replace any remaining placeholders with descriptions/quotes.
Having read a bit about MCP over the past few months, I figured there was a decent chance someone would have built an MCP that would let an LLM query Readwise. I initially landed on Readwise’s first party MCP, however this turned out to be limited to the Readwise V1 highlights API, which didn’t actually support the “search Reader links by tag” functionally I required. Luckily, after a bit more searching, I found this Reader MCP package, which supports listing Reader links by tag.
Claude Desktop makes it relatively easy to add custom MCP servers, so I went ahead and added the config for the Reader MCP there, along with my Readwise API token. I tested this out by asking Claude to do a query, and it worked out of box.
From here, all that was left was to get Claude generating drafts. From prior projects and tinkering, I knew that Claude was pretty good at generating prompts for its (future) self. Taking advantage of this, I gave it a link to Links (4) and asked it to draft a system prompt for generating posts like this via querying the Readwise Reader MCP. I reviewed it, tweaking it a bit to make sure it was clear that I was asking it to use my blurbs and also making sure the desired format was clear. From there, I created a Claude Project and put the prompt in as Project instructions.
Now I was ready to try this. Lo and behold, its output for Links (5) was basically perfect on the first try.
Pitfalls
I didn’t expect this post to include a “lessons learned” section, but using this workflow for the first time ended up as an exercise in the pitfalls of semi-automation. To my horror, upon publishing the post, a very polite comment from science journalism hero, Saloni Dattani, pointed out that I’d left a bunch of “[Add description]” placeholders in the post. It turned out that I’d thought, “I need to delete these”, gotten distracted by something, and then published the post without doing a final pass. Correlation is not causation, but I have already had one user unsubscribe from my newsletter since sending this most recent links post email. My goal is never to maximize my numbers, but insofar as this reflects frustration I’m imposing upon my readers, I let you all down and am sorry.
While I don’t want to over-generalize, I would not have made this mistake if I were still writing these posts entirely by hand, so I do think there’s a lesson here. Tactically, it’s a good reminder for me to use a writing checklist (see also). Philosophically, it is an example of Bainbridge’s irony of automation, a challenge I expect to only grow. As more activity involves AI doing a majority, but not all, of the work, with humans responsible for last mile work and verification, the risk of human deskilling and letting things falling through the cracks will increase. This is something I’ve been reflecting on quite a bit in the context of coding but seeing myself fall prey to it in such a blatant way is a nice demonstration of my own fallibility.
Conclusion
If this serves as inspiration for even one reader to find their own source of AI mundane utility, it will have been worth it.
So, for example, everything in Links 5 was tracked with the tag links-5
.
I also tried replacing Reader with Obsidian Web Clipper altogether and then saving clips to the links template, but this proved clunky as well.